]> granicus.if.org Git - clang/commitdiff
Finish up the changes to this adjustments.
authorAnders Carlsson <andersca@mac.com>
Sat, 27 Feb 2010 16:52:49 +0000 (16:52 +0000)
committerAnders Carlsson <andersca@mac.com>
Sat, 27 Feb 2010 16:52:49 +0000 (16:52 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@97328 91177308-0d34-0410-b5e6-96231b3b80d8

lib/CodeGen/CGVtable.cpp
test/CodeGenCXX/vtable-layout.cpp

index 5a07b43deae4a7bb1e9010fc8092638dec884922..c17334b645c3c402d516d8d3a8ac6e6fe605a97d 100644 (file)
@@ -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));
   
index 84f0132a137bad9bbe4c55438b059e9cec371127..01232c8f1e48695642f62d6cdfaba8ef340173fe 100644 (file)
@@ -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