Improve support for non-virtual 'this' pointer adjustments. With this, it should be possible to use the new vtable layout code for all class hierarchies that do not involve virtual bases.

llvm-svn: 96137
This commit is contained in:
Anders Carlsson 2010-02-14 00:16:19 +00:00
parent d3adb0ced9
commit 258a1e35e8
2 changed files with 83 additions and 28 deletions

View File

@ -136,9 +136,9 @@ private:
SubobjectOffsetsMapTy &Offsets);
/// ComputeThisAdjustmentBaseOffset - Compute the base offset for adjusting
/// the 'this' pointer from BaseRD to DerivedRD.
BaseOffset ComputeThisAdjustmentBaseOffset(const CXXRecordDecl *BaseRD,
const CXXRecordDecl *DerivedRD);
/// the 'this' pointer from the base subobject to the derived subobject.
BaseOffset ComputeThisAdjustmentBaseOffset(BaseSubobject BaseSubobject,
BaseSubobject Derived);
static void MergeSubobjectOffsets(const SubobjectOffsetsMapTy &NewOffsets,
SubobjectOffsetsMapTy &Offsets);
@ -229,22 +229,11 @@ void FinalOverriders::AddOverriders(BaseSubobject Base,
}
}
static FinalOverriders::BaseOffset
ComputeBaseOffset(ASTContext &Context, const CXXRecordDecl *BaseRD,
const CXXRecordDecl *DerivedRD) {
CXXBasePaths Paths(/*FindAmbiguities=*/false,
/*RecordPaths=*/true, /*DetectVirtual=*/false);
if (!const_cast<CXXRecordDecl *>(DerivedRD)->
isDerivedFrom(const_cast<CXXRecordDecl *>(BaseRD), Paths)) {
assert(false && "Class must be derived from the passed in base class!");
return FinalOverriders::BaseOffset();
}
static FinalOverriders::BaseOffset
ComputeBaseOffset(ASTContext &Context, const CXXRecordDecl *DerivedRD,
const CXXBasePath &Path) {
int64_t NonVirtualOffset = 0;
const CXXBasePath &Path = Paths.front();
unsigned NonVirtualStart = 0;
const CXXRecordDecl *VirtualBase = 0;
@ -280,6 +269,22 @@ ComputeBaseOffset(ASTContext &Context, const CXXRecordDecl *BaseRD,
// CharUnits.
return FinalOverriders::BaseOffset(DerivedRD, VirtualBase,
NonVirtualOffset / 8);
}
static FinalOverriders::BaseOffset
ComputeBaseOffset(ASTContext &Context, const CXXRecordDecl *BaseRD,
const CXXRecordDecl *DerivedRD) {
CXXBasePaths Paths(/*FindAmbiguities=*/false,
/*RecordPaths=*/true, /*DetectVirtual=*/false);
if (!const_cast<CXXRecordDecl *>(DerivedRD)->
isDerivedFrom(const_cast<CXXRecordDecl *>(BaseRD), Paths)) {
assert(false && "Class must be derived from the passed in base class!");
return FinalOverriders::BaseOffset();
}
return ComputeBaseOffset(Context, DerivedRD, Paths.front());
}
static FinalOverriders::BaseOffset
@ -337,9 +342,12 @@ ComputeReturnAdjustmentBaseOffset(ASTContext &Context,
}
FinalOverriders::BaseOffset
FinalOverriders::ComputeThisAdjustmentBaseOffset(const CXXRecordDecl *BaseRD,
const CXXRecordDecl *DerivedRD) {
CXXBasePaths Paths(/*FindAmbiguities=*/false,
FinalOverriders::ComputeThisAdjustmentBaseOffset(BaseSubobject Base,
BaseSubobject Derived) {
const CXXRecordDecl *BaseRD = Base.getBase();
const CXXRecordDecl *DerivedRD = Derived.getBase();
CXXBasePaths Paths(/*FindAmbiguities=*/true,
/*RecordPaths=*/true, /*DetectVirtual=*/true);
if (!const_cast<CXXRecordDecl *>(DerivedRD)->
@ -350,10 +358,15 @@ FinalOverriders::ComputeThisAdjustmentBaseOffset(const CXXRecordDecl *BaseRD,
assert(!Paths.getDetectedVirtual() && "FIXME: Handle virtual bases!");
// FIXME: We need to go through all paths here, just not the first one.
BaseOffset Offset = ComputeBaseOffset(Context, BaseRD, DerivedRD);
BaseOffset Offset;
// FIXME: This is not going to be enough with virtual bases.
// FIXME: We should not use / 8 here.
int64_t DerivedToBaseOffset =
(Base.getBaseOffset() - Derived.getBaseOffset()) / 8;
Offset.NonVirtualOffset = -DerivedToBaseOffset;
Offset.NonVirtualOffset = -Offset.NonVirtualOffset;
return Offset;
}
@ -380,8 +393,9 @@ void FinalOverriders::PropagateOverrider(const CXXMethodDecl *OldMD,
for (unsigned I = 0, E = OffsetVector.size(); I != E; ++I) {
uint64_t Offset = OffsetVector[I];
BaseSubobject OverriddenSubobject = BaseSubobject(OverriddenRD, Offset);
BaseSubobjectMethodPairTy SubobjectAndMethod =
std::make_pair(BaseSubobject(OverriddenRD, Offset), OverriddenMD);
std::make_pair(OverriddenSubobject, OverriddenMD);
OverriderInfo &Overrider = OverridersMap[SubobjectAndMethod];
@ -402,8 +416,8 @@ void FinalOverriders::PropagateOverrider(const CXXMethodDecl *OldMD,
// Check if we need a 'this' adjustment base offset as well.
if (Offset != NewBase.getBaseOffset()) {
BaseOffset ThisBaseOffset =
ComputeThisAdjustmentBaseOffset(OverriddenMD->getParent(),
NewMD->getParent());
ComputeThisAdjustmentBaseOffset(OverriddenSubobject,
NewBase);
assert(!ThisBaseOffset.isEmpty() &&
"Should not get an empty 'this' adjustment!");
@ -921,7 +935,7 @@ void VtableBuilder::layoutVtable(BaseSubobject Base) {
// First, add the offset to top.
// FIXME: This is not going to be right for construction vtables.
// FIXME: We should not use -8 here.
// FIXME: We should not use / 8 here.
int64_t OffsetToTop = -(int64_t)Base.getBaseOffset() / 8;
Components.push_back(VtableComponent::MakeOffsetToTop(OffsetToTop));

View File

@ -279,4 +279,45 @@ struct C : A1, A2 {
};
void C::f() { }
}
}
namespace Test7 {
// Test that the D::f overrider for A::f have different 'this' pointer
// adjustments in the two A base subobjects.
struct A {
virtual void f();
int a;
};
struct B1 : A { };
struct B2 : A { };
struct C { virtual void c(); };
// CHECK: Vtable for 'Test7::D' (10 entries).
// CHECK-NEXT: 0 | offset_to_top (0)
// CHECK-NEXT: 1 | Test7::D RTTI
// CHECK-NEXT: -- (Test7::C, 0) vtable address --
// CHECK-NEXT: -- (Test7::D, 0) vtable address --
// CHECK-NEXT: 2 | void Test7::C::c()
// CHECK-NEXT: 3 | void Test7::D::f()
// CHECK-NEXT: 4 | offset_to_top (-8)
// CHECK-NEXT: 5 | Test7::D RTTI
// CHECK-NEXT: -- (Test7::A, 8) vtable address --
// CHECK-NEXT: -- (Test7::B1, 8) vtable address --
// CHECK-NEXT: 6 | void Test7::D::f()
// CHECK-NEXT: [this adjustment: -8 non-virtual]
// CHECK-NEXT: 7 | offset_to_top (-24)
// CHECK-NEXT: 8 | Test7::D RTTI
// CHECK-NEXT: -- (Test7::A, 24) vtable address --
// CHECK-NEXT: -- (Test7::B2, 24) vtable address --
// CHECK-NEXT: 9 | void Test7::D::f()
// CHECK-NEXT: [this adjustment: -24 non-virtual]
struct D : C, B1, B2 {
virtual void f();
};
void D::f() { }
}