@@ -360,16 +360,17 @@ void ModuleFileCache::remove(StringRef ModuleName) {
360360// / Collect the directly and indirectly required module names for \param
361361// / ModuleName in topological order. The \param ModuleName is guaranteed to
362362// / be the last element in \param ModuleNames.
363- llvm::SmallVector<StringRef> getAllRequiredModules (ProjectModules &MDB,
363+ llvm::SmallVector<StringRef> getAllRequiredModules (PathRef RequiredSource,
364+ ProjectModules &MDB,
364365 StringRef ModuleName) {
365366 llvm::SmallVector<llvm::StringRef> ModuleNames;
366367 llvm::StringSet<> ModuleNamesSet;
367368
368369 auto VisitDeps = [&](StringRef ModuleName, auto Visitor) -> void {
369370 ModuleNamesSet.insert (ModuleName);
370371
371- for (StringRef RequiredModuleName :
372- MDB.getRequiredModules (MDB. getSourceForModuleName (ModuleName)))
372+ for (StringRef RequiredModuleName : MDB. getRequiredModules (
373+ MDB.getSourceForModuleName (ModuleName, RequiredSource )))
373374 if (ModuleNamesSet.insert (RequiredModuleName).second )
374375 Visitor (RequiredModuleName, Visitor);
375376
@@ -380,30 +381,114 @@ llvm::SmallVector<StringRef> getAllRequiredModules(ProjectModules &MDB,
380381 return ModuleNames;
381382}
382383
384+ class CachingProjectModules : public ProjectModules {
385+ public:
386+ CachingProjectModules (const GlobalCompilationDatabase &CDB) : CDB(CDB) {}
387+
388+ std::vector<std::string> getRequiredModules (PathRef File) override {
389+ std::unique_ptr<ProjectModules> MDB = CDB.getProjectModules (File);
390+ if (!MDB) {
391+ elog (" Failed to get Project Modules information for {0}" , File);
392+ return {};
393+ }
394+ return MDB->getRequiredModules (File);
395+ }
396+
397+ std::string getModuleNameForSource (PathRef File) override {
398+ std::unique_ptr<ProjectModules> MDB = CDB.getProjectModules (File);
399+ if (!MDB) {
400+ elog (" Failed to get Project Modules information for {0}" , File);
401+ return {};
402+ }
403+ return MDB->getModuleNameForSource (File);
404+ }
405+
406+ void setCommandMangler (CommandMangler M) override {
407+ // GlobalCompilationDatabase::getProjectModules() will set mangler
408+ // for the underlying ProjectModules.
409+ }
410+
411+ std::string getSourceForModuleName (llvm::StringRef ModuleName,
412+ PathRef RequiredSrcFile) override {
413+ std::string CachedResult;
414+ {
415+ std::lock_guard<std::mutex> Lock (CacheMutex);
416+ auto Iter = ModuleNameToSourceCache.find (ModuleName);
417+ if (Iter != ModuleNameToSourceCache.end ())
418+ CachedResult = Iter->second ;
419+ }
420+
421+ std::unique_ptr<ProjectModules> MDB =
422+ CDB.getProjectModules (RequiredSrcFile);
423+ if (!MDB) {
424+ elog (" Failed to get Project Modules information for {0}" ,
425+ RequiredSrcFile);
426+ return {};
427+ }
428+
429+ // Verify Cached Result by seeing if the source declaring the same module
430+ // as we query.
431+ if (!CachedResult.empty ()) {
432+ std::string ModuleNameOfCachedSource =
433+ MDB->getModuleNameForSource (CachedResult);
434+ if (ModuleNameOfCachedSource == ModuleName)
435+ return CachedResult;
436+ else {
437+ // Cached Result is invalid. Clear it.
438+
439+ std::lock_guard<std::mutex> Lock (CacheMutex);
440+ ModuleNameToSourceCache.erase (ModuleName);
441+ }
442+ }
443+
444+ auto Result = MDB->getSourceForModuleName (ModuleName, RequiredSrcFile);
445+
446+ {
447+ std::lock_guard<std::mutex> Lock (CacheMutex);
448+ ModuleNameToSourceCache.insert ({ModuleName, Result});
449+ }
450+
451+ return Result;
452+ }
453+
454+ private:
455+ const GlobalCompilationDatabase &CDB;
456+
457+ std::mutex CacheMutex;
458+ llvm::StringMap<std::string> ModuleNameToSourceCache;
459+ };
460+
383461} // namespace
384462
385463class ModulesBuilder ::ModulesBuilderImpl {
386464public:
387- ModulesBuilderImpl (const GlobalCompilationDatabase &CDB) : Cache(CDB) {}
465+ ModulesBuilderImpl (const GlobalCompilationDatabase &CDB)
466+ : CachedProjectModules(CDB), Cache(CDB) {}
467+
468+ CachingProjectModules &getCachedProjectModules () {
469+ return CachedProjectModules;
470+ }
388471
389472 const GlobalCompilationDatabase &getCDB () const { return Cache.getCDB (); }
390473
391474 llvm::Error
392- getOrBuildModuleFile (StringRef ModuleName, const ThreadsafeFS &TFS ,
393- ProjectModules &MDB,
475+ getOrBuildModuleFile (PathRef RequiredSource, StringRef ModuleName ,
476+ const ThreadsafeFS &TFS, ProjectModules &MDB,
394477 ReusablePrerequisiteModules &BuiltModuleFiles);
395478
396479private:
480+ CachingProjectModules CachedProjectModules;
397481 ModuleFileCache Cache;
398482};
399483
400484llvm::Error ModulesBuilder::ModulesBuilderImpl::getOrBuildModuleFile (
401- StringRef ModuleName, const ThreadsafeFS &TFS, ProjectModules &MDB ,
402- ReusablePrerequisiteModules &BuiltModuleFiles) {
485+ PathRef RequiredSource, StringRef ModuleName, const ThreadsafeFS &TFS,
486+ ProjectModules &MDB, ReusablePrerequisiteModules &BuiltModuleFiles) {
403487 if (BuiltModuleFiles.isModuleUnitBuilt (ModuleName))
404488 return llvm::Error::success ();
405489
406- PathRef ModuleUnitFileName = MDB.getSourceForModuleName (ModuleName);
490+ std::string ModuleUnitFileName =
491+ MDB.getSourceForModuleName (ModuleName, RequiredSource);
407492 // / It is possible that we're meeting third party modules (modules whose
408493 // / source are not in the project. e.g, the std module may be a third-party
409494 // / module for most project) or something wrong with the implementation of
@@ -416,7 +501,7 @@ llvm::Error ModulesBuilder::ModulesBuilderImpl::getOrBuildModuleFile(
416501 llvm::formatv (" Don't get the module unit for module {0}" , ModuleName));
417502
418503 // Get Required modules in topological order.
419- auto ReqModuleNames = getAllRequiredModules (MDB, ModuleName);
504+ auto ReqModuleNames = getAllRequiredModules (RequiredSource, MDB, ModuleName);
420505 for (llvm::StringRef ReqModuleName : ReqModuleNames) {
421506 if (BuiltModuleFiles.isModuleUnitBuilt (ModuleName))
422507 continue ;
@@ -449,21 +534,17 @@ llvm::Error ModulesBuilder::ModulesBuilderImpl::getOrBuildModuleFile(
449534std::unique_ptr<PrerequisiteModules>
450535ModulesBuilder::buildPrerequisiteModulesFor (PathRef File,
451536 const ThreadsafeFS &TFS) {
452- std::unique_ptr<ProjectModules> MDB = Impl->getCDB ().getProjectModules (File);
453- if (!MDB) {
454- elog (" Failed to get Project Modules information for {0}" , File);
455- return std::make_unique<FailedPrerequisiteModules>();
456- }
537+ ProjectModules &MDB = Impl->getCachedProjectModules ();
457538
458- std::vector<std::string> RequiredModuleNames = MDB-> getRequiredModules (File);
539+ std::vector<std::string> RequiredModuleNames = MDB. getRequiredModules (File);
459540 if (RequiredModuleNames.empty ())
460541 return std::make_unique<ReusablePrerequisiteModules>();
461542
462543 auto RequiredModules = std::make_unique<ReusablePrerequisiteModules>();
463544 for (llvm::StringRef RequiredModuleName : RequiredModuleNames) {
464545 // Return early if there is any error.
465546 if (llvm::Error Err = Impl->getOrBuildModuleFile (
466- RequiredModuleName, TFS, * MDB. get () , *RequiredModules.get ())) {
547+ File, RequiredModuleName, TFS, MDB, *RequiredModules.get ())) {
467548 elog (" Failed to build module {0}; due to {1}" , RequiredModuleName,
468549 toString (std::move (Err)));
469550 return std::make_unique<FailedPrerequisiteModules>();
0 commit comments