]> granicus.if.org Git - clang/commitdiff
Introduce a fast path for the ASTReader's name lookup within a
authorDouglas Gregor <dgregor@apple.com>
Mon, 21 Jan 2013 15:25:38 +0000 (15:25 +0000)
committerDouglas Gregor <dgregor@apple.com>
Mon, 21 Jan 2013 15:25:38 +0000 (15:25 +0000)
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.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@173050 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/Serialization/ASTReader.h
lib/Serialization/ASTCommon.cpp
lib/Serialization/ASTCommon.h
lib/Serialization/ASTReader.cpp
lib/Serialization/ASTWriter.cpp

index 328f9672f8765f3a598c1ef8024e16b2177e79e4..994008de44bd822f068e6f32edb6b654f6e5ea99 100644 (file)
@@ -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);
index bf1e25a412083d29c86143b72675003fb92713a0..df87165df794f018ab736d7ec019878a8b3dd2e0 100644 (file)
@@ -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<TagDecl>(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<Decl>(DC);
+
+  case Decl::ObjCProtocol:
+    if (const ObjCProtocolDecl *Def
+          = cast<ObjCProtocolDecl>(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;
+
+}
index 643deb24d10ec39a47e39f01939dfcc9acec3b89..f9db1f0f94dcff74e7aa5b28823423eb0fa1cea5 100644 (file)
@@ -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
index 00bae0aea3dceafc94e309dbdd3d60ae877b61f2..db850f3f83fe75eba6c6378457af2801c47291ef 100644 (file)
@@ -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<DeclContext*>(DC)->lookup(Name);
index 37577ce071851e3ad6b017bce3f09be9b10c0a24..2f9e1543c2cf9eed0f99e0c308ce61df7f6520f4 100644 (file)
@@ -4780,6 +4780,7 @@ void ASTWriter::AddedVisibleDecl(const DeclContext *DC, const Decl *D) {
   if (!(!D->isFromASTFile() && cast<Decl>(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);
 }