diff options
author | Anders Carlsson <andersca@mac.com> | 2010-02-27 16:52:49 +0000 |
---|---|---|
committer | Anders Carlsson <andersca@mac.com> | 2010-02-27 16:52:49 +0000 |
commit | 2ef9d6bbd3ae2cf53318bb8fabc4fa6cc0743aff (patch) | |
tree | 53e53be67571fef3c6b0aa646739cf22a5ee6c2e | |
parent | aeb863c3b4f1b1f38a524d21570c17aa8fd9e9c9 (diff) |
Finish up the changes to this adjustments.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@97328 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | lib/CodeGen/CGVtable.cpp | 139 | ||||
-rw-r--r-- | test/CodeGenCXX/vtable-layout.cpp | 61 |
2 files changed, 163 insertions, 37 deletions
diff --git a/lib/CodeGen/CGVtable.cpp b/lib/CodeGen/CGVtable.cpp index 5a07b43dea..c17334b645 100644 --- a/lib/CodeGen/CGVtable.cpp +++ b/lib/CodeGen/CGVtable.cpp @@ -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)); diff --git a/test/CodeGenCXX/vtable-layout.cpp b/test/CodeGenCXX/vtable-layout.cpp index 84f0132a13..01232c8f1e 100644 --- a/test/CodeGenCXX/vtable-layout.cpp +++ b/test/CodeGenCXX/vtable-layout.cpp @@ -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() {} + +}
\ No newline at end of file |