================ @@ -316,36 +287,169 @@ llvm::Error buildModuleFile(llvm::StringRef ModuleName, if (Clang->getDiagnostics().hasErrorOccurred()) return llvm::createStringError("Compilation failed"); - BuiltModuleFiles.addModuleFile(ModuleName, Inputs.CompileCommand.Output); - return llvm::Error::success(); + return ModuleFile{ModuleName, Inputs.CompileCommand.Output}; +} + +bool ReusablePrerequisiteModules::canReuse( + const CompilerInvocation &CI, + llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS) const { + if (RequiredModules.empty()) + return true; + + SmallVector<StringRef> BMIPaths; + for (auto &MF : RequiredModules) + BMIPaths.push_back(MF->ModuleFilePath); + return IsModuleFilesUpToDate(BMIPaths, *this, VFS); } } // namespace +class ModulesBuilder::ModuleFileCache { +public: + ModuleFileCache(const GlobalCompilationDatabase &CDB) : CDB(CDB) {} + + llvm::Error + getOrBuildModuleFile(StringRef ModuleName, const ThreadsafeFS &TFS, + ProjectModules &MDB, + ReusablePrerequisiteModules &RequiredModules); + const GlobalCompilationDatabase &getCDB() const { return CDB; } + +private: + std::shared_ptr<ModuleFile> + getValidModuleFile(StringRef ModuleName, ProjectModules &MDB, + const ThreadsafeFS &TFS, + PrerequisiteModules &BuiltModuleFiles); + + /// This should only be called by getValidModuleFile. This is unlocked version + /// of getValidModuleFile. The function is extracted to avoid dead locks when + /// recursing. + std::shared_ptr<ModuleFile> + isValidModuleFileUnlocked(StringRef ModuleName, ProjectModules &MDB, + const ThreadsafeFS &TFS, + PrerequisiteModules &BuiltModuleFiles); + + const GlobalCompilationDatabase &CDB; + + llvm::StringMap<std::shared_ptr<ModuleFile>> ModuleFiles; + // Mutex to guard accesses to ModuleFiles. + std::mutex ModuleFilesMutex; +}; + +std::shared_ptr<ModuleFile> +ModulesBuilder::ModuleFileCache::isValidModuleFileUnlocked( + StringRef ModuleName, ProjectModules &MDB, const ThreadsafeFS &TFS, + PrerequisiteModules &BuiltModuleFiles) { + auto Iter = ModuleFiles.find(ModuleName); + if (Iter != ModuleFiles.end()) { + if (!IsModuleFileUpToDate(Iter->second->ModuleFilePath, BuiltModuleFiles, + TFS.view(std::nullopt))) { + log("Found not-up-date module file {0} for module {1} in cache", + Iter->second->ModuleFilePath, ModuleName); + ModuleFiles.erase(Iter); + return nullptr; + } + + if (llvm::any_of( + MDB.getRequiredModules(MDB.getSourceForModuleName(ModuleName)), + [&MDB, &TFS, &BuiltModuleFiles, this](auto &&RequiredModuleName) { + return !isValidModuleFileUnlocked(RequiredModuleName, MDB, TFS, + BuiltModuleFiles); + })) { + ModuleFiles.erase(Iter); + return nullptr; + } + + return Iter->second; + } + + log("Don't find {0} in cache", ModuleName); + + return nullptr; +} + +std::shared_ptr<ModuleFile> ModulesBuilder::ModuleFileCache::getValidModuleFile( + StringRef ModuleName, ProjectModules &MDB, const ThreadsafeFS &TFS, + PrerequisiteModules &BuiltModuleFiles) { + std::lock_guard<std::mutex> _(ModuleFilesMutex); + + return isValidModuleFileUnlocked(ModuleName, MDB, TFS, BuiltModuleFiles); +} + +llvm::Error ModulesBuilder::ModuleFileCache::getOrBuildModuleFile( ---------------- kadircet wrote:
similar to comment in `buildModuleFile`, can we turn this into just `getModuleFile`, which returns the latest cached module-file and make it callers responsibility to deal with freshness of the data. I don't think making this class concerned about both cache management and building/verifying module-files is necessary (and goes against separation of concerns). https://github.com/llvm/llvm-project/pull/106683 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits