summaryrefslogtreecommitdiffstats
path: root/clang/lib/AST/RecordLayoutBuilder.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib/AST/RecordLayoutBuilder.cpp')
-rw-r--r--clang/lib/AST/RecordLayoutBuilder.cpp120
1 files changed, 112 insertions, 8 deletions
diff --git a/clang/lib/AST/RecordLayoutBuilder.cpp b/clang/lib/AST/RecordLayoutBuilder.cpp
index 901d5a5b26f..10295f18835 100644
--- a/clang/lib/AST/RecordLayoutBuilder.cpp
+++ b/clang/lib/AST/RecordLayoutBuilder.cpp
@@ -16,6 +16,7 @@
#include "clang/AST/Expr.h"
#include "clang/AST/RecordLayout.h"
#include "clang/Basic/TargetInfo.h"
+#include <llvm/ADT/SmallSet.h>
#include <llvm/Support/MathExtras.h>
using namespace clang;
@@ -25,14 +26,17 @@ ASTRecordLayoutBuilder::ASTRecordLayoutBuilder(ASTContext &Ctx)
IsUnion(false), NonVirtualSize(0), NonVirtualAlignment(8) {}
void ASTRecordLayoutBuilder::LayoutVtable(const CXXRecordDecl *RD) {
- if (RD->isPolymorphic() || RD->getNumVBases())
- {
- // assert (RD->getNumBases() == 0 && "no polymorphic inheritance yet");
- int AS = 0;
- UpdateAlignment(Ctx.Target.getPointerAlign(AS));
- Size += Ctx.Target.getPointerWidth(AS);
- NextOffset = Size;
- }
+ // FIXME: audit indirect virtual bases
+ if (!RD->isPolymorphic() && !RD->getNumVBases())
+ return;
+
+ SelectPrimaryBase(RD);
+ if (PrimaryBase == 0) {
+ int AS = 0;
+ UpdateAlignment(Ctx.Target.getPointerAlign(AS));
+ Size += Ctx.Target.getPointerWidth(AS);
+ NextOffset = Size;
+ }
}
void
@@ -47,6 +51,104 @@ ASTRecordLayoutBuilder::LayoutNonVirtualBases(const CXXRecordDecl *RD) {
}
}
+// Helper routines related to the abi definition from:
+// http://www.codesourcery.com/public/cxx-abi/abi.html
+//
+/// IsNearlyEmpty - Indicates when a class has a vtable pointer, but
+/// no other data.
+bool ASTRecordLayoutBuilder::IsNearlyEmpty(const CXXRecordDecl *RD) {
+ // FIXME: Audit the corners
+ if (!RD->isDynamicClass())
+ return false;
+ const ASTRecordLayout &BaseInfo = Ctx.getASTRecordLayout(RD);
+ if (BaseInfo.getNonVirtualSize() == Ctx.Target.getPointerWidth(0))
+ return true;
+ return false;
+}
+
+void ASTRecordLayoutBuilder::SelectPrimaryForBase(const CXXRecordDecl *RD,
+ llvm::SmallSet<const CXXRecordDecl*, 32> &IndirectPrimary) {
+ for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(),
+ e = RD->bases_end(); i != e; ++i) {
+ if (!i->isVirtual()) {
+ const CXXRecordDecl *Base =
+ cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl());
+ // Only bases with virtual bases participate in computing the
+ // indirect primary base classes.
+ // FIXME: audit indirect virtual bases
+ if (Base->getNumVBases() == 0)
+ return;
+ // FIXME: This information is recomputed a whole lot, cache it instead.
+ SelectPrimaryBase(Base);
+ IndirectPrimary.insert(PrimaryBase);
+ SelectPrimaryForBase(Base, IndirectPrimary);
+ }
+ }
+}
+
+/// SelectPrimaryBase - Selects the primary base for the given class and
+/// records that with setPrimaryBase.
+void ASTRecordLayoutBuilder::SelectPrimaryBase(const CXXRecordDecl *RD) {
+ // The primary base is the first non-virtual indirect or direct base class,
+ // if one exists.
+ for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(),
+ e = RD->bases_end(); i != e; ++i) {
+ if (!i->isVirtual()) {
+ const CXXRecordDecl *Base =
+ cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl());
+ if (Base->isDynamicClass()) {
+ setPrimaryBase(Base);
+ return;
+ }
+ }
+ }
+
+ // Otherwise, it is the first nearly empty virtual base that is not an
+ // indirect primary base class, if one exists.
+
+ // If we have no virtual bases at this point, bail out as the searching below
+ // is expensive.
+ // FIXME: audit indirect virtual bases
+ if (RD->getNumVBases() == 0) {
+ setPrimaryBase(0);
+ return;
+ }
+
+ // First, we compute all the primary bases for all of out direct and indirect
+ // non-virtual bases, and record all their primary base classes.
+ const CXXRecordDecl *FirstPrimary = 0;
+ llvm::SmallSet<const CXXRecordDecl*, 32> IndirectPrimary;
+ for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(),
+ e = RD->bases_end(); i != e; ++i) {
+ if (!i->isVirtual()) {
+ const CXXRecordDecl *Base =
+ cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl());
+ SelectPrimaryForBase(Base, IndirectPrimary);
+ }
+ }
+
+ // Then we can search for the first nearly empty virtual base itself.
+ // FIXME: audit indirect virtual bases
+ for (CXXRecordDecl::base_class_const_iterator i = RD->vbases_begin(),
+ e = RD->vbases_end(); i != e; ++i) {
+ const CXXRecordDecl *Base =
+ cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl());
+ if (IsNearlyEmpty(Base)) {
+ if (FirstPrimary==0)
+ FirstPrimary = Base;
+ if (!IndirectPrimary.count(Base)) {
+ setPrimaryBase(Base);
+ return;
+ }
+ }
+ }
+
+ // Otherwise if is the first nearly empty base, if one exists, otherwise
+ // there is no primary base class.
+ setPrimaryBase(FirstPrimary);
+ return;
+}
+
void ASTRecordLayoutBuilder::LayoutNonVirtualBase(const CXXRecordDecl *RD) {
const ASTRecordLayout &BaseInfo = Ctx.getASTRecordLayout(RD);
assert(BaseInfo.getDataSize() > 0 &&
@@ -86,6 +188,7 @@ void ASTRecordLayoutBuilder::Layout(const RecordDecl *D) {
LayoutVtable(RD);
LayoutNonVirtualBases(RD);
+ // FIXME: audit indirect virtual bases
assert (RD->getNumVBases() == 0
&& "FIXME: We don't support virtual bases yet!");
// FIXME: We need to layout the virtual bases in the complete object layout.
@@ -277,6 +380,7 @@ ASTRecordLayoutBuilder::ComputeLayout(ASTContext &Ctx,
Builder.FieldOffsets.size(),
NonVirtualSize,
Builder.NonVirtualAlignment,
+ Builder.PrimaryBase,
Builder.Bases.data(),
Builder.BaseOffsets.data(),
Builder.Bases.size());
OpenPOWER on IntegriCloud