Move key functions to a separate map.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@90745 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h
index 1e32a25..fe27027 100644
--- a/include/clang/AST/ASTContext.h
+++ b/include/clang/AST/ASTContext.h
@@ -45,6 +45,8 @@
class SourceManager;
class TargetInfo;
// Decls
+ class CXXMethodDecl;
+ class CXXRecordDecl;
class Decl;
class FieldDecl;
class ObjCIvarDecl;
@@ -106,6 +108,9 @@
llvm::DenseMap<const RecordDecl*, const ASTRecordLayout*> ASTRecordLayouts;
llvm::DenseMap<const ObjCContainerDecl*, const ASTRecordLayout*> ObjCLayouts;
+ /// KeyFunctions - A cache mapping from CXXRecordDecls to key functions.
+ llvm::DenseMap<const CXXRecordDecl*, const CXXMethodDecl*> KeyFunctions;
+
/// \brief Mapping from ObjCContainers to their ObjCImplementations.
llvm::DenseMap<ObjCContainerDecl*, ObjCImplDecl*> ObjCImpls;
@@ -852,6 +857,13 @@
const ASTRecordLayout &
getASTObjCImplementationLayout(const ObjCImplementationDecl *D);
+ /// getKeyFunction - Get the key function for the given record decl.
+ /// The key function is, according to the Itanium C++ ABI section 5.2.3:
+ ///
+ /// ...the first non-pure virtual function that is not inline at the point
+ /// of class definition.
+ const CXXMethodDecl *getKeyFunction(const CXXRecordDecl *RD);
+
void CollectObjCIvars(const ObjCInterfaceDecl *OI,
llvm::SmallVectorImpl<FieldDecl*> &Fields);
diff --git a/include/clang/AST/RecordLayout.h b/include/clang/AST/RecordLayout.h
index 5d2973e..a8334b6 100644
--- a/include/clang/AST/RecordLayout.h
+++ b/include/clang/AST/RecordLayout.h
@@ -119,13 +119,6 @@
/// VBaseOffsets - Contains a map from vbase classes to their offset.
/// FIXME: This should really use a SmallPtrMap, once we have one in LLVM :)
llvm::DenseMap<const CXXRecordDecl *, uint64_t> VBaseOffsets;
-
- /// KeyFunction - The key function, according to the Itanium C++ ABI,
- /// section 5.2.3:
- ///
- /// ...the first non-pure virtual function that is not inline at the point
- /// of class definition.
- const CXXMethodDecl *KeyFunction;
};
/// CXXInfo - If the record layout is for a C++ record, this will have
@@ -154,8 +147,7 @@
const std::pair<const CXXRecordDecl *, uint64_t> *bases,
unsigned numbases,
const std::pair<const CXXRecordDecl *, uint64_t> *vbases,
- unsigned numvbases,
- const CXXMethodDecl *KeyFunction)
+ unsigned numvbases)
: Size(size), DataSize(datasize), FieldOffsets(0), Alignment(alignment),
FieldCount(fieldcount), CXXInfo(new CXXRecordLayoutInfo) {
if (FieldCount > 0) {
@@ -171,7 +163,6 @@
CXXInfo->BaseOffsets[bases[i].first] = bases[i].second;
for (unsigned i = 0; i != numvbases; ++i)
CXXInfo->VBaseOffsets[vbases[i].first] = vbases[i].second;
- CXXInfo->KeyFunction = KeyFunction;
}
~ASTRecordLayout() {
@@ -254,13 +245,6 @@
return CXXInfo->VBaseOffsets[VBase];
}
- /// getKeyFunction - Get the key function.
- const CXXMethodDecl *getKeyFunction() const {
- assert(CXXInfo && "Record layout does not have C++ specific info!");
-
- return CXXInfo->KeyFunction;
- }
-
primary_base_info_iterator primary_base_begin() const {
assert(CXXInfo && "Record layout does not have C++ specific info!");
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp
index cc96a5d..490f338 100644
--- a/lib/AST/ASTContext.cpp
+++ b/lib/AST/ASTContext.cpp
@@ -1104,6 +1104,20 @@
return *NewEntry;
}
+const CXXMethodDecl *ASTContext::getKeyFunction(const CXXRecordDecl *RD) {
+ RD = cast<CXXRecordDecl>(RD->getDefinition(*this));
+ assert(RD && "Cannot get key function for forward declarations!");
+
+ const CXXMethodDecl *&Entry = KeyFunctions[RD];
+ if (!Entry)
+ Entry = ASTRecordLayoutBuilder::ComputeKeyFunction(RD);
+ else
+ assert(Entry == ASTRecordLayoutBuilder::ComputeKeyFunction(RD) &&
+ "Key function changed!");
+
+ return Entry;
+}
+
//===----------------------------------------------------------------------===//
// Type creation/memoization methods
//===----------------------------------------------------------------------===//
diff --git a/lib/AST/RecordLayoutBuilder.cpp b/lib/AST/RecordLayoutBuilder.cpp
index 0886739..550a32b 100644
--- a/lib/AST/RecordLayoutBuilder.cpp
+++ b/lib/AST/RecordLayoutBuilder.cpp
@@ -663,8 +663,61 @@
Alignment = NewAlignment;
}
-static const CXXMethodDecl *GetKeyFunction(const CXXRecordDecl *RD) {
- if (!RD->isDynamicClass())
+const ASTRecordLayout *
+ASTRecordLayoutBuilder::ComputeLayout(ASTContext &Ctx,
+ const RecordDecl *D) {
+ ASTRecordLayoutBuilder Builder(Ctx);
+
+ Builder.Layout(D);
+
+ if (!isa<CXXRecordDecl>(D))
+ return new ASTRecordLayout(Builder.Size, Builder.Alignment, Builder.Size,
+ Builder.FieldOffsets.data(),
+ Builder.FieldOffsets.size());
+
+ // FIXME: This is not always correct. See the part about bitfields at
+ // http://www.codesourcery.com/public/cxx-abi/abi.html#POD for more info.
+ // FIXME: IsPODForThePurposeOfLayout should be stored in the record layout.
+ bool IsPODForThePurposeOfLayout = cast<CXXRecordDecl>(D)->isPOD();
+
+ // FIXME: This should be done in FinalizeLayout.
+ uint64_t DataSize =
+ IsPODForThePurposeOfLayout ? Builder.Size : Builder.DataSize;
+ uint64_t NonVirtualSize =
+ IsPODForThePurposeOfLayout ? DataSize : Builder.NonVirtualSize;
+
+ return new ASTRecordLayout(Builder.Size, Builder.Alignment, DataSize,
+ Builder.FieldOffsets.data(),
+ Builder.FieldOffsets.size(),
+ NonVirtualSize,
+ Builder.NonVirtualAlignment,
+ Builder.PrimaryBase,
+ Builder.Bases.data(),
+ Builder.Bases.size(),
+ Builder.VBases.data(),
+ Builder.VBases.size());
+}
+
+const ASTRecordLayout *
+ASTRecordLayoutBuilder::ComputeLayout(ASTContext &Ctx,
+ const ObjCInterfaceDecl *D,
+ const ObjCImplementationDecl *Impl) {
+ ASTRecordLayoutBuilder Builder(Ctx);
+
+ Builder.Layout(D, Impl);
+
+ return new ASTRecordLayout(Builder.Size, Builder.Alignment,
+ Builder.DataSize,
+ Builder.FieldOffsets.data(),
+ Builder.FieldOffsets.size());
+}
+
+const CXXMethodDecl *
+ASTRecordLayoutBuilder::ComputeKeyFunction(const CXXRecordDecl *RD) {
+ assert(RD->isDynamicClass() && "Class does not have any virtual methods!");
+
+ // If a class isnt' polymorphic it doesn't have a key function.
+ if (!RD->isPolymorphic())
return 0;
for (CXXRecordDecl::method_iterator I = RD->method_begin(),
@@ -692,54 +745,3 @@
return 0;
}
-const ASTRecordLayout *
-ASTRecordLayoutBuilder::ComputeLayout(ASTContext &Ctx,
- const RecordDecl *D) {
- ASTRecordLayoutBuilder Builder(Ctx);
-
- Builder.Layout(D);
-
- if (!isa<CXXRecordDecl>(D))
- return new ASTRecordLayout(Builder.Size, Builder.Alignment, Builder.Size,
- Builder.FieldOffsets.data(),
- Builder.FieldOffsets.size());
-
- // FIXME: This is not always correct. See the part about bitfields at
- // http://www.codesourcery.com/public/cxx-abi/abi.html#POD for more info.
- // FIXME: IsPODForThePurposeOfLayout should be stored in the record layout.
- bool IsPODForThePurposeOfLayout = cast<CXXRecordDecl>(D)->isPOD();
-
- // FIXME: This should be done in FinalizeLayout.
- uint64_t DataSize =
- IsPODForThePurposeOfLayout ? Builder.Size : Builder.DataSize;
- uint64_t NonVirtualSize =
- IsPODForThePurposeOfLayout ? DataSize : Builder.NonVirtualSize;
-
- const CXXMethodDecl *KeyFunction = GetKeyFunction(cast<CXXRecordDecl>(D));
-
- return new ASTRecordLayout(Builder.Size, Builder.Alignment, DataSize,
- Builder.FieldOffsets.data(),
- Builder.FieldOffsets.size(),
- NonVirtualSize,
- Builder.NonVirtualAlignment,
- Builder.PrimaryBase,
- Builder.Bases.data(),
- Builder.Bases.size(),
- Builder.VBases.data(),
- Builder.VBases.size(),
- KeyFunction);
-}
-
-const ASTRecordLayout *
-ASTRecordLayoutBuilder::ComputeLayout(ASTContext &Ctx,
- const ObjCInterfaceDecl *D,
- const ObjCImplementationDecl *Impl) {
- ASTRecordLayoutBuilder Builder(Ctx);
-
- Builder.Layout(D, Impl);
-
- return new ASTRecordLayout(Builder.Size, Builder.Alignment,
- Builder.DataSize,
- Builder.FieldOffsets.data(),
- Builder.FieldOffsets.size());
-}
diff --git a/lib/AST/RecordLayoutBuilder.h b/lib/AST/RecordLayoutBuilder.h
index 69e0498..d4171d3 100644
--- a/lib/AST/RecordLayoutBuilder.h
+++ b/lib/AST/RecordLayoutBuilder.h
@@ -151,6 +151,7 @@
static const ASTRecordLayout *ComputeLayout(ASTContext &Ctx,
const ObjCInterfaceDecl *D,
const ObjCImplementationDecl *Impl);
+ static const CXXMethodDecl *ComputeKeyFunction(const CXXRecordDecl *RD);
};
} // end namespace clang
diff --git a/lib/CodeGen/CGVtable.cpp b/lib/CodeGen/CGVtable.cpp
index 6fda6a4..d227a5e 100644
--- a/lib/CodeGen/CGVtable.cpp
+++ b/lib/CodeGen/CGVtable.cpp
@@ -1433,10 +1433,8 @@
if (!RD->isDynamicClass())
return;
- const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD);
-
// Get the key function.
- const CXXMethodDecl *KeyFunction = Layout.getKeyFunction();
+ const CXXMethodDecl *KeyFunction = CGM.getContext().getKeyFunction(RD);
if (KeyFunction) {
// We don't have the right key function.
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index 2df172e..1e96bf5 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -5090,8 +5090,12 @@
return;
CXXRecordDecl *RD = MD->getParent();
- const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
- const CXXMethodDecl *KeyFunction = Layout.getKeyFunction();
+
+ // Ignore classes without a vtable.
+ if (!RD->isDynamicClass())
+ return;
+
+ const CXXMethodDecl *KeyFunction = Context.getKeyFunction(RD);
if (!KeyFunction) {
// This record does not have a key function, so we assume that the vtable