From: Douglas Gregor Date: Wed, 18 Jan 2012 20:56:22 +0000 (+0000) Subject: Optimize unqualified/global name lookup in modules by introducing a X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=057df20b3107cef764052d271c89b8591b98b3ce;p=clang Optimize unqualified/global name lookup in modules by introducing a generational scheme for identifiers that avoids searching the hash tables of a given module more than once for a given identifier. Previously, loading any new module invalidated all of the previous lookup results for all identifiers, causing us to perform the lookups repeatedly. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@148412 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Serialization/ASTReader.h b/include/clang/Serialization/ASTReader.h index e7bdf50ae1..6148151487 100644 --- a/include/clang/Serialization/ASTReader.h +++ b/include/clang/Serialization/ASTReader.h @@ -579,6 +579,10 @@ private: /// \brief Whether to disable the use of stat caches in AST files. bool DisableStatCache; + /// \brief The current "generation" of the module file import stack, which + /// indicates how many separate module file load operations have occurred. + unsigned CurrentGeneration; + /// \brief Mapping from switch-case IDs in the chain to switch-case statements /// /// Statements usually don't have IDs, but switch cases need them, so that the @@ -652,6 +656,9 @@ private: /// loaded once the recursive loading has completed. std::deque PendingIdentifierInfos; + /// \brief The generation number of + llvm::DenseMap IdentifierGeneration; + /// \brief Contains declarations and definitions that will be /// "interesting" to the ASTConsumer, when we get that AST consumer. /// @@ -1432,6 +1439,9 @@ public: /// \brief Update an out-of-date identifier. virtual void updateOutOfDateIdentifier(IdentifierInfo &II); + /// \brief Note that this identifier is up-to-date. + void markIdentifierUpToDate(IdentifierInfo *II); + /// \brief Read the macro definition corresponding to this iterator /// into the unread macro record offsets table. void LoadMacroDefinition( diff --git a/include/clang/Serialization/Module.h b/include/clang/Serialization/Module.h index ad2c98e695..831a873ac1 100644 --- a/include/clang/Serialization/Module.h +++ b/include/clang/Serialization/Module.h @@ -57,7 +57,7 @@ struct DeclContextInfo { /// other modules. class ModuleFile { public: - ModuleFile(ModuleKind Kind); + ModuleFile(ModuleKind Kind, unsigned Generation); ~ModuleFile(); // === General information === @@ -72,6 +72,9 @@ public: /// user. bool DirectlyImported; + /// \brief The generation of which this module file is a part. + unsigned Generation; + /// \brief The memory buffer that stores the data associated with /// this AST file. llvm::OwningPtr Buffer; diff --git a/include/clang/Serialization/ModuleManager.h b/include/clang/Serialization/ModuleManager.h index ac9483894d..6ff0640b64 100644 --- a/include/clang/Serialization/ModuleManager.h +++ b/include/clang/Serialization/ModuleManager.h @@ -95,6 +95,8 @@ public: /// \param ImportedBy The module that is importing this module, or NULL if /// this module is imported directly by the user. /// + /// \param Generation The generation in which this module was loaded. + /// /// \param ErrorStr Will be set to a non-empty string if any errors occurred /// while trying to load the module. /// @@ -102,7 +104,7 @@ public: /// and a boolean indicating whether the module was newly added. std::pair addModule(StringRef FileName, ModuleKind Type, ModuleFile *ImportedBy, - std::string &ErrorStr); + unsigned Generation, std::string &ErrorStr); /// \brief Add an in-memory buffer the list of known buffers void addInMemoryBuffer(StringRef FileName, llvm::MemoryBuffer *Buffer); diff --git a/lib/Serialization/ASTReader.cpp b/lib/Serialization/ASTReader.cpp index 245e8b1b18..5842bbb468 100644 --- a/lib/Serialization/ASTReader.cpp +++ b/lib/Serialization/ASTReader.cpp @@ -514,7 +514,7 @@ IdentifierInfo *ASTIdentifierLookupTrait::ReadData(const internal_key_type& k, II = &Reader.getIdentifierTable().getOwn(StringRef(k.first, k.second)); Reader.SetIdentifierInfo(ID, II); II->setIsFromAST(); - II->setOutOfDate(false); + Reader.markIdentifierUpToDate(II); return II; } @@ -540,7 +540,7 @@ IdentifierInfo *ASTIdentifierLookupTrait::ReadData(const internal_key_type& k, IdentifierInfo *II = KnownII; if (!II) II = &Reader.getIdentifierTable().getOwn(StringRef(k.first, k.second)); - II->setOutOfDate(false); + Reader.markIdentifierUpToDate(II); II->setIsFromAST(); // Set or check the various bits in the IdentifierInfo structure. @@ -1560,14 +1560,20 @@ namespace { /// \brief Visitor class used to look up identifirs in an AST file. class IdentifierLookupVisitor { StringRef Name; + unsigned PriorGeneration; IdentifierInfo *Found; public: - explicit IdentifierLookupVisitor(StringRef Name) : Name(Name), Found() { } + IdentifierLookupVisitor(StringRef Name, unsigned PriorGeneration) + : Name(Name), PriorGeneration(PriorGeneration), Found() { } static bool visit(ModuleFile &M, void *UserData) { IdentifierLookupVisitor *This = static_cast(UserData); + // If we've already searched this module file, skip it now. + if (M.Generation <= This->PriorGeneration) + return true; + ASTIdentifierLookupTable *IdTable = (ASTIdentifierLookupTable *)M.IdentifierLookupTable; if (!IdTable) @@ -1593,7 +1599,24 @@ namespace { } void ASTReader::updateOutOfDateIdentifier(IdentifierInfo &II) { - get(II.getName()); + unsigned PriorGeneration = 0; + if (getContext().getLangOptions().Modules) + PriorGeneration = IdentifierGeneration[&II]; + + IdentifierLookupVisitor Visitor(II.getName(), PriorGeneration); + ModuleMgr.visit(IdentifierLookupVisitor::visit, &Visitor); + markIdentifierUpToDate(&II); +} + +void ASTReader::markIdentifierUpToDate(IdentifierInfo *II) { + if (!II) + return; + + II->setOutOfDate(false); + + // Update the generation for this identifier. + if (getContext().getLangOptions().Modules) + IdentifierGeneration[II] = CurrentGeneration; } const FileEntry *ASTReader::getFileEntry(StringRef filenameStrRef) { @@ -2612,6 +2635,9 @@ void ASTReader::makeModuleVisible(Module *Mod, ASTReader::ASTReadResult ASTReader::ReadAST(const std::string &FileName, ModuleKind Type) { + // Bump the generation number. + ++CurrentGeneration; + switch(ReadASTCore(FileName, Type, /*ImportedBy=*/0)) { case Failure: return Failure; case IgnorePCH: return IgnorePCH; @@ -2619,7 +2645,7 @@ ASTReader::ASTReadResult ASTReader::ReadAST(const std::string &FileName, } // Here comes stuff that we only do once the entire chain is loaded. - + // Check the predefines buffers. if (!DisableValidation && Type == MK_PCH && // FIXME: CheckPredefinesBuffers also sets the SuggestedPredefines; @@ -2635,7 +2661,7 @@ ASTReader::ASTReadResult ASTReader::ReadAST(const std::string &FileName, IdEnd = PP.getIdentifierTable().end(); Id != IdEnd; ++Id) Id->second->setOutOfDate(true); - + // Resolve any unresolved module exports. for (unsigned I = 0, N = UnresolvedModuleImportExports.size(); I != N; ++I) { UnresolvedModuleImportExport &Unresolved = UnresolvedModuleImportExports[I]; @@ -2683,7 +2709,7 @@ ASTReader::ASTReadResult ASTReader::ReadASTCore(StringRef FileName, bool NewModule; std::string ErrorStr; llvm::tie(M, NewModule) = ModuleMgr.addModule(FileName, Type, ImportedBy, - ErrorStr); + CurrentGeneration, ErrorStr); if (!M) { // We couldn't load the module. @@ -5109,11 +5135,11 @@ void ASTReader::InitializeSema(Sema &S) { } IdentifierInfo* ASTReader::get(const char *NameStart, const char *NameEnd) { - IdentifierLookupVisitor Visitor(StringRef(NameStart, NameEnd - NameStart)); + IdentifierLookupVisitor Visitor(StringRef(NameStart, NameEnd - NameStart), + /*PriorGeneration=*/0); ModuleMgr.visit(IdentifierLookupVisitor::visit, &Visitor); IdentifierInfo *II = Visitor.getIdentifierInfo(); - if (II) - II->setOutOfDate(false); + markIdentifierUpToDate(II); return II; } @@ -6236,7 +6262,8 @@ ASTReader::ASTReader(Preprocessor &PP, ASTContext &Context, Consumer(0), ModuleMgr(FileMgr.getFileSystemOptions()), RelocatablePCH(false), isysroot(isysroot), DisableValidation(DisableValidation), - DisableStatCache(DisableStatCache), NumStatHits(0), NumStatMisses(0), + DisableStatCache(DisableStatCache), + CurrentGeneration(0), NumStatHits(0), NumStatMisses(0), NumSLocEntriesRead(0), TotalNumSLocEntries(0), NumStatementsRead(0), TotalNumStatements(0), NumMacrosRead(0), TotalNumMacros(0), NumSelectorsRead(0), NumMethodPoolEntriesRead(0), diff --git a/lib/Serialization/Module.cpp b/lib/Serialization/Module.cpp index cb8c9cca06..bed545a0b2 100644 --- a/lib/Serialization/Module.cpp +++ b/lib/Serialization/Module.cpp @@ -20,8 +20,8 @@ using namespace clang; using namespace serialization; using namespace reader; -ModuleFile::ModuleFile(ModuleKind Kind) - : Kind(Kind), DirectlyImported(false), SizeInBits(0), +ModuleFile::ModuleFile(ModuleKind Kind, unsigned Generation) + : Kind(Kind), DirectlyImported(false), Generation(Generation), SizeInBits(0), LocalNumSLocEntries(0), SLocEntryBaseID(0), SLocEntryBaseOffset(0), SLocEntryOffsets(0), SLocFileOffsets(0), LocalNumIdentifiers(0), diff --git a/lib/Serialization/ModuleManager.cpp b/lib/Serialization/ModuleManager.cpp index 4470855ec7..ab364b7ebd 100644 --- a/lib/Serialization/ModuleManager.cpp +++ b/lib/Serialization/ModuleManager.cpp @@ -35,7 +35,8 @@ llvm::MemoryBuffer *ModuleManager::lookupBuffer(StringRef Name) { std::pair ModuleManager::addModule(StringRef FileName, ModuleKind Type, - ModuleFile *ImportedBy, std::string &ErrorStr) { + ModuleFile *ImportedBy, unsigned Generation, + std::string &ErrorStr) { const FileEntry *Entry = FileMgr.getFile(FileName); if (!Entry && FileName != "-") { ErrorStr = "file not found"; @@ -47,7 +48,7 @@ ModuleManager::addModule(StringRef FileName, ModuleKind Type, bool NewModule = false; if (!ModuleEntry) { // Allocate a new module. - ModuleFile *New = new ModuleFile(Type); + ModuleFile *New = new ModuleFile(Type, Generation); New->FileName = FileName.str(); Chain.push_back(New); NewModule = true;