MethodInfo(uint64_t BaseOffset, uint64_t VtableIndex)
: BaseOffset(BaseOffset), VtableIndex(VtableIndex) { }
+
+ MethodInfo() : BaseOffset(0), VtableIndex(0) { }
};
typedef llvm::DenseMap<const CXXMethodDecl *, MethodInfo> MethodInfoMapTy;
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
/// 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.
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;
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));
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));
}
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,
// 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.
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 =
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);
}
}
PrimaryBasesSetVectorTy PrimaryBases;
AddMethods(Base, Base, PrimaryBases);
+ // Compute 'this' pointer adjustments.
+ ComputeThisAdjustments();
+
// Record the address point.
AddressPoints.insert(std::make_pair(Base, AddressPoint));
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() {}
+
+}
\ No newline at end of file