]> granicus.if.org Git - clang/commitdiff
MS ABI: Include the vfptr offset in memptrs to virtual methods
authorReid Kleckner <reid@kleckner.net>
Fri, 21 Feb 2014 02:27:32 +0000 (02:27 +0000)
committerReid Kleckner <reid@kleckner.net>
Fri, 21 Feb 2014 02:27:32 +0000 (02:27 +0000)
Virtual methods expect 'this' to point to the vfptr containing the
virtual method, and this extends to virtual member pointer thunks.  The
relevant vfptr is always at offset zero on entry to the thunk, and no
this adjustment is needed.

Previously we would not include the vfptr adjustment in the member
pointer, and we'd look at the vfptr offset when loading from the vftable
in the thunk.

Fixes PR18917.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@201835 91177308-0d34-0410-b5e6-96231b3b80d8

lib/CodeGen/MicrosoftCXXABI.cpp
test/CodeGenCXX/microsoft-abi-member-pointers.cpp

index 57ad9fb1ad9c712da6c0184fe29e6df70dae8f59..7e3cf4f200061b3ccb6582638434d1f3f103faba 100644 (file)
@@ -328,8 +328,9 @@ private:
   const VBTableGlobals &enumerateVBTables(const CXXRecordDecl *RD);
 
   /// \brief Generate a thunk for calling a virtual member function MD.
-  llvm::Function *EmitVirtualMemPtrThunk(const CXXMethodDecl *MD,
-                                         StringRef ThunkName);
+  llvm::Function *EmitVirtualMemPtrThunk(
+      const CXXMethodDecl *MD,
+      const MicrosoftVTableContext::MethodVFTableLocation &ML);
 
 public:
   virtual llvm::Type *ConvertMemberPointerType(const MemberPointerType *MPT);
@@ -1015,9 +1016,15 @@ MicrosoftCXXABI::enumerateVBTables(const CXXRecordDecl *RD) {
   return VBGlobals;
 }
 
-llvm::Function *
-MicrosoftCXXABI::EmitVirtualMemPtrThunk(const CXXMethodDecl *MD,
-                                        StringRef ThunkName) {
+llvm::Function *MicrosoftCXXABI::EmitVirtualMemPtrThunk(
+    const CXXMethodDecl *MD,
+    const MicrosoftVTableContext::MethodVFTableLocation &ML) {
+  // Calculate the mangled name.
+  SmallString<256> ThunkName;
+  llvm::raw_svector_ostream Out(ThunkName);
+  getMangleContext().mangleVirtualMemPtrThunk(MD, Out);
+  Out.flush();
+
   // If the thunk has been generated previously, just return it.
   if (llvm::GlobalValue *GV = CGM.getModule().getNamedValue(ThunkName))
     return cast<llvm::Function>(GV);
@@ -1041,9 +1048,14 @@ MicrosoftCXXABI::EmitVirtualMemPtrThunk(const CXXMethodDecl *MD,
   CodeGenFunction CGF(CGM);
   CGF.StartThunk(ThunkFn, MD, FnInfo);
 
-  // Get to the Callee.
+  // Load the vfptr and then callee from the vftable.  The callee should have
+  // adjusted 'this' so that the vfptr is at offset zero.
   llvm::Value *This = CGF.LoadCXXThis();
-  llvm::Value *Callee = getVirtualFunctionPointer(CGF, MD, This, ThunkTy);
+  llvm::Value *VTable =
+      CGF.GetVTablePtr(This, ThunkTy->getPointerTo()->getPointerTo());
+  llvm::Value *VFuncPtr =
+      CGF.Builder.CreateConstInBoundsGEP1_64(VTable, ML.Index, "vfn");
+  llvm::Value *Callee = CGF.Builder.CreateLoad(VFuncPtr);
 
   // Make the call and return the result.
   CGF.EmitCallAndReturnForThunk(MD, Callee, 0);
@@ -1523,13 +1535,10 @@ MicrosoftCXXABI::BuildMemberPointer(const CXXRecordDecl *RD,
                                "member function in virtual base class");
       FirstField = llvm::Constant::getNullValue(CGM.VoidPtrTy);
     } else {
-      SmallString<256> ThunkName;
-      llvm::raw_svector_ostream Out(ThunkName);
-      getMangleContext().mangleVirtualMemPtrThunk(MD, Out);
-      Out.flush();
-
-      llvm::Function *Thunk = EmitVirtualMemPtrThunk(MD, ThunkName.str());
+      llvm::Function *Thunk = EmitVirtualMemPtrThunk(MD, ML);
       FirstField = llvm::ConstantExpr::getBitCast(Thunk, CGM.VoidPtrTy);
+      // Include the vfptr adjustment if the method is in a non-primary vftable.
+      NonVirtualBaseAdjustment += ML.VFPtrOffset;
     }
   }
 
index dd526490c12a4ca2a212e7f37d8ec2c05fe34981..8d9a848cbcd5cb8a869a7d08c6a0e2b8d59b4131 100644 (file)
@@ -560,6 +560,29 @@ int *load_data(A *a, int A::*mp) {
 }
 
 }
+
+namespace Test4 {
+
+struct A        { virtual void f(); };
+struct B        { virtual void g(); };
+struct C : A, B { virtual void g(); };
+
+void (C::*getmp())() {
+  return &C::g;
+}
+// CHECK-LABEL: define i64 @"\01?getmp@Test4@@YAP8C@1@AEXXZXZ"()
+// CHECK: store { i8*, i32 } { i8* bitcast (void (i8*)* @"\01??_9C@Test4@@$BA@AE" to i8*), i32 4 }, { i8*, i32 }* %{{.*}}
+//
+
+// CHECK-LABEL: define linkonce_odr x86_thiscallcc void @"\01??_9C@Test4@@$BA@AE"(i8*)
+// CHECK-NOT:  getelementptr
+// CHECK:  load void (i8*)*** %{{.*}}
+// CHECK:  getelementptr inbounds void (i8*)** %{{.*}}, i64 0
+// CHECK-NOT:  getelementptr
+// CHECK:  call x86_thiscallcc void %
+
+}
+
 #else
 struct __virtual_inheritance A;
 #ifdef MEMFUN