diff --git a/clang/include/clang/CrossTU/CrossTranslationUnit.h b/clang/include/clang/CrossTU/CrossTranslationUnit.h --- a/clang/include/clang/CrossTU/CrossTranslationUnit.h +++ b/clang/include/clang/CrossTU/CrossTranslationUnit.h @@ -163,16 +163,22 @@ void emitCrossTUDiagnostics(const IndexError &IE); private: + bool checkThresholdReached() const; + llvm::Error lazyInitCTUIndex(StringRef CrossTUDir, StringRef IndexName); + ASTUnit *getCachedASTUnitForName(StringRef LookupName) const; + std::unique_ptr loadFromASTFile(StringRef ASTFileName) const; + ASTUnit *loadFromASTFileCached(StringRef LookupName, StringRef ASTFileName); + llvm::Expected + getASTFileNameForLookup(StringRef LookupName) const; + void lazyInitImporterSharedSt(TranslationUnitDecl *ToTU); ASTImporter &getOrCreateASTImporter(ASTContext &From); template - llvm::Expected getCrossTUDefinitionImpl(const T *D, - StringRef CrossTUDir, - StringRef IndexName, - bool DisplayCTUProgress); + llvm::Expected + getCrossTUDefinitionImpl(const T *D, StringRef CrossTUDir, + StringRef IndexName, bool DisplayCTUProgress); template - const T *findDefInDeclContext(const DeclContext *DC, - StringRef LookupName); + const T *findDefInDeclContext(const DeclContext *DC, StringRef LookupName); template llvm::Expected importDefinitionImpl(const T *D); diff --git a/clang/lib/CrossTU/CrossTranslationUnit.cpp b/clang/lib/CrossTU/CrossTranslationUnit.cpp --- a/clang/lib/CrossTU/CrossTranslationUnit.cpp +++ b/clang/lib/CrossTU/CrossTranslationUnit.cpp @@ -237,8 +237,8 @@ if (LookupName.empty()) return llvm::make_error( index_error_code::failed_to_generate_usr); - llvm::Expected ASTUnitOrError = loadExternalAST( - LookupName, CrossTUDir, IndexName, DisplayCTUProgress); + llvm::Expected ASTUnitOrError = + loadExternalAST(LookupName, CrossTUDir, IndexName, DisplayCTUProgress); if (!ASTUnitOrError) return ASTUnitOrError.takeError(); ASTUnit *Unit = *ASTUnitOrError; @@ -340,6 +340,92 @@ } } +bool CrossTranslationUnitContext::checkThresholdReached() const { + if (NumASTLoaded >= CTULoadThreshold) { + ++NumASTLoadThresholdReached; + return true; + } + return false; +} + +llvm::Error CrossTranslationUnitContext::lazyInitCTUIndex(StringRef CrossTUDir, + StringRef IndexName) { + // Dont initialize if the map is filled. + if (!NameFileMap.empty()) + return llvm::Error::success(); + + // Get the absolute path to the index file. + SmallString<256> IndexFile = CrossTUDir; + if (llvm::sys::path::is_absolute(IndexName)) + IndexFile = IndexName; + else + llvm::sys::path::append(IndexFile, IndexName); + + if (auto IndexMapping = parseCrossTUIndex(IndexFile, CrossTUDir)) { + // Initialize member map. + NameFileMap = *IndexMapping; + return llvm::Error::success(); + } else { + // Error while parsing CrossTU index file. + return IndexMapping.takeError(); + }; +} + +ASTUnit *CrossTranslationUnitContext::getCachedASTUnitForName( + StringRef LookupName) const { + auto CacheEntry = NameASTUnitMap.find(LookupName); + if (CacheEntry != NameASTUnitMap.end()) + return CacheEntry->second; + else + return nullptr; +} + +std::unique_ptr +CrossTranslationUnitContext::loadFromASTFile(StringRef ASTFileName) const { + // Load AST from ast-dump. + IntrusiveRefCntPtr DiagOpts = new DiagnosticOptions(); + TextDiagnosticPrinter *DiagClient = + new TextDiagnosticPrinter(llvm::errs(), &*DiagOpts); + IntrusiveRefCntPtr DiagID(new DiagnosticIDs()); + IntrusiveRefCntPtr Diags( + new DiagnosticsEngine(DiagID, &*DiagOpts, DiagClient)); + + return ASTUnit::LoadFromASTFile( + ASTFileName, CI.getPCHContainerOperations()->getRawReader(), + ASTUnit::LoadEverything, Diags, CI.getFileSystemOpts()); +} + +llvm::Expected +CrossTranslationUnitContext::getASTFileNameForLookup( + StringRef LookupName) const { + auto NameFileMapEntry = NameFileMap.find(LookupName); + if (NameFileMapEntry != NameFileMap.end()) { + return NameFileMapEntry->second; + } else { + ++NumNotInOtherTU; + return llvm::make_error(index_error_code::missing_definition); + } +} + +ASTUnit * +CrossTranslationUnitContext::loadFromASTFileCached(StringRef LookupName, + StringRef ASTFileName) { + ASTUnit *Unit = nullptr; + + auto ASTCacheEntry = FileASTUnitMap.find(ASTFileName); + if (ASTCacheEntry == FileASTUnitMap.end()) { + // Load the ASTUnit from the pre-dumped AST file specified by ASTFileName. + std::unique_ptr LoadedUnit = loadFromASTFile(ASTFileName); + Unit = LoadedUnit.get(); + FileASTUnitMap[ASTFileName] = std::move(LoadedUnit); + } else { + Unit = ASTCacheEntry->second.get(); + } + NameASTUnitMap[LookupName] = Unit; + + return Unit; +} + llvm::Expected CrossTranslationUnitContext::loadExternalAST( StringRef LookupName, StringRef CrossTUDir, StringRef IndexName, bool DisplayCTUProgress) { @@ -348,65 +434,38 @@ // translation units contains decls with the same lookup name an // error will be returned. - if (NumASTLoaded >= CTULoadThreshold) { - ++NumASTLoadThresholdReached; + // If import threshold is reached, don't import anything. + if (checkThresholdReached()) return llvm::make_error( index_error_code::load_threshold_reached); - } - ASTUnit *Unit = nullptr; - auto NameUnitCacheEntry = NameASTUnitMap.find(LookupName); - if (NameUnitCacheEntry == NameASTUnitMap.end()) { - if (NameFileMap.empty()) { - SmallString<256> IndexFile = CrossTUDir; - if (llvm::sys::path::is_absolute(IndexName)) - IndexFile = IndexName; - else - llvm::sys::path::append(IndexFile, IndexName); - llvm::Expected> IndexOrErr = - parseCrossTUIndex(IndexFile, CrossTUDir); - if (IndexOrErr) - NameFileMap = *IndexOrErr; - else - return IndexOrErr.takeError(); - } + // First try to access the cache to get the ASTUnit for the function name + // specified by LookupName. + ASTUnit *Unit = getCachedASTUnitForName(LookupName); + if (Unit) + return Unit; - auto It = NameFileMap.find(LookupName); - if (It == NameFileMap.end()) { - ++NumNotInOtherTU; - return llvm::make_error(index_error_code::missing_definition); - } - StringRef ASTFileName = It->second; - auto ASTCacheEntry = FileASTUnitMap.find(ASTFileName); - if (ASTCacheEntry == FileASTUnitMap.end()) { - IntrusiveRefCntPtr DiagOpts = new DiagnosticOptions(); - TextDiagnosticPrinter *DiagClient = - new TextDiagnosticPrinter(llvm::errs(), &*DiagOpts); - IntrusiveRefCntPtr DiagID(new DiagnosticIDs()); - IntrusiveRefCntPtr Diags( - new DiagnosticsEngine(DiagID, &*DiagOpts, DiagClient)); - - std::unique_ptr LoadedUnit(ASTUnit::LoadFromASTFile( - ASTFileName, CI.getPCHContainerOperations()->getRawReader(), - ASTUnit::LoadEverything, Diags, CI.getFileSystemOpts())); - Unit = LoadedUnit.get(); - FileASTUnitMap[ASTFileName] = std::move(LoadedUnit); - ++NumASTLoaded; - if (DisplayCTUProgress) { - llvm::errs() << "CTU loaded AST file: " - << ASTFileName << "\n"; - } - } else { - Unit = ASTCacheEntry->second.get(); + // Lazily initialize the mapping from function names to AST files. + if (llvm::Error InitFailed = lazyInitCTUIndex(CrossTUDir, IndexName)) + return std::move(InitFailed); + + llvm::Expected ASTFileName = getASTFileNameForLookup(LookupName); + if (!ASTFileName) + return ASTFileName.takeError(); + + // Try to load from ASTFile but use cache for both file and function names. + Unit = loadFromASTFileCached(LookupName, *ASTFileName); + + if (Unit) { + ++NumASTLoaded; + if (DisplayCTUProgress) { + llvm::errs() << "CTU loaded AST file: " << *ASTFileName << "\n"; } - NameASTUnitMap[LookupName] = Unit; + return Unit; } else { - Unit = NameUnitCacheEntry->second; - } - if (!Unit) return llvm::make_error( index_error_code::failed_to_get_external_ast); - return Unit; + } } template