From 9f7828905552b0dcfe809412f1bb55432eedae06 Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Mon, 21 Jan 2013 15:25:38 +0000 Subject: [PATCH] Introduce a fast path for the ASTReader's name lookup within a DeclContext. When the DeclContext is of a kind that can only be defined once and never updated, we limit the search to the module file that conatins the lookup table. Provides a 15% speedup in one modules-heavy source file. llvm-svn: 173050 --- clang/include/clang/Serialization/ASTReader.h | 2 +- clang/lib/Serialization/ASTCommon.cpp | 58 +++++++++++++++++++++++++++ clang/lib/Serialization/ASTCommon.h | 12 ++++++ clang/lib/Serialization/ASTReader.cpp | 34 +++++++++++++++- clang/lib/Serialization/ASTWriter.cpp | 1 + 5 files changed, 104 insertions(+), 3 deletions(-) diff --git a/clang/include/clang/Serialization/ASTReader.h b/clang/include/clang/Serialization/ASTReader.h index 328f967..994008d 100644 --- a/clang/include/clang/Serialization/ASTReader.h +++ b/clang/include/clang/Serialization/ASTReader.h @@ -1311,7 +1311,7 @@ public: /// \brief Retrieve the module file that owns the given declaration, or NULL /// if the declaration is not from a module file. - ModuleFile *getOwningModuleFile(Decl *D); + ModuleFile *getOwningModuleFile(const Decl *D); /// \brief Returns the source location for the decl \p ID. SourceLocation getSourceLocationForDeclID(serialization::GlobalDeclID ID); diff --git a/clang/lib/Serialization/ASTCommon.cpp b/clang/lib/Serialization/ASTCommon.cpp index bf1e25a..df87165 100644 --- a/clang/lib/Serialization/ASTCommon.cpp +++ b/clang/lib/Serialization/ASTCommon.cpp @@ -12,6 +12,7 @@ //===----------------------------------------------------------------------===// #include "ASTCommon.h" +#include "clang/AST/DeclObjC.h" #include "clang/Basic/IdentifierTable.h" #include "clang/Serialization/ASTDeserializationListener.h" #include "llvm/ADT/StringExtras.h" @@ -85,3 +86,60 @@ unsigned serialization::ComputeHash(Selector Sel) { R = llvm::HashString(II->getName(), R); return R; } + +const Decl *serialization::getDefinitiveDeclContext(const DeclContext *DC) { + switch (DC->getDeclKind()) { + // These entities may have multiple definitions. + case Decl::TranslationUnit: + case Decl::Namespace: + case Decl::LinkageSpec: + return 0; + + // C/C++ tag types can only be defined in one place. + case Decl::Enum: + case Decl::Record: + if (const TagDecl *Def = cast(DC)->getDefinition()) + return Def; + break; + + // FIXME: These can be defined in one place... except special member + // functions and out-of-line definitions. + case Decl::CXXRecord: + case Decl::ClassTemplateSpecialization: + case Decl::ClassTemplatePartialSpecialization: + return 0; + + // Each function, method, and block declaration is its own DeclContext. + case Decl::Function: + case Decl::CXXMethod: + case Decl::CXXConstructor: + case Decl::CXXDestructor: + case Decl::CXXConversion: + case Decl::ObjCMethod: + case Decl::Block: + // Objective C categories, category implementations, and class + // implementations can only be defined in one place. + case Decl::ObjCCategory: + case Decl::ObjCCategoryImpl: + case Decl::ObjCImplementation: + return cast(DC); + + case Decl::ObjCProtocol: + if (const ObjCProtocolDecl *Def + = cast(DC)->getDefinition()) + return Def; + break; + + // FIXME: These are defined in one place, but properties in class extensions + // end up being back-patched into the main interface. See + // Sema::HandlePropertyInClassExtension for the offending code. + case Decl::ObjCInterface: + break; + + default: + llvm_unreachable("Unhandled DeclContext in AST reader"); + } + + return 0; + +} diff --git a/clang/lib/Serialization/ASTCommon.h b/clang/lib/Serialization/ASTCommon.h index 643deb2..f9db1f0 100644 --- a/clang/lib/Serialization/ASTCommon.h +++ b/clang/lib/Serialization/ASTCommon.h @@ -58,6 +58,18 @@ TypeID MakeTypeID(ASTContext &Context, QualType T, IdxForTypeTy IdxForType) { unsigned ComputeHash(Selector Sel); +/// \brief Retrieve the "definitive" declaration that provides all of the +/// visible entries for the given declaration context, if there is one. +/// +/// The "definitive" declaration is the only place where we need to look to +/// find information about the declarations within the given declaration +/// context. For example, C++ and Objective-C classes, C structs/unions, and +/// Objective-C protocols, categories, and extensions are all defined in a +/// single place in the source code, so they have definitive declarations +/// associated with them. C++ namespaces, on the other hand, can have +/// multiple definitions. +const Decl *getDefinitiveDeclContext(const DeclContext *DC); + } // namespace serialization } // namespace clang diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp index 00bae0a..db850f3 100644 --- a/clang/lib/Serialization/ASTReader.cpp +++ b/clang/lib/Serialization/ASTReader.cpp @@ -4971,7 +4971,7 @@ bool ASTReader::isDeclIDFromModule(serialization::GlobalDeclID ID, return &M == I->second; } -ModuleFile *ASTReader::getOwningModuleFile(Decl *D) { +ModuleFile *ASTReader::getOwningModuleFile(const Decl *D) { if (!D->isFromASTFile()) return 0; GlobalDeclMapType::const_iterator I = GlobalDeclMap.find(D->getGlobalID()); @@ -5307,6 +5307,27 @@ namespace { }; } +/// \brief Retrieve the "definitive" module file for the definition of the +/// given declaration context, if there is one. +/// +/// The "definitive" module file is the only place where we need to look to +/// find information about the declarations within the given declaration +/// context. For example, C++ and Objective-C classes, C structs/unions, and +/// Objective-C protocols, categories, and extensions are all defined in a +/// single place in the source code, so they have definitive module files +/// associated with them. C++ namespaces, on the other hand, can have +/// definitions in multiple different module files. +/// +/// Note: this needs to be kept in sync with ASTWriter::AddedVisibleDecl's +/// NDEBUG checking. +static ModuleFile *getDefinitiveModuleFileFor(const DeclContext *DC, + ASTReader &Reader) { + if (const Decl *D = getDefinitiveDeclContext(DC)) + return Reader.getOwningModuleFile(D); + + return 0; +} + DeclContext::lookup_result ASTReader::FindExternalVisibleDeclsByName(const DeclContext *DC, DeclarationName Name) { @@ -5335,7 +5356,16 @@ ASTReader::FindExternalVisibleDeclsByName(const DeclContext *DC, } DeclContextNameLookupVisitor Visitor(*this, Contexts, Name, Decls); - ModuleMgr.visit(&DeclContextNameLookupVisitor::visit, &Visitor); + + // If we can definitively determine which module file to look into, + // only look there. Otherwise, look in all module files. + ModuleFile *Definitive; + if (Contexts.size() == 1 && + (Definitive = getDefinitiveModuleFileFor(DC, *this))) { + DeclContextNameLookupVisitor::visit(*Definitive, &Visitor); + } else { + ModuleMgr.visit(&DeclContextNameLookupVisitor::visit, &Visitor); + } ++NumVisibleDeclContextsRead; SetExternalVisibleDeclsForName(DC, Name, Decls); return const_cast(DC)->lookup(Name); diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp index 37577ce..2f9e154 100644 --- a/clang/lib/Serialization/ASTWriter.cpp +++ b/clang/lib/Serialization/ASTWriter.cpp @@ -4780,6 +4780,7 @@ void ASTWriter::AddedVisibleDecl(const DeclContext *DC, const Decl *D) { if (!(!D->isFromASTFile() && cast(DC)->isFromASTFile())) return; // Not a source decl added to a DeclContext from PCH. + assert(!getDefinitiveDeclContext(DC) && "DeclContext not definitive!"); AddUpdatedDeclContext(DC); UpdatingVisibleDecls.push_back(D); } -- 2.7.4