virtual void Destroy(ASTContext& C);
+ bool isDynamicClass() const {
+ return Polymorphic || NumVBases!=0;
+ }
+
/// setBases - Sets the base classes of this struct or class.
void setBases(ASTContext &C,
CXXBaseSpecifier const * const *Bases, unsigned NumBases);
/// which is the alignment of the object without virtual bases.
uint64_t NonVirtualAlign;
+ /// PrimaryBase - The primary base for our vtable.
+ const CXXRecordDecl *PrimaryBase;
+
/// BaseOffsets - Contains a map from base classes to their offset.
/// FIXME: Does it make sense to store offsets for virtual base classes
/// here?
ASTRecordLayout(uint64_t size, unsigned alignment, uint64_t datasize,
const uint64_t *fieldoffsets, unsigned fieldcount,
uint64_t nonvirtualsize, unsigned nonvirtualalign,
- const CXXRecordDecl **bases, const uint64_t *baseoffsets,
- unsigned basecount)
+ const CXXRecordDecl *PB, const CXXRecordDecl **bases,
+ const uint64_t *baseoffsets, unsigned basecount)
: Size(size), DataSize(datasize), FieldOffsets(0), Alignment(alignment),
FieldCount(fieldcount), CXXInfo(new CXXRecordLayoutInfo) {
if (FieldCount > 0) {
FieldOffsets[i] = fieldoffsets[i];
}
+ CXXInfo->PrimaryBase = PB;
CXXInfo->NonVirtualSize = nonvirtualsize;
CXXInfo->NonVirtualAlign = nonvirtualalign;
for (unsigned i = 0; i != basecount; ++i)
return CXXInfo->NonVirtualAlign;
}
+ /// getPrimaryBase - Get the primary base.
+ const CXXRecordDecl *getPrimaryBase() const {
+ assert(CXXInfo && "Record layout does not have C++ specific info!");
+
+ return CXXInfo->PrimaryBase;
+ }
+
/// getBaseClassOffset - Get the offset, in bits, for the given base class.
uint64_t getBaseClassOffset(const CXXRecordDecl *Base) const {
assert(CXXInfo && "Record layout does not have C++ specific info!");
#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;
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
}
}
+// 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 &&
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.
Builder.FieldOffsets.size(),
NonVirtualSize,
Builder.NonVirtualAlignment,
+ Builder.PrimaryBase,
Builder.Bases.data(),
Builder.BaseOffsets.data(),
Builder.Bases.size());
#define LLVM_CLANG_AST_RECORDLAYOUTBUILDER_H
#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/SmallSet.h"
#include "llvm/Support/DataTypes.h"
namespace clang {
uint64_t NonVirtualSize;
unsigned NonVirtualAlignment;
+ const CXXRecordDecl *PrimaryBase;
+
llvm::SmallVector<const CXXRecordDecl *, 4> Bases;
llvm::SmallVector<uint64_t, 4> BaseOffsets;
void LayoutFields(const RecordDecl *D);
void LayoutField(const FieldDecl *D);
+ void SelectPrimaryBase(const CXXRecordDecl *RD);
+ void SelectPrimaryForBase(const CXXRecordDecl *RD,
+ llvm::SmallSet<const CXXRecordDecl*, 32> &IndirectPrimary);
+ void setPrimaryBase(const CXXRecordDecl *PB) { PrimaryBase = PB; }
+ bool IsNearlyEmpty(const CXXRecordDecl *RD);
void LayoutVtable(const CXXRecordDecl *RD);
void LayoutNonVirtualBases(const CXXRecordDecl *RD);
void LayoutNonVirtualBase(const CXXRecordDecl *RD);
llvm::Type *Ptr8Ty;
Ptr8Ty = llvm::PointerType::get(llvm::Type::Int8Ty, 0);
m = llvm::Constant::getNullValue(Ptr8Ty);
- int64_t offset = 0;
- methods.push_back(m); offset += LLVMPointerWidth;
- methods.push_back(GenerateRtti(RD)); offset += LLVMPointerWidth;
+ int64_t Offset = 0;
+ methods.push_back(m); Offset += LLVMPointerWidth;
+ methods.push_back(GenerateRtti(RD)); Offset += LLVMPointerWidth;
+
+ const ASTRecordLayout &Layout = getContext().getASTRecordLayout(RD);
+ const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase();
for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(),
e = RD->bases_end(); i != e; ++i) {
continue;
const CXXRecordDecl *Base =
cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl());
+ if (PrimaryBase != Base) {
+ const ASTRecordLayout &Layout = getContext().getASTRecordLayout(RD);
+ int64_t BaseOffset = -(Layout.getBaseClassOffset(Base) / 8);
+ m = llvm::ConstantInt::get(llvm::Type::Int64Ty, BaseOffset);
+ m = llvm::ConstantExpr::getIntToPtr(m, Ptr8Ty);
+ methods.push_back(m);
+ // FIXME: GenerateRtti for Base in RD.
+ m = llvm::Constant::getNullValue(Ptr8Ty);
+ methods.push_back(m);
+ }
for (meth_iter mi = Base->method_begin(), me = Base->method_end(); mi != me;
++mi) {
if (mi->isVirtual()) {
methods.push_back(m);
}
}
+ if (PrimaryBase == Base) {
+ for (meth_iter mi = RD->method_begin(), me = RD->method_end(); mi != me;
+ ++mi) {
+ if (mi->isVirtual()) {
+ m = CGM.GetAddrOfFunction(GlobalDecl(*mi));
+ m = llvm::ConstantExpr::getBitCast(m, Ptr8Ty);
+ methods.push_back(m);
+ }
+ }
+ }
}
-
- for (meth_iter mi = RD->method_begin(), me = RD->method_end(); mi != me;
- ++mi) {
- if (mi->isVirtual()) {
- m = CGM.GetAddrOfFunction(GlobalDecl(*mi));
- m = llvm::ConstantExpr::getBitCast(m, Ptr8Ty);
- methods.push_back(m);
+ if (PrimaryBase == 0) {
+ for (meth_iter mi = RD->method_begin(), me = RD->method_end(); mi != me;
+ ++mi) {
+ if (mi->isVirtual()) {
+ m = CGM.GetAddrOfFunction(GlobalDecl(*mi));
+ m = llvm::ConstantExpr::getBitCast(m, Ptr8Ty);
+ methods.push_back(m);
+ }
}
}
+
llvm::Constant *C;
llvm::ArrayType *type = llvm::ArrayType::get(Ptr8Ty, methods.size());
C = llvm::ConstantArray::get(type, methods);
// FIXME: finish layout for virtual bases
vtable = Builder.CreateGEP(vtable,
llvm::ConstantInt::get(llvm::Type::Int64Ty,
- offset/8));
+ Offset/8));
return vtable;
}
virtual void bar1();
virtual void bar2();
};
+void B::bar1() { }
+void B::bar2() { }
+
+struct C {
+ virtual void bee1();
+ virtual void bee2();
+};
+void C::bee1() { }
+void C::bee2() { }
static_assert (sizeof (B) == (sizeof(void *)), "vtable pointer layout");
-class A : public B {
+class A : public B, public C {
public:
virtual void foo1();
virtual void foo2();
A() { }
} *a;
+void A::foo1() { }
+void A::foo2() { }
int main() {
A a;
// CHECK-LP64: .quad __ZN1B4bar2Ev
// CHECK-LP64: .quad __ZN1A4foo1Ev
// CHECK-LP64: .quad __ZN1A4foo2Ev
+// CHECK-LP64: .quad 18446744073709551608
+// CHECK-LP64: .space 8
+// CHECK-LP64: .quad __ZN1C4bee1Ev
+// CHECK-LP64: .quad __ZN1C4bee2Ev
// CHECK-LP32: __ZTV1A:
// CHECK-LP32: .space 4
// CHECK-LP32: .long __ZN1B4bar2Ev
// CHECK-LP32: .long __ZN1A4foo1Ev
// CHECK-LP32: .long __ZN1A4foo2Ev
+// CHECK-LP32: .long 4294967292
+// CHECK-LP32: .space 4
+// CHECK-LP32: .long __ZN1C4bee1Ev
+// CHECK-LP32: .long __ZN1C4bee2Ev