[cfe-commits] r116507 - in /cfe/trunk: include/clang/AST/Decl.h include/clang/AST/DeclBase.h include/clang/AST/ExternalASTSource.h include/clang/Serialization/ASTBitCodes.h include/clang/Serialization/ASTReader.h lib/AST/Decl.cpp lib/AST/DeclBase.cpp lib/Serialization/ASTReader.cpp lib/Serialization/ASTWriter.cpp test/PCH/check-deserializations.cpp

Argyrios Kyrtzidis akyrtzi at gmail.com
Thu Oct 14 13:14:34 PDT 2010


Author: akirtzidis
Date: Thu Oct 14 15:14:34 2010
New Revision: 116507

URL: http://llvm.org/viewvc/llvm-project?rev=116507&view=rev
Log:
Allow deserialization of just the fields of a record, when we want to iterate over them,
instead of deserializing the complete declaration context of the record.

Iterating over the fields of a record is very common (e.g to determine the layout), unfortunately we needlessly deserialize every declaration
that the declaration context of the record contains; this can be bad for large C++ classes that contain a lot of methods.
Fix this by allow deserialization of just the fields when we want to iterate over them.
Progress for rdar://7260160.

Added:
    cfe/trunk/test/PCH/check-deserializations.cpp
Modified:
    cfe/trunk/include/clang/AST/Decl.h
    cfe/trunk/include/clang/AST/DeclBase.h
    cfe/trunk/include/clang/AST/ExternalASTSource.h
    cfe/trunk/include/clang/Serialization/ASTBitCodes.h
    cfe/trunk/include/clang/Serialization/ASTReader.h
    cfe/trunk/lib/AST/Decl.cpp
    cfe/trunk/lib/AST/DeclBase.cpp
    cfe/trunk/lib/Serialization/ASTReader.cpp
    cfe/trunk/lib/Serialization/ASTWriter.cpp

Modified: cfe/trunk/include/clang/AST/Decl.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Decl.h?rev=116507&r1=116506&r2=116507&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/Decl.h (original)
+++ cfe/trunk/include/clang/AST/Decl.h Thu Oct 14 15:14:34 2010
@@ -2215,6 +2215,13 @@
   /// containing an object.
   bool HasObjectMember : 1;
 
+  /// \brief Whether the field declarations of this record have been loaded
+  /// from external storage. To avoid unnecessary deserialization of
+  /// methods/nested types we allow deserialization of just the fields
+  /// when needed.
+  mutable bool LoadedFieldsFromExternalStorage : 1;
+  friend void DeclContext::LoadLexicalDeclsFromExternalStorage() const;
+
 protected:
   RecordDecl(Kind DK, TagKind TK, DeclContext *DC,
              SourceLocation L, IdentifierInfo *Id,
@@ -2293,11 +2300,10 @@
   // data members, functions, constructors, destructors, etc.
   typedef specific_decl_iterator<FieldDecl> field_iterator;
 
-  field_iterator field_begin() const {
-    return field_iterator(decls_begin());
-  }
+  field_iterator field_begin() const;
+
   field_iterator field_end() const {
-    return field_iterator(decls_end());
+    return field_iterator(decl_iterator());
   }
 
   // field_empty - Whether there are any fields (non-static data
@@ -2315,6 +2321,10 @@
   static bool classofKind(Kind K) {
     return K >= firstRecord && K <= lastRecord;
   }
+
+private:
+  /// \brief Deserialize just the fields.
+  void LoadFieldsFromExternalStorage() const;
 };
 
 class FileScopeAsmDecl : public Decl {

Modified: cfe/trunk/include/clang/AST/DeclBase.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclBase.h?rev=116507&r1=116506&r2=116507&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/DeclBase.h (original)
+++ cfe/trunk/include/clang/AST/DeclBase.h Thu Oct 14 15:14:34 2010
@@ -698,6 +698,7 @@
   /// dependent context).
   mutable StoredDeclsMap *LookupPtr;
 
+protected:
   /// FirstDecl - The first declaration stored within this declaration
   /// context.
   mutable Decl *FirstDecl;
@@ -710,7 +711,12 @@
 
   friend class ExternalASTSource;
 
-protected:
+  /// \brief Build up a chain of declarations.
+  ///
+  /// \returns the first/last pair of declarations.
+  static std::pair<Decl *, Decl *>
+  BuildDeclChain(const llvm::SmallVectorImpl<Decl*> &Decls);
+
    DeclContext(Decl::Kind K)
      : DeclKind(K), ExternalLexicalStorage(false),
        ExternalVisibleStorage(false), LookupPtr(0), FirstDecl(0),

Modified: cfe/trunk/include/clang/AST/ExternalASTSource.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/ExternalASTSource.h?rev=116507&r1=116506&r2=116507&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/ExternalASTSource.h (original)
+++ cfe/trunk/include/clang/AST/ExternalASTSource.h Thu Oct 14 15:14:34 2010
@@ -14,6 +14,7 @@
 #ifndef LLVM_CLANG_AST_EXTERNAL_AST_SOURCE_H
 #define LLVM_CLANG_AST_EXTERNAL_AST_SOURCE_H
 
+#include "clang/AST/DeclBase.h"
 #include <cassert>
 #include <vector>
 
@@ -110,11 +111,31 @@
   virtual void MaterializeVisibleDecls(const DeclContext *DC) = 0;
 
   /// \brief Finds all declarations lexically contained within the given
-  /// DeclContext.
+  /// DeclContext, after applying an optional filter predicate.
+  ///
+  /// \param isKindWeWant a predicate function that returns true if the passed
+  /// declaration kind is one we are looking for. If NULL, all declarations
+  /// are returned.
   ///
   /// \return true if an error occurred
   virtual bool FindExternalLexicalDecls(const DeclContext *DC,
-                                llvm::SmallVectorImpl<Decl*> &Result) = 0;
+                                        bool (*isKindWeWant)(Decl::Kind),
+                                      llvm::SmallVectorImpl<Decl*> &Result) = 0;
+
+  /// \brief Finds all declarations lexically contained within the given
+  /// DeclContext.
+  ///
+  /// \return true if an error occurred
+  bool FindExternalLexicalDecls(const DeclContext *DC,
+                                llvm::SmallVectorImpl<Decl*> &Result) {
+    return FindExternalLexicalDecls(DC, 0, Result);
+  }
+
+  template <typename DeclTy>
+  bool FindExternalLexicalDeclsBy(const DeclContext *DC,
+                                llvm::SmallVectorImpl<Decl*> &Result) {
+    return FindExternalLexicalDecls(DC, DeclTy::classofKind, Result);
+  }
 
   /// \brief Notify ExternalASTSource that we started deserialization of
   /// a decl or type so until FinishedDeserializing is called there may be

Modified: cfe/trunk/include/clang/Serialization/ASTBitCodes.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Serialization/ASTBitCodes.h?rev=116507&r1=116506&r2=116507&view=diff
==============================================================================
--- cfe/trunk/include/clang/Serialization/ASTBitCodes.h (original)
+++ cfe/trunk/include/clang/Serialization/ASTBitCodes.h Thu Oct 14 15:14:34 2010
@@ -54,6 +54,9 @@
     /// reserved for the translation unit declaration.
     typedef uint32_t DeclID;
 
+    /// \brief a Decl::Kind/DeclID pair.
+    typedef std::pair<uint32_t, DeclID> KindDeclIDPair;
+
     /// \brief An ID number that refers to a type in an AST file.
     ///
     /// The ID of a type is partitioned into two parts: the lower

Modified: cfe/trunk/include/clang/Serialization/ASTReader.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Serialization/ASTReader.h?rev=116507&r1=116506&r2=116507&view=diff
==============================================================================
--- cfe/trunk/include/clang/Serialization/ASTReader.h (original)
+++ cfe/trunk/include/clang/Serialization/ASTReader.h Thu Oct 14 15:14:34 2010
@@ -405,7 +405,7 @@
   /// \brief Information about the contents of a DeclContext.
   struct DeclContextInfo {
     void *NameLookupTableData; // a ASTDeclContextNameLookupTable.
-    const serialization::DeclID *LexicalDecls;
+    const serialization::KindDeclIDPair *LexicalDecls;
     unsigned NumLexicalDecls;
   };
   // In a full chain, there could be multiple updates to every decl context,
@@ -928,6 +928,7 @@
   /// \returns true if there was an error while reading the
   /// declarations for this declaration context.
   virtual bool FindExternalLexicalDecls(const DeclContext *DC,
+                                        bool (*isKindWeWant)(Decl::Kind),
                                         llvm::SmallVectorImpl<Decl*> &Decls);
 
   /// \brief Notify ASTReader that we started deserialization of

Modified: cfe/trunk/lib/AST/Decl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Decl.cpp?rev=116507&r1=116506&r2=116507&view=diff
==============================================================================
--- cfe/trunk/lib/AST/Decl.cpp (original)
+++ cfe/trunk/lib/AST/Decl.cpp Thu Oct 14 15:14:34 2010
@@ -1651,6 +1651,7 @@
   HasFlexibleArrayMember = false;
   AnonymousStructOrUnion = false;
   HasObjectMember = false;
+  LoadedFieldsFromExternalStorage = false;
   assert(classof(static_cast<Decl*>(this)) && "Invalid Kind!");
 }
 
@@ -1673,6 +1674,13 @@
     cast<RecordDecl>(getDeclContext())->getDeclName() == getDeclName();
 }
 
+RecordDecl::field_iterator RecordDecl::field_begin() const {
+  if (hasExternalLexicalStorage() && !LoadedFieldsFromExternalStorage)
+    LoadFieldsFromExternalStorage();
+
+  return field_iterator(decl_iterator(FirstDecl));
+}
+
 /// completeDefinition - Notes that the definition of this type is now
 /// complete.
 void RecordDecl::completeDefinition() {
@@ -1691,6 +1699,31 @@
   return D;
 }
 
+void RecordDecl::LoadFieldsFromExternalStorage() const {
+  ExternalASTSource *Source = getASTContext().getExternalSource();
+  assert(hasExternalLexicalStorage() && Source && "No external storage?");
+
+  // Notify that we have a RecordDecl doing some initialization.
+  ExternalASTSource::Deserializing TheFields(Source);
+
+  llvm::SmallVector<Decl*, 64> Decls;
+  if (Source->FindExternalLexicalDeclsBy<FieldDecl>(this, Decls))
+    return;
+
+#ifndef NDEBUG
+  // Check that all decls we got were FieldDecls.
+  for (unsigned i=0, e=Decls.size(); i != e; ++i)
+    assert(isa<FieldDecl>(Decls[i]));
+#endif
+
+  LoadedFieldsFromExternalStorage = true;
+
+  if (Decls.empty())
+    return;
+
+  llvm::tie(FirstDecl, LastDecl) = BuildDeclChain(Decls);
+}
+
 //===----------------------------------------------------------------------===//
 // BlockDecl Implementation
 //===----------------------------------------------------------------------===//

Modified: cfe/trunk/lib/AST/DeclBase.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclBase.cpp?rev=116507&r1=116506&r2=116507&view=diff
==============================================================================
--- cfe/trunk/lib/AST/DeclBase.cpp (original)
+++ cfe/trunk/lib/AST/DeclBase.cpp Thu Oct 14 15:14:34 2010
@@ -599,6 +599,24 @@
   }
 }
 
+std::pair<Decl *, Decl *>
+DeclContext::BuildDeclChain(const llvm::SmallVectorImpl<Decl*> &Decls) {
+  // Build up a chain of declarations via the Decl::NextDeclInContext field.
+  Decl *FirstNewDecl = 0;
+  Decl *PrevDecl = 0;
+  for (unsigned I = 0, N = Decls.size(); I != N; ++I) {
+    Decl *D = Decls[I];
+    if (PrevDecl)
+      PrevDecl->NextDeclInContext = D;
+    else
+      FirstNewDecl = D;
+
+    PrevDecl = D;
+  }
+
+  return std::make_pair(FirstNewDecl, PrevDecl);
+}
+
 /// \brief Load the declarations within this lexical storage from an
 /// external source.
 void
@@ -619,26 +637,22 @@
   if (Decls.empty())
     return;
 
-  // Resolve all of the declaration IDs into declarations, building up
-  // a chain of declarations via the Decl::NextDeclInContext field.
-  Decl *FirstNewDecl = 0;
-  Decl *PrevDecl = 0;
-  for (unsigned I = 0, N = Decls.size(); I != N; ++I) {
-    Decl *D = Decls[I];
-    if (PrevDecl)
-      PrevDecl->NextDeclInContext = D;
-    else
-      FirstNewDecl = D;
-
-    PrevDecl = D;
-  }
+  // We may have already loaded just the fields of this record, in which case
+  // don't add the decls, just replace the FirstDecl/LastDecl chain.
+  if (const RecordDecl *RD = dyn_cast<RecordDecl>(this))
+    if (RD->LoadedFieldsFromExternalStorage) {
+      llvm::tie(FirstDecl, LastDecl) = BuildDeclChain(Decls);
+      return;
+    }
 
   // Splice the newly-read declarations into the beginning of the list
   // of declarations.
-  PrevDecl->NextDeclInContext = FirstDecl;
-  FirstDecl = FirstNewDecl;
+  Decl *ExternalFirst, *ExternalLast;
+  llvm::tie(ExternalFirst, ExternalLast) = BuildDeclChain(Decls);
+  ExternalLast->NextDeclInContext = FirstDecl;
+  FirstDecl = ExternalFirst;
   if (!LastDecl)
-    LastDecl = PrevDecl;
+    LastDecl = ExternalLast;
 }
 
 DeclContext::lookup_result

Modified: cfe/trunk/lib/Serialization/ASTReader.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTReader.cpp?rev=116507&r1=116506&r2=116507&view=diff
==============================================================================
--- cfe/trunk/lib/Serialization/ASTReader.cpp (original)
+++ cfe/trunk/lib/Serialization/ASTReader.cpp Thu Oct 14 15:14:34 2010
@@ -903,8 +903,8 @@
       return true;
     }
 
-    Info.LexicalDecls = reinterpret_cast<const DeclID*>(Blob);
-    Info.NumLexicalDecls = BlobLen / sizeof(DeclID);
+    Info.LexicalDecls = reinterpret_cast<const KindDeclIDPair*>(Blob);
+    Info.NumLexicalDecls = BlobLen / sizeof(KindDeclIDPair);
   } else {
     Info.LexicalDecls = 0;
     Info.NumLexicalDecls = 0;
@@ -1778,8 +1778,8 @@
     case TU_UPDATE_LEXICAL: {
       DeclContextInfo Info = {
         /* No visible information */ 0,
-        reinterpret_cast<const DeclID *>(BlobStart),
-        BlobLen / sizeof(DeclID)
+        reinterpret_cast<const KindDeclIDPair *>(BlobStart),
+        BlobLen / sizeof(KindDeclIDPair)
       };
       DeclContextOffsets[Context ? Context->getTranslationUnitDecl() : 0]
         .push_back(Info);
@@ -3242,6 +3242,7 @@
 }
 
 bool ASTReader::FindExternalLexicalDecls(const DeclContext *DC,
+                                         bool (*isKindWeWant)(Decl::Kind),
                                          llvm::SmallVectorImpl<Decl*> &Decls) {
   assert(DC->hasExternalLexicalStorage() &&
          "DeclContext has no lexical decls in storage");
@@ -3258,9 +3259,12 @@
       continue;
 
     // Load all of the declaration IDs
-    for (const DeclID *ID = I->LexicalDecls, *IDE = ID + I->NumLexicalDecls;
-         ID != IDE; ++ID) {
-      Decl *D = GetDecl(*ID);
+    for (const KindDeclIDPair *ID = I->LexicalDecls,
+                              *IDE = ID + I->NumLexicalDecls; ID != IDE; ++ID) {
+      if (isKindWeWant && !isKindWeWant((Decl::Kind)ID->first))
+        continue;
+
+      Decl *D = GetDecl(ID->second);
       assert(D && "Null decl in lexical decls");
       Decls.push_back(D);
     }

Modified: cfe/trunk/lib/Serialization/ASTWriter.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTWriter.cpp?rev=116507&r1=116506&r2=116507&view=diff
==============================================================================
--- cfe/trunk/lib/Serialization/ASTWriter.cpp (original)
+++ cfe/trunk/lib/Serialization/ASTWriter.cpp Thu Oct 14 15:14:34 2010
@@ -1474,14 +1474,15 @@
   uint64_t Offset = Stream.GetCurrentBitNo();
   RecordData Record;
   Record.push_back(DECL_CONTEXT_LEXICAL);
-  llvm::SmallVector<DeclID, 64> Decls;
+  llvm::SmallVector<KindDeclIDPair, 64> Decls;
   for (DeclContext::decl_iterator D = DC->decls_begin(), DEnd = DC->decls_end();
          D != DEnd; ++D)
-    Decls.push_back(GetDeclRef(*D));
+    Decls.push_back(std::make_pair((*D)->getKind(), GetDeclRef(*D)));
 
   ++NumLexicalDeclContexts;
   Stream.EmitRecordWithBlob(DeclContextLexicalAbbrev, Record,
-     reinterpret_cast<char*>(Decls.data()), Decls.size() * sizeof(DeclID));
+                            reinterpret_cast<char*>(Decls.data()),
+                            Decls.size() * sizeof(KindDeclIDPair));
   return Offset;
 }
 
@@ -2471,12 +2472,12 @@
   // We don't start with the translation unit, but with its decls that
   // don't come from the chained PCH.
   const TranslationUnitDecl *TU = Context.getTranslationUnitDecl();
-  llvm::SmallVector<DeclID, 64> NewGlobalDecls;
+  llvm::SmallVector<KindDeclIDPair, 64> NewGlobalDecls;
   for (DeclContext::decl_iterator I = TU->noload_decls_begin(),
                                   E = TU->noload_decls_end();
        I != E; ++I) {
     if ((*I)->getPCHLevel() == 0)
-      NewGlobalDecls.push_back(GetDeclRef(*I));
+      NewGlobalDecls.push_back(std::make_pair((*I)->getKind(), GetDeclRef(*I)));
     else if ((*I)->isChangedSinceDeserialization())
       (void)GetDeclRef(*I); // Make sure it's written, but don't record it.
   }
@@ -2489,7 +2490,7 @@
   Record.push_back(TU_UPDATE_LEXICAL);
   Stream.EmitRecordWithBlob(TuUpdateLexicalAbbrev, Record,
                           reinterpret_cast<const char*>(NewGlobalDecls.data()),
-                          NewGlobalDecls.size() * sizeof(DeclID));
+                          NewGlobalDecls.size() * sizeof(KindDeclIDPair));
   // And in C++, a visible updates block for the TU.
   if (Context.getLangOptions().CPlusPlus) {
     Abv = new llvm::BitCodeAbbrev();

Added: cfe/trunk/test/PCH/check-deserializations.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/PCH/check-deserializations.cpp?rev=116507&view=auto
==============================================================================
--- cfe/trunk/test/PCH/check-deserializations.cpp (added)
+++ cfe/trunk/test/PCH/check-deserializations.cpp Thu Oct 14 15:14:34 2010
@@ -0,0 +1,19 @@
+// RUN: %clang_cc1 -emit-pch -o %t %s
+// RUN: %clang_cc1 -error-on-deserialized-decl S1_method -include-pch %t -emit-llvm-only %s 
+
+#ifndef HEADER
+#define HEADER
+// Header.
+
+struct S1 {
+  void S1_method(); // This should not be deserialized.
+};
+
+
+#else
+// Using the header.
+
+void test(S1*) {
+}
+
+#endif





More information about the cfe-commits mailing list