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. llvm-svn: 189627
This commit is contained in:
parent
b81766ca23
commit
676c404dec
|
@ -148,7 +148,7 @@ class ASTContext : public RefCountedBase<ASTContext> {
|
||||||
mutable TypeInfoMap MemoizedTypeInfo;
|
mutable TypeInfoMap MemoizedTypeInfo;
|
||||||
|
|
||||||
/// \brief A cache mapping from CXXRecordDecls to key functions.
|
/// \brief A cache mapping from CXXRecordDecls to key functions.
|
||||||
llvm::DenseMap<const CXXRecordDecl*, const CXXMethodDecl*> KeyFunctions;
|
llvm::DenseMap<const CXXRecordDecl*, LazyDeclPtr> KeyFunctions;
|
||||||
|
|
||||||
/// \brief Mapping from ObjCContainers to their ObjCImplementations.
|
/// \brief Mapping from ObjCContainers to their ObjCImplementations.
|
||||||
llvm::DenseMap<ObjCContainerDecl*, ObjCImplDecl*> ObjCImpls;
|
llvm::DenseMap<ObjCContainerDecl*, ObjCImplDecl*> ObjCImpls;
|
||||||
|
|
|
@ -2438,32 +2438,31 @@ const CXXMethodDecl *ASTContext::getCurrentKeyFunction(const CXXRecordDecl *RD)
|
||||||
assert(RD->getDefinition() && "Cannot get key function for forward decl!");
|
assert(RD->getDefinition() && "Cannot get key function for forward decl!");
|
||||||
RD = cast<CXXRecordDecl>(RD->getDefinition());
|
RD = cast<CXXRecordDecl>(RD->getDefinition());
|
||||||
|
|
||||||
const CXXMethodDecl *&entry = KeyFunctions[RD];
|
LazyDeclPtr &Entry = KeyFunctions[RD];
|
||||||
if (!entry) {
|
if (!Entry)
|
||||||
entry = computeKeyFunction(*this, RD);
|
Entry = const_cast<CXXMethodDecl*>(computeKeyFunction(*this, RD));
|
||||||
}
|
|
||||||
|
|
||||||
return entry;
|
return cast_or_null<CXXMethodDecl>(Entry.get(getExternalSource()));
|
||||||
}
|
}
|
||||||
|
|
||||||
void ASTContext::setNonKeyFunction(const CXXMethodDecl *method) {
|
void ASTContext::setNonKeyFunction(const CXXMethodDecl *Method) {
|
||||||
assert(method == method->getFirstDeclaration() &&
|
assert(Method == Method->getFirstDeclaration() &&
|
||||||
"not working with method declaration from class definition");
|
"not working with method declaration from class definition");
|
||||||
|
|
||||||
// Look up the cache entry. Since we're working with the first
|
// Look up the cache entry. Since we're working with the first
|
||||||
// declaration, its parent must be the class definition, which is
|
// declaration, its parent must be the class definition, which is
|
||||||
// the correct key for the KeyFunctions hash.
|
// the correct key for the KeyFunctions hash.
|
||||||
llvm::DenseMap<const CXXRecordDecl*, const CXXMethodDecl*>::iterator
|
llvm::DenseMap<const CXXRecordDecl*, LazyDeclPtr>::iterator
|
||||||
i = KeyFunctions.find(method->getParent());
|
I = KeyFunctions.find(Method->getParent());
|
||||||
|
|
||||||
// If it's not cached, there's nothing to do.
|
// 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,
|
// If it is cached, check whether it's the target method, and if so,
|
||||||
// remove it from the cache.
|
// 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?
|
// FIXME: remember that we did this for module / chained PCH state?
|
||||||
KeyFunctions.erase(i);
|
KeyFunctions.erase(I);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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.
|
// compute it.
|
||||||
if (D->IsCompleteDefinition) {
|
if (D->IsCompleteDefinition) {
|
||||||
if (CXXMethodDecl *Key = ReadDeclAs<CXXMethodDecl>(Record, Idx))
|
if (DeclID KeyFn = ReadDeclID(Record, Idx))
|
||||||
C.KeyFunctions[D] = Key;
|
C.KeyFunctions[D] = KeyFn;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Redecl;
|
return Redecl;
|
||||||
|
|
|
@ -1,18 +1,25 @@
|
||||||
// RUN: %clang_cc1 -emit-pch -o %t %s
|
// RUN: %clang_cc1 -emit-pch -o %t.1 %s
|
||||||
// RUN: %clang_cc1 -error-on-deserialized-decl S1_method -include-pch %t -emit-llvm-only %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
|
#ifndef HEADER1
|
||||||
#define HEADER
|
#define HEADER1
|
||||||
// Header.
|
// Header.
|
||||||
|
|
||||||
struct S1 {
|
struct S1 {
|
||||||
void S1_method(); // This should not be deserialized.
|
void S1_method();
|
||||||
virtual void S1_keyfunc();
|
virtual void S1_keyfunc();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#elif !defined(HEADER2)
|
||||||
|
#define HEADER2
|
||||||
|
|
||||||
|
// Chained PCH.
|
||||||
|
S1 *p;
|
||||||
|
|
||||||
#else
|
#else
|
||||||
// Using the header.
|
|
||||||
|
// Using the headers.
|
||||||
|
|
||||||
void test(S1*) {
|
void test(S1*) {
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue