From cd03f862d82cac28c9517e2036716f8d49112c8b Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Thu, 29 Aug 2013 23:59:27 +0000 Subject: [PATCH] Be lazier when loading KeyFunctions from PCH/modules. We don't need to load these in eagerly if we're not actually processing a translation unit. The added laziness here also avoids us loading in parts of a CXXRecordDecl earlier than an upcoming class template specialization merging patch would like. Ideally, we should mark the vtable as used when we see a definition for the key function, rather than having a separate pass over dynamic classes at the end of the TU. The existing approach is pretty bad for PCH/modules, since it forcibly loads the declarations of all key functions in all imported modules, whether or not those key functions are defined. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@189627 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/AST/ASTContext.h | 2 +- lib/AST/RecordLayoutBuilder.cpp | 23 +++++++++++------------ lib/Serialization/ASTReaderDecl.cpp | 6 +++--- test/PCH/check-deserializations.cpp | 19 +++++++++++++------ 4 files changed, 28 insertions(+), 22 deletions(-) diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h index 06264efa06..6f27fbee0e 100644 --- a/include/clang/AST/ASTContext.h +++ b/include/clang/AST/ASTContext.h @@ -148,7 +148,7 @@ class ASTContext : public RefCountedBase { mutable TypeInfoMap MemoizedTypeInfo; /// \brief A cache mapping from CXXRecordDecls to key functions. - llvm::DenseMap KeyFunctions; + llvm::DenseMap KeyFunctions; /// \brief Mapping from ObjCContainers to their ObjCImplementations. llvm::DenseMap ObjCImpls; diff --git a/lib/AST/RecordLayoutBuilder.cpp b/lib/AST/RecordLayoutBuilder.cpp index 5df372639d..e5222c971e 100644 --- a/lib/AST/RecordLayoutBuilder.cpp +++ b/lib/AST/RecordLayoutBuilder.cpp @@ -2438,32 +2438,31 @@ const CXXMethodDecl *ASTContext::getCurrentKeyFunction(const CXXRecordDecl *RD) assert(RD->getDefinition() && "Cannot get key function for forward decl!"); RD = cast(RD->getDefinition()); - const CXXMethodDecl *&entry = KeyFunctions[RD]; - if (!entry) { - entry = computeKeyFunction(*this, RD); - } + LazyDeclPtr &Entry = KeyFunctions[RD]; + if (!Entry) + Entry = const_cast(computeKeyFunction(*this, RD)); - return entry; + return cast_or_null(Entry.get(getExternalSource())); } -void ASTContext::setNonKeyFunction(const CXXMethodDecl *method) { - assert(method == method->getFirstDeclaration() && +void ASTContext::setNonKeyFunction(const CXXMethodDecl *Method) { + assert(Method == Method->getFirstDeclaration() && "not working with method declaration from class definition"); // Look up the cache entry. Since we're working with the first // declaration, its parent must be the class definition, which is // the correct key for the KeyFunctions hash. - llvm::DenseMap::iterator - i = KeyFunctions.find(method->getParent()); + llvm::DenseMap::iterator + I = KeyFunctions.find(Method->getParent()); // If it's not cached, there's nothing to do. - if (i == KeyFunctions.end()) return; + if (I == KeyFunctions.end()) return; // If it is cached, check whether it's the target method, and if so, // remove it from the cache. - if (i->second == method) { + if (I->second.get(getExternalSource()) == Method) { // FIXME: remember that we did this for module / chained PCH state? - KeyFunctions.erase(i); + KeyFunctions.erase(I); } } diff --git a/lib/Serialization/ASTReaderDecl.cpp b/lib/Serialization/ASTReaderDecl.cpp index 3c93340f5e..a224aefa8f 100644 --- a/lib/Serialization/ASTReaderDecl.cpp +++ b/lib/Serialization/ASTReaderDecl.cpp @@ -1276,11 +1276,11 @@ ASTDeclReader::VisitCXXRecordDeclImpl(CXXRecordDecl *D) { } } - // Load the key function to avoid deserializing every method so we can + // Lazily load the key function to avoid deserializing every method so we can // compute it. if (D->IsCompleteDefinition) { - if (CXXMethodDecl *Key = ReadDeclAs(Record, Idx)) - C.KeyFunctions[D] = Key; + if (DeclID KeyFn = ReadDeclID(Record, Idx)) + C.KeyFunctions[D] = KeyFn; } return Redecl; diff --git a/test/PCH/check-deserializations.cpp b/test/PCH/check-deserializations.cpp index 9f73c95c54..66eb5b480b 100644 --- a/test/PCH/check-deserializations.cpp +++ b/test/PCH/check-deserializations.cpp @@ -1,18 +1,25 @@ -// RUN: %clang_cc1 -emit-pch -o %t %s -// RUN: %clang_cc1 -error-on-deserialized-decl S1_method -include-pch %t -emit-llvm-only %s +// 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 -#ifndef HEADER -#define HEADER +#ifndef HEADER1 +#define HEADER1 // Header. struct S1 { - void S1_method(); // This should not be deserialized. + void S1_method(); virtual void S1_keyfunc(); }; +#elif !defined(HEADER2) +#define HEADER2 + +// Chained PCH. +S1 *p; #else -// Using the header. + +// Using the headers. void test(S1*) { } -- 2.40.0