r189646 - Don't eagerly load all conversion operators when loading a class declaration

Richard Smith richard-llvm at metafoo.co.uk
Thu Aug 29 21:46:40 PDT 2013


Author: rsmith
Date: Thu Aug 29 23:46:40 2013
New Revision: 189646

URL: http://llvm.org/viewvc/llvm-project?rev=189646&view=rev
Log:
Don't eagerly load all conversion operators when loading a class declaration
from a PCH/module.

Modified:
    cfe/trunk/include/clang/AST/ASTUnresolvedSet.h
    cfe/trunk/include/clang/AST/ASTVector.h
    cfe/trunk/include/clang/AST/DeclCXX.h
    cfe/trunk/include/clang/AST/UnresolvedSet.h
    cfe/trunk/include/clang/Serialization/ASTReader.h
    cfe/trunk/lib/AST/DeclCXX.cpp
    cfe/trunk/lib/Serialization/ASTReader.cpp
    cfe/trunk/lib/Serialization/ASTWriter.cpp
    cfe/trunk/test/PCH/check-deserializations.cpp

Modified: cfe/trunk/include/clang/AST/ASTUnresolvedSet.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/ASTUnresolvedSet.h?rev=189646&r1=189645&r2=189646&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/ASTUnresolvedSet.h (original)
+++ cfe/trunk/include/clang/AST/ASTUnresolvedSet.h Thu Aug 29 23:46:40 2013
@@ -22,12 +22,21 @@ namespace clang {
 
 /// \brief An UnresolvedSet-like class which uses the ASTContext's allocator.
 class ASTUnresolvedSet {
-  typedef ASTVector<DeclAccessPair> DeclsTy;
+  struct DeclsTy : ASTVector<DeclAccessPair> {
+    DeclsTy() {}
+    DeclsTy(ASTContext &C, unsigned N) : ASTVector<DeclAccessPair>(C, N) {}
+
+    bool isLazy() const { return getTag(); }
+    void setLazy(bool Lazy) { setTag(Lazy); }
+  };
+
   DeclsTy Decls;
 
   ASTUnresolvedSet(const ASTUnresolvedSet &) LLVM_DELETED_FUNCTION;
   void operator=(const ASTUnresolvedSet &) LLVM_DELETED_FUNCTION;
 
+  friend class LazyASTUnresolvedSet;
+
 public:
   ASTUnresolvedSet() {}
   ASTUnresolvedSet(ASTContext &C, unsigned N) : Decls(C, N) {}
@@ -48,7 +57,7 @@ public:
   /// Replaces the given declaration with the new one, once.
   ///
   /// \return true if the set changed
-  bool replace(const NamedDecl* Old, NamedDecl *New, AccessSpecifier AS) {
+  bool replace(const NamedDecl *Old, NamedDecl *New, AccessSpecifier AS) {
     for (DeclsTy::iterator I = Decls.begin(), E = Decls.end(); I != E; ++I) {
       if (I->getDecl() == Old) {
         I->set(New, AS);
@@ -76,7 +85,29 @@ public:
   DeclAccessPair &operator[](unsigned I) { return Decls[I]; }
   const DeclAccessPair &operator[](unsigned I) const { return Decls[I]; }
 };
-  
+
+/// \brief An UnresolvedSet-like class that might not have been loaded from the
+/// external AST source yet.
+class LazyASTUnresolvedSet {
+  mutable ASTUnresolvedSet Impl;
+
+  void getFromExternalSource(ASTContext &C) const;
+
+public:
+  ASTUnresolvedSet &get(ASTContext &C) const {
+    if (Impl.Decls.isLazy())
+      getFromExternalSource(C);
+    return Impl;
+  }
+
+  void reserve(ASTContext &C, unsigned N) { Impl.reserve(C, N); }
+  void addLazyDecl(ASTContext &C, uintptr_t ID, AccessSpecifier AS) {
+    assert(Impl.empty() || Impl.Decls.isLazy());
+    Impl.Decls.setLazy(true);
+    Impl.addDecl(C, reinterpret_cast<NamedDecl*>(ID << 2), AS);
+  }
+};
+
 } // namespace clang
 
 #endif

Modified: cfe/trunk/include/clang/AST/ASTVector.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/ASTVector.h?rev=189646&r1=189645&r2=189646&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/ASTVector.h (original)
+++ cfe/trunk/include/clang/AST/ASTVector.h Thu Aug 29 23:46:40 2013
@@ -55,16 +55,24 @@ namespace clang {
 
 template<typename T>
 class ASTVector {
-  T *Begin, *End, *Capacity;
+private:
+  T *Begin, *End;
+  llvm::PointerIntPair<T*, 1, bool> Capacity;
 
   void setEnd(T *P) { this->End = P; }
 
+protected:
+  // Make a tag bit available to users of this class.
+  // FIXME: This is a horrible hack.
+  bool getTag() const { return Capacity.getInt(); }
+  void setTag(bool B) { Capacity.setInt(B); }
+
 public:
   // Default ctor - Initialize to empty.
-  ASTVector() : Begin(NULL), End(NULL), Capacity(NULL) { }
+  ASTVector() : Begin(0), End(0), Capacity(0, false) {}
 
   ASTVector(const ASTContext &C, unsigned N)
-  : Begin(NULL), End(NULL), Capacity(NULL) {
+      : Begin(0), End(0), Capacity(0, false) {
     reserve(C, N);
   }
 
@@ -156,7 +164,7 @@ public:
   }
 
   void push_back(const_reference Elt, const ASTContext &C) {
-    if (End < Capacity) {
+    if (End < this->capacity_ptr()) {
     Retry:
       new (End) T(Elt);
       ++End;
@@ -167,13 +175,13 @@ public:
   }
 
   void reserve(const ASTContext &C, unsigned N) {
-    if (unsigned(Capacity-Begin) < N)
+    if (unsigned(this->capacity_ptr()-Begin) < N)
       grow(C, N);
   }
 
   /// capacity - Return the total number of elements in the currently allocated
   /// buffer.
-  size_t capacity() const { return Capacity - Begin; }
+  size_t capacity() const { return this->capacity_ptr() - Begin; }
 
   /// append - Add the specified range to the end of the SmallVector.
   ///
@@ -220,7 +228,7 @@ public:
       return this->end()-1;
     }
 
-    if (this->End < this->Capacity) {
+    if (this->End < this->capacity_ptr()) {
     Retry:
       new (this->end()) T(this->back());
       this->setEnd(this->end()+1);
@@ -365,13 +373,16 @@ private:
   }
 
 protected:
-  iterator capacity_ptr() { return (iterator)this->Capacity; }
+  const_iterator capacity_ptr() const {
+    return (iterator) Capacity.getPointer();
+  }
+  iterator capacity_ptr() { return (iterator)Capacity.getPointer(); }
 };
 
 // Define this out-of-line to dissuade the C++ compiler from inlining it.
 template <typename T>
 void ASTVector<T>::grow(const ASTContext &C, size_t MinSize) {
-  size_t CurCapacity = Capacity-Begin;
+  size_t CurCapacity = this->capacity();
   size_t CurSize = size();
   size_t NewCapacity = 2*CurCapacity;
   if (NewCapacity < MinSize)
@@ -394,7 +405,7 @@ void ASTVector<T>::grow(const ASTContext
   // ASTContext never frees any memory.
   Begin = NewElts;
   End = NewElts+CurSize;
-  Capacity = Begin+NewCapacity;
+  Capacity.setPointer(Begin+NewCapacity);
 }
 
 } // end: clang namespace

Modified: cfe/trunk/include/clang/AST/DeclCXX.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclCXX.h?rev=189646&r1=189645&r2=189646&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/DeclCXX.h (original)
+++ cfe/trunk/include/clang/AST/DeclCXX.h Thu Aug 29 23:46:40 2013
@@ -473,14 +473,14 @@ class CXXRecordDecl : public RecordDecl
     /// inherited conversion functions).
     ///
     /// Each of the entries in this overload set is a CXXConversionDecl.
-    ASTUnresolvedSet Conversions;
+    LazyASTUnresolvedSet Conversions;
 
     /// \brief The conversion functions of this C++ class and all those
     /// inherited conversion functions that are visible in this class.
     ///
     /// Each of the entries in this overload set is a CXXConversionDecl or a
     /// FunctionTemplateDecl.
-    ASTUnresolvedSet VisibleConversions;
+    LazyASTUnresolvedSet VisibleConversions;
 
     /// \brief The declaration which defines this record.
     CXXRecordDecl *Definition;
@@ -1014,10 +1014,10 @@ public:
 
   typedef UnresolvedSetIterator conversion_iterator;
   conversion_iterator conversion_begin() const {
-    return data().Conversions.begin();
+    return data().Conversions.get(getASTContext()).begin();
   }
   conversion_iterator conversion_end() const {
-    return data().Conversions.end();
+    return data().Conversions.get(getASTContext()).end();
   }
 
   /// Removes a conversion function from this class.  The conversion

Modified: cfe/trunk/include/clang/AST/UnresolvedSet.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/UnresolvedSet.h?rev=189646&r1=189645&r2=189646&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/UnresolvedSet.h (original)
+++ cfe/trunk/include/clang/AST/UnresolvedSet.h Thu Aug 29 23:46:40 2013
@@ -51,6 +51,7 @@ public:
   typedef std::iterator_traits<IteratorTy>::iterator_category iterator_category;
 
   NamedDecl *getDecl() const { return ir->getDecl(); }
+  void setDecl(NamedDecl *ND) const { return ir->setDecl(ND); }
   AccessSpecifier getAccess() const { return ir->getAccess(); }
   void setAccess(AccessSpecifier AS) { ir->setAccess(AS); }
   DeclAccessPair getPair() const { return *ir; }

Modified: cfe/trunk/include/clang/Serialization/ASTReader.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Serialization/ASTReader.h?rev=189646&r1=189645&r2=189646&view=diff
==============================================================================
--- cfe/trunk/include/clang/Serialization/ASTReader.h (original)
+++ cfe/trunk/include/clang/Serialization/ASTReader.h Thu Aug 29 23:46:40 2013
@@ -88,7 +88,7 @@ class TypeLocReader;
 struct HeaderFileInfo;
 class VersionTuple;
 class TargetOptions;
-class ASTUnresolvedSet;
+class LazyASTUnresolvedSet;
 
 /// \brief Abstract interface for callback invocations by the ASTReader.
 ///
@@ -1745,7 +1745,7 @@ public:
                            unsigned &Idx);
 
   /// \brief Read a UnresolvedSet structure.
-  void ReadUnresolvedSet(ModuleFile &F, ASTUnresolvedSet &Set,
+  void ReadUnresolvedSet(ModuleFile &F, LazyASTUnresolvedSet &Set,
                          const RecordData &Record, unsigned &Idx);
 
   /// \brief Read a C++ base specifier.

Modified: cfe/trunk/lib/AST/DeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclCXX.cpp?rev=189646&r1=189645&r2=189646&view=diff
==============================================================================
--- cfe/trunk/lib/AST/DeclCXX.cpp (original)
+++ cfe/trunk/lib/AST/DeclCXX.cpp Thu Aug 29 23:46:40 2013
@@ -35,6 +35,17 @@ AccessSpecDecl *AccessSpecDecl::CreateDe
   return new (Mem) AccessSpecDecl(EmptyShell());
 }
 
+void LazyASTUnresolvedSet::getFromExternalSource(ASTContext &C) const {
+  ExternalASTSource *Source = C.getExternalSource();
+  assert(Impl.Decls.isLazy() && "getFromExternalSource for non-lazy set");
+  assert(Source && "getFromExternalSource with no external source");
+
+  for (ASTUnresolvedSet::iterator I = Impl.begin(); I != Impl.end(); ++I)
+    I.setDecl(cast<NamedDecl>(Source->GetExternalDecl(
+        reinterpret_cast<uintptr_t>(I.getDecl()) >> 2)));
+  Impl.Decls.setLazy(false);
+}
+
 CXXRecordDecl::DefinitionData::DefinitionData(CXXRecordDecl *D)
   : UserDeclaredConstructor(false), UserDeclaredSpecialMembers(0),
     Aggregate(true), PlainOldData(true), Empty(true), Polymorphic(false),
@@ -552,18 +563,16 @@ void CXXRecordDecl::addedMember(Decl *D)
 
       if (Conversion->getPrimaryTemplate()) {
         // We don't record specializations.
-      } else if (FunTmpl) {
-        if (FunTmpl->getPreviousDecl())
-          data().Conversions.replace(FunTmpl->getPreviousDecl(),
-                                     FunTmpl, AS);
-        else
-          data().Conversions.addDecl(getASTContext(), FunTmpl, AS);
       } else {
-        if (Conversion->getPreviousDecl())
-          data().Conversions.replace(Conversion->getPreviousDecl(),
-                                     Conversion, AS);
+        ASTContext &Ctx = getASTContext();
+        ASTUnresolvedSet &Conversions = data().Conversions.get(Ctx);
+        NamedDecl *Primary =
+            FunTmpl ? cast<NamedDecl>(FunTmpl) : cast<NamedDecl>(Conversion);
+        if (Primary->getPreviousDecl())
+          Conversions.replace(cast<NamedDecl>(Primary->getPreviousDecl()),
+                              Primary, AS);
         else
-          data().Conversions.addDecl(getASTContext(), Conversion, AS);
+          Conversions.addDecl(Ctx, Primary, AS);
       }
     }
 
@@ -880,10 +889,13 @@ void CXXRecordDecl::addedMember(Decl *D)
   }
   
   // Handle using declarations of conversion functions.
-  if (UsingShadowDecl *Shadow = dyn_cast<UsingShadowDecl>(D))
+  if (UsingShadowDecl *Shadow = dyn_cast<UsingShadowDecl>(D)) {
     if (Shadow->getDeclName().getNameKind()
-          == DeclarationName::CXXConversionFunctionName)
-      data().Conversions.addDecl(getASTContext(), Shadow, Shadow->getAccess());
+          == DeclarationName::CXXConversionFunctionName) {
+      ASTContext &Ctx = getASTContext();
+      data().Conversions.get(Ctx).addDecl(Ctx, Shadow, Shadow->getAccess());
+    }
+  }
 }
 
 void CXXRecordDecl::finishedDefaultedOrDeletedMember(CXXMethodDecl *D) {
@@ -1083,16 +1095,21 @@ static void CollectVisibleConversions(AS
 /// in current class; including conversion function templates.
 std::pair<CXXRecordDecl::conversion_iterator,CXXRecordDecl::conversion_iterator>
 CXXRecordDecl::getVisibleConversionFunctions() {
-  // If root class, all conversions are visible.
-  if (bases_begin() == bases_end())
-    return std::make_pair(data().Conversions.begin(), data().Conversions.end());
-  // If visible conversion list is already evaluated, return it.
-  if (!data().ComputedVisibleConversions) {
-    CollectVisibleConversions(getASTContext(), this, data().VisibleConversions);
-    data().ComputedVisibleConversions = true;
+  ASTContext &Ctx = getASTContext();
+
+  ASTUnresolvedSet *Set;
+  if (bases_begin() == bases_end()) {
+    // If root class, all conversions are visible.
+    Set = &data().Conversions.get(Ctx);
+  } else {
+    Set = &data().VisibleConversions.get(Ctx);
+    // If visible conversion list is not evaluated, evaluate it.
+    if (!data().ComputedVisibleConversions) {
+      CollectVisibleConversions(Ctx, this, *Set);
+      data().ComputedVisibleConversions = true;
+    }
   }
-  return std::make_pair(data().VisibleConversions.begin(),
-                        data().VisibleConversions.end());
+  return std::make_pair(Set->begin(), Set->end());
 }
 
 void CXXRecordDecl::removeConversion(const NamedDecl *ConvDecl) {
@@ -1107,7 +1124,7 @@ void CXXRecordDecl::removeConversion(con
   // with sufficiently large numbers of directly-declared conversions
   // that asymptotic behavior matters.
 
-  ASTUnresolvedSet &Convs = data().Conversions;
+  ASTUnresolvedSet &Convs = data().Conversions.get(getASTContext());
   for (unsigned I = 0, E = Convs.size(); I != E; ++I) {
     if (Convs[I].getDecl() == ConvDecl) {
       Convs.erase(I);
@@ -1233,8 +1250,7 @@ void CXXRecordDecl::completeDefinition(C
   }
   
   // Set access bits correctly on the directly-declared conversions.
-  for (UnresolvedSetIterator I = data().Conversions.begin(), 
-                             E = data().Conversions.end(); 
+  for (conversion_iterator I = conversion_begin(), E = conversion_end();
        I != E; ++I)
     I.setAccess((*I)->getAccess());
 }

Modified: cfe/trunk/lib/Serialization/ASTReader.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTReader.cpp?rev=189646&r1=189645&r2=189646&view=diff
==============================================================================
--- cfe/trunk/lib/Serialization/ASTReader.cpp (original)
+++ cfe/trunk/lib/Serialization/ASTReader.cpp Thu Aug 29 23:46:40 2013
@@ -6972,14 +6972,14 @@ ReadTemplateArgumentList(SmallVectorImpl
 }
 
 /// \brief Read a UnresolvedSet structure.
-void ASTReader::ReadUnresolvedSet(ModuleFile &F, ASTUnresolvedSet &Set,
+void ASTReader::ReadUnresolvedSet(ModuleFile &F, LazyASTUnresolvedSet &Set,
                                   const RecordData &Record, unsigned &Idx) {
   unsigned NumDecls = Record[Idx++];
   Set.reserve(Context, NumDecls);
   while (NumDecls--) {
-    NamedDecl *D = ReadDeclAs<NamedDecl>(F, Record, Idx);
+    DeclID ID = ReadDeclID(F, Record, Idx);
     AccessSpecifier AS = (AccessSpecifier)Record[Idx++];
-    Set.addDecl(Context, D, AS);
+    Set.addLazyDecl(Context, ID, AS);
   }
 }
 

Modified: cfe/trunk/lib/Serialization/ASTWriter.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTWriter.cpp?rev=189646&r1=189645&r2=189646&view=diff
==============================================================================
--- cfe/trunk/lib/Serialization/ASTWriter.cpp (original)
+++ cfe/trunk/lib/Serialization/ASTWriter.cpp Thu Aug 29 23:46:40 2013
@@ -5117,8 +5117,8 @@ void ASTWriter::AddCXXDefinitionData(con
     AddCXXBaseSpecifiersRef(Data.getVBases(), Data.getVBases() + Data.NumVBases, 
                             Record);
 
-  AddUnresolvedSet(Data.Conversions, Record);
-  AddUnresolvedSet(Data.VisibleConversions, Record);
+  AddUnresolvedSet(Data.Conversions.get(*Context), Record);
+  AddUnresolvedSet(Data.VisibleConversions.get(*Context), Record);
   // Data.Definition is the owning decl, no need to write it. 
   AddDeclRef(D->getFirstFriend(), Record);
   

Modified: cfe/trunk/test/PCH/check-deserializations.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/PCH/check-deserializations.cpp?rev=189646&r1=189645&r2=189646&view=diff
==============================================================================
--- cfe/trunk/test/PCH/check-deserializations.cpp (original)
+++ cfe/trunk/test/PCH/check-deserializations.cpp Thu Aug 29 23:46:40 2013
@@ -1,6 +1,6 @@
 // RUN: %clang_cc1 -emit-pch -o %t.1 %s
-// RUN: %clang_cc1 -error-on-deserialized-decl S1_keyfunc -include-pch %t.1 -emit-pch -o %t.2 %s
-// RUN: %clang_cc1 -error-on-deserialized-decl S1_method -include-pch %t.2 -emit-llvm-only %s
+// RUN: %clang_cc1 -error-on-deserialized-decl S1_keyfunc -error-on-deserialized-decl S3 -include-pch %t.1 -emit-pch -o %t.2 %s
+// RUN: %clang_cc1 -error-on-deserialized-decl S1_method -error-on-deserialized-decl S3 -include-pch %t.2 -emit-llvm-only %s
 
 #ifndef HEADER1
 #define HEADER1
@@ -11,17 +11,24 @@ struct S1 {
   virtual void S1_keyfunc();
 };
 
+struct S3 {};
+
+struct S2 {
+  operator S3();
+};
+
 #elif !defined(HEADER2)
 #define HEADER2
 
 // Chained PCH.
-S1 *p;
+S1 *s1;
+S2 *s2;
 
 #else
 
 // Using the headers.
 
-void test(S1*) {
+void test(S1*, S2*) {
 }
 
 #endif





More information about the cfe-commits mailing list