зеркало из https://github.com/microsoft/clang.git
Finish up the changes to this adjustments.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@97328 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Родитель
aeb863c3b4
Коммит
2ef9d6bbd3
|
@ -1159,6 +1159,8 @@ private:
|
|||
|
||||
MethodInfo(uint64_t BaseOffset, uint64_t VtableIndex)
|
||||
: BaseOffset(BaseOffset), VtableIndex(VtableIndex) { }
|
||||
|
||||
MethodInfo() : BaseOffset(0), VtableIndex(0) { }
|
||||
};
|
||||
|
||||
typedef llvm::DenseMap<const CXXMethodDecl *, MethodInfo> MethodInfoMapTy;
|
||||
|
@ -1186,6 +1188,10 @@ private:
|
|||
llvm::SmallVector<std::pair<uint64_t, ThisAdjustment>, 16>
|
||||
ThisAdjustments;
|
||||
|
||||
/// ComputeThisAdjustments - Compute the 'this' pointer adjustments for the
|
||||
/// part of the vtable we're currently building.
|
||||
void ComputeThisAdjustments();
|
||||
|
||||
typedef llvm::SmallPtrSet<const CXXRecordDecl *, 4> VisitedVirtualBasesSetTy;
|
||||
|
||||
/// PrimaryVirtualBases - All known virtual bases who are a primary base of
|
||||
|
@ -1204,8 +1210,7 @@ private:
|
|||
|
||||
/// AddMethod - Add a single virtual member function to the vtable
|
||||
/// components vector.
|
||||
void AddMethod(const CXXMethodDecl *MD, ReturnAdjustment ReturnAdjustment,
|
||||
ThisAdjustment ThisAdjustment);
|
||||
void AddMethod(const CXXMethodDecl *MD, ReturnAdjustment ReturnAdjustment);
|
||||
|
||||
/// IsOverriderUsed - Returns whether the overrider will ever be used in this
|
||||
/// part of the vtable.
|
||||
|
@ -1290,6 +1295,50 @@ OverridesMethodInBases(const CXXMethodDecl *MD,
|
|||
return 0;
|
||||
}
|
||||
|
||||
void VtableBuilder::ComputeThisAdjustments() {
|
||||
// Now go through the method info map and see if any of the methods need
|
||||
// 'this' pointer adjustments.
|
||||
for (MethodInfoMapTy::const_iterator I = MethodInfoMap.begin(),
|
||||
E = MethodInfoMap.end(); I != E; ++I) {
|
||||
const CXXMethodDecl *MD = I->first;
|
||||
const MethodInfo &MethodInfo = I->second;
|
||||
|
||||
BaseSubobject OverriddenBaseSubobject(MD->getParent(),
|
||||
MethodInfo.BaseOffset);
|
||||
|
||||
// Get the final overrider for this method.
|
||||
FinalOverriders::OverriderInfo Overrider =
|
||||
Overriders.getOverrider(OverriddenBaseSubobject, MD);
|
||||
|
||||
// Check if we need an adjustment.
|
||||
if (Overrider.BaseOffset == MethodInfo.BaseOffset)
|
||||
continue;
|
||||
|
||||
BaseSubobject OverriderBaseSubobject(Overrider.Method->getParent(),
|
||||
Overrider.BaseOffset);
|
||||
|
||||
// Compute the adjustment offset.
|
||||
BaseOffset ThisAdjustmentOffset =
|
||||
Overriders.ComputeThisAdjustmentBaseOffset(OverriddenBaseSubobject,
|
||||
OverriderBaseSubobject);
|
||||
|
||||
// Then compute the adjustment itself.
|
||||
ThisAdjustment ThisAdjustment = ComputeThisAdjustment(Overrider.Method,
|
||||
ThisAdjustmentOffset);
|
||||
|
||||
ThisAdjustments.push_back(std::make_pair(MethodInfo.VtableIndex,
|
||||
ThisAdjustment));
|
||||
if (isa<CXXDestructorDecl>(MD)) {
|
||||
// Add an adjustment for the deleting destructor as well.
|
||||
ThisAdjustments.push_back(std::make_pair(MethodInfo.VtableIndex + 1,
|
||||
ThisAdjustment));
|
||||
}
|
||||
}
|
||||
|
||||
/// Clear the method info map.
|
||||
MethodInfoMap.clear();
|
||||
}
|
||||
|
||||
VtableBuilder::ReturnAdjustment
|
||||
VtableBuilder::ComputeReturnAdjustment(BaseOffset Offset) {
|
||||
ReturnAdjustment Adjustment;
|
||||
|
@ -1343,18 +1392,10 @@ VtableBuilder::ComputeThisAdjustment(const CXXMethodDecl *MD,
|
|||
|
||||
void
|
||||
VtableBuilder::AddMethod(const CXXMethodDecl *MD,
|
||||
ReturnAdjustment ReturnAdjustment,
|
||||
ThisAdjustment ThisAdjustment) {
|
||||
ReturnAdjustment ReturnAdjustment) {
|
||||
if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(MD)) {
|
||||
assert(ReturnAdjustment.isEmpty() &&
|
||||
"Destructor can't have return adjustment!");
|
||||
// Add the 'this' pointer adjustments if necessary.
|
||||
if (!ThisAdjustment.isEmpty()) {
|
||||
ThisAdjustments.push_back(std::make_pair(Components.size(),
|
||||
ThisAdjustment));
|
||||
ThisAdjustments.push_back(std::make_pair(Components.size() + 1,
|
||||
ThisAdjustment));
|
||||
}
|
||||
|
||||
// Add both the complete destructor and the deleting destructor.
|
||||
Components.push_back(VtableComponent::MakeCompleteDtor(DD));
|
||||
|
@ -1365,11 +1406,6 @@ VtableBuilder::AddMethod(const CXXMethodDecl *MD,
|
|||
ReturnAdjustments.push_back(std::make_pair(Components.size(),
|
||||
ReturnAdjustment));
|
||||
|
||||
// Add the 'this' pointer adjustment if necessary.
|
||||
if (!ThisAdjustment.isEmpty())
|
||||
ThisAdjustments.push_back(std::make_pair(Components.size(),
|
||||
ThisAdjustment));
|
||||
|
||||
// Add the function.
|
||||
Components.push_back(VtableComponent::MakeFunction(MD));
|
||||
}
|
||||
|
@ -1464,6 +1500,28 @@ VtableBuilder::IsOverriderUsed(BaseSubobject Base,
|
|||
return OverridesIndirectMethodInBases(Overrider.Method, PrimaryBases);
|
||||
}
|
||||
|
||||
/// FindNearestOverriddenMethod - Given a method, returns the overridden method
|
||||
/// from the nearest base. Returns null if no method was found.
|
||||
static const CXXMethodDecl *
|
||||
FindNearestOverriddenMethod(const CXXMethodDecl *MD,
|
||||
VtableBuilder::PrimaryBasesSetVectorTy &Bases) {
|
||||
for (int I = Bases.size(), E = 0; I != E; --I) {
|
||||
const CXXRecordDecl *PrimaryBase = Bases[I - 1];
|
||||
|
||||
// Now check the overriden methods.
|
||||
for (CXXMethodDecl::method_iterator I = MD->begin_overridden_methods(),
|
||||
E = MD->end_overridden_methods(); I != E; ++I) {
|
||||
const CXXMethodDecl *OverriddenMD = *I;
|
||||
|
||||
// We found our overridden method.
|
||||
if (OverriddenMD->getParent() == PrimaryBase)
|
||||
return OverriddenMD;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
VtableBuilder::AddMethods(BaseSubobject Base,
|
||||
BaseSubobject FirstBaseInPrimaryBaseChain,
|
||||
|
@ -1512,10 +1570,25 @@ VtableBuilder::AddMethods(BaseSubobject Base,
|
|||
// base. If this is the case, and the return type doesn't require adjustment
|
||||
// then we can just use the member function from the primary base.
|
||||
if (const CXXMethodDecl *OverriddenMD =
|
||||
OverridesMethodInBases(MD, PrimaryBases)) {
|
||||
FindNearestOverriddenMethod(MD, PrimaryBases)) {
|
||||
if (ComputeReturnAdjustmentBaseOffset(Context, MD,
|
||||
OverriddenMD).isEmpty())
|
||||
OverriddenMD).isEmpty()) {
|
||||
// Replace the method info of the overridden method with our own
|
||||
// method.
|
||||
assert(MethodInfoMap.count(OverriddenMD) &&
|
||||
"Did not find the overridden method!");
|
||||
MethodInfo &OverriddenMethodInfo = MethodInfoMap[OverriddenMD];
|
||||
|
||||
MethodInfo MethodInfo(Base.getBaseOffset(),
|
||||
OverriddenMethodInfo.VtableIndex);
|
||||
|
||||
assert(!MethodInfoMap.count(MD) &&
|
||||
"Should not have method info for this method yet!");
|
||||
|
||||
MethodInfoMap.insert(std::make_pair(MD, MethodInfo));
|
||||
MethodInfoMap.erase(OverriddenMD);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Check if this overrider is going to be used.
|
||||
|
@ -1524,6 +1597,13 @@ VtableBuilder::AddMethods(BaseSubobject Base,
|
|||
Components.push_back(VtableComponent::MakeUnusedFunction(OverriderMD));
|
||||
continue;
|
||||
}
|
||||
|
||||
// Insert the method info for this method.
|
||||
MethodInfo MethodInfo(Base.getBaseOffset(), Components.size());
|
||||
|
||||
assert(!MethodInfoMap.count(MD) &&
|
||||
"Should not have method info for this method yet!");
|
||||
MethodInfoMap.insert(std::make_pair(MD, MethodInfo));
|
||||
|
||||
// Check if this overrider needs a return adjustment.
|
||||
BaseOffset ReturnAdjustmentOffset =
|
||||
|
@ -1532,25 +1612,7 @@ VtableBuilder::AddMethods(BaseSubobject Base,
|
|||
ReturnAdjustment ReturnAdjustment =
|
||||
ComputeReturnAdjustment(ReturnAdjustmentOffset);
|
||||
|
||||
ThisAdjustment ThisAdjustment;
|
||||
|
||||
// Check if this overrider needs a 'this' pointer adjustment.
|
||||
// (We use the base offset of the first base in the primary base chain here,
|
||||
// because Base will not have the right offset if it is a primary virtual
|
||||
// base that is not a primary base in the complete class.
|
||||
if (FirstBaseInPrimaryBaseChain.getBaseOffset() != Overrider.BaseOffset) {
|
||||
BaseSubobject OverriderBaseSubobject(Overrider.Method->getParent(),
|
||||
Overrider.BaseOffset);
|
||||
|
||||
BaseOffset ThisAdjustmentOffset =
|
||||
Overriders.ComputeThisAdjustmentBaseOffset(FirstBaseInPrimaryBaseChain,
|
||||
OverriderBaseSubobject);
|
||||
|
||||
ThisAdjustment = ComputeThisAdjustment(Overrider.Method,
|
||||
ThisAdjustmentOffset);
|
||||
}
|
||||
|
||||
AddMethod(Overrider.Method, ReturnAdjustment, ThisAdjustment);
|
||||
AddMethod(Overrider.Method, ReturnAdjustment);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1599,6 +1661,9 @@ void VtableBuilder::LayoutPrimaryAndAndSecondaryVtables(BaseSubobject Base,
|
|||
PrimaryBasesSetVectorTy PrimaryBases;
|
||||
AddMethods(Base, Base, PrimaryBases);
|
||||
|
||||
// Compute 'this' pointer adjustments.
|
||||
ComputeThisAdjustments();
|
||||
|
||||
// Record the address point.
|
||||
AddressPoints.insert(std::make_pair(Base, AddressPoint));
|
||||
|
||||
|
|
|
@ -645,3 +645,64 @@ class E : virtual D {
|
|||
void E::f() {}
|
||||
|
||||
}
|
||||
|
||||
namespace Test18 {
|
||||
|
||||
// Test that we compute the right 'this' adjustment offsets.
|
||||
|
||||
struct A {
|
||||
virtual void f();
|
||||
virtual void g();
|
||||
};
|
||||
|
||||
struct B : virtual A {
|
||||
virtual void f();
|
||||
};
|
||||
|
||||
struct C : A, B {
|
||||
virtual void g();
|
||||
};
|
||||
|
||||
// CHECK: Vtable for 'Test18::D' (24 entries).
|
||||
// CHECK-NEXT: 0 | vbase_offset (8)
|
||||
// CHECK-NEXT: 1 | vbase_offset (0)
|
||||
// CHECK-NEXT: 2 | vbase_offset (0)
|
||||
// CHECK-NEXT: 3 | vcall_offset (8)
|
||||
// CHECK-NEXT: 4 | vcall_offset (0)
|
||||
// CHECK-NEXT: 5 | offset_to_top (0)
|
||||
// CHECK-NEXT: 6 | Test18::D RTTI
|
||||
// CHECK-NEXT: -- (Test18::A, 0) vtable address --
|
||||
// CHECK-NEXT: -- (Test18::B, 0) vtable address --
|
||||
// CHECK-NEXT: -- (Test18::D, 0) vtable address --
|
||||
// CHECK-NEXT: 7 | void Test18::D::f()
|
||||
// CHECK-NEXT: 8 | void Test18::C::g()
|
||||
// CHECK-NEXT: [this adjustment: 0 non-virtual, -32 vcall offset offset]
|
||||
// CHECK-NEXT: 9 | void Test18::D::h()
|
||||
// CHECK-NEXT: 10 | vcall_offset (0)
|
||||
// CHECK-NEXT: 11 | vcall_offset (-8)
|
||||
// CHECK-NEXT: 12 | vbase_offset (-8)
|
||||
// CHECK-NEXT: 13 | offset_to_top (-8)
|
||||
// CHECK-NEXT: 14 | Test18::D RTTI
|
||||
// CHECK-NEXT: -- (Test18::A, 8) vtable address --
|
||||
// CHECK-NEXT: -- (Test18::C, 8) vtable address --
|
||||
// CHECK-NEXT: 15 | void Test18::D::f()
|
||||
// CHECK-NEXT: [this adjustment: 0 non-virtual, -32 vcall offset offset]
|
||||
// CHECK-NEXT: 16 | void Test18::C::g()
|
||||
// CHECK-NEXT: 17 | vbase_offset (-16)
|
||||
// CHECK-NEXT: 18 | vcall_offset (-8)
|
||||
// CHECK-NEXT: 19 | vcall_offset (-16)
|
||||
// CHECK-NEXT: 20 | offset_to_top (-16)
|
||||
// CHECK-NEXT: 21 | Test18::D RTTI
|
||||
// CHECK-NEXT: -- (Test18::A, 16) vtable address --
|
||||
// CHECK-NEXT: -- (Test18::B, 16) vtable address --
|
||||
// CHECK-NEXT: 22 | void Test18::D::f()
|
||||
// CHECK-NEXT: [this adjustment: -8 non-virtual, -32 vcall offset offset]
|
||||
// CHECK-NEXT: 23 | [unused] void Test18::C::g()
|
||||
struct D : virtual B, virtual C, virtual A
|
||||
{
|
||||
virtual void f();
|
||||
virtual void h();
|
||||
};
|
||||
void D::f() {}
|
||||
|
||||
}
|
Загрузка…
Ссылка в новой задаче