diff options
author | Timur Iskhodzhanov <timurrrr@google.com> | 2013-11-06 06:24:31 +0000 |
---|---|---|
committer | Timur Iskhodzhanov <timurrrr@google.com> | 2013-11-06 06:24:31 +0000 |
commit | 053142a90d700c21e491444d6996bb1ff80fa0e2 (patch) | |
tree | 2e96d9574c342b5d807cbb69c39b23e6df2f9bb8 /clang/lib | |
parent | 67b277c34fc517ea9f17e5505d9c420485224239 (diff) | |
download | bcm5719-llvm-053142a90d700c21e491444d6996bb1ff80fa0e2.tar.gz bcm5719-llvm-053142a90d700c21e491444d6996bb1ff80fa0e2.zip |
Fix PR17738 - add support for vtordisp thunks when using -cxx-abi microsoft
llvm-svn: 194132
Diffstat (limited to 'clang/lib')
-rw-r--r-- | clang/lib/AST/ItaniumMangle.cpp | 7 | ||||
-rw-r--r-- | clang/lib/AST/MicrosoftMangle.cpp | 71 | ||||
-rw-r--r-- | clang/lib/AST/VTableBuilder.cpp | 109 | ||||
-rw-r--r-- | clang/lib/CodeGen/ItaniumCXXABI.cpp | 3 | ||||
-rw-r--r-- | clang/lib/CodeGen/MicrosoftCXXABI.cpp | 25 |
5 files changed, 171 insertions, 44 deletions
diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp index 953bff20ad6..3d0e7253d76 100644 --- a/clang/lib/AST/ItaniumMangle.cpp +++ b/clang/lib/AST/ItaniumMangle.cpp @@ -3657,8 +3657,9 @@ void ItaniumMangleContextImpl::mangleThunk(const CXXMethodDecl *MD, Mangler.getStream() << 'c'; // Mangle the 'this' pointer adjustment. - Mangler.mangleCallOffset(Thunk.This.NonVirtual, Thunk.This.VCallOffsetOffset); - + Mangler.mangleCallOffset(Thunk.This.NonVirtual, + Thunk.This.Virtual.Itanium.VCallOffsetOffset); + // Mangle the return pointer adjustment if there is one. if (!Thunk.Return.isEmpty()) Mangler.mangleCallOffset(Thunk.Return.NonVirtual, @@ -3677,7 +3678,7 @@ void ItaniumMangleContextImpl::mangleCXXDtorThunk( // Mangle the 'this' pointer adjustment. Mangler.mangleCallOffset(ThisAdjustment.NonVirtual, - ThisAdjustment.VCallOffsetOffset); + ThisAdjustment.Virtual.Itanium.VCallOffsetOffset); Mangler.mangleFunctionEncoding(DD); } diff --git a/clang/lib/AST/MicrosoftMangle.cpp b/clang/lib/AST/MicrosoftMangle.cpp index 08d1eb07a32..c36c16745c0 100644 --- a/clang/lib/AST/MicrosoftMangle.cpp +++ b/clang/lib/AST/MicrosoftMangle.cpp @@ -121,7 +121,7 @@ public: void mangleDeclaration(const NamedDecl *ND); void mangleFunctionEncoding(const FunctionDecl *FD); void mangleVariableEncoding(const VarDecl *VD); - void mangleNumber(int64_t Number); + void mangleNumber(uint32_t Number); void mangleNumber(const llvm::APSInt &Value); void mangleType(QualType T, SourceRange Range, QualifierMangleMode QMM = QMM_Mangle); @@ -387,8 +387,8 @@ void MicrosoftCXXNameMangler::mangleName(const NamedDecl *ND) { Out << '@'; } -void MicrosoftCXXNameMangler::mangleNumber(int64_t Number) { - llvm::APSInt APSNumber(/*BitWidth=*/64, /*isUnsigned=*/false); +void MicrosoftCXXNameMangler::mangleNumber(uint32_t Number) { + llvm::APSInt APSNumber(/*BitWidth=*/32, /*isUnsigned=*/true); APSNumber = Number; mangleNumber(APSNumber); } @@ -836,7 +836,7 @@ void MicrosoftCXXNameMangler::mangleLocalName(const FunctionDecl *FD) { // functions. You could have a method baz of class C inside a function bar // inside a function foo, like so: // ?baz@C@?3??bar@?1??foo@@YAXXZ@YAXXZ@QAEXXZ - int NestLevel = getLocalNestingLevel(FD); + unsigned NestLevel = getLocalNestingLevel(FD); Out << '?'; mangleNumber(NestLevel); Out << '?'; @@ -1367,24 +1367,18 @@ void MicrosoftCXXNameMangler::mangleFunctionClass(const FunctionDecl *FD) { // ::= D # private: static far // ::= E # private: virtual near // ::= F # private: virtual far - // ::= G # private: thunk near - // ::= H # private: thunk far // ::= I # protected: near // ::= J # protected: far // ::= K # protected: static near // ::= L # protected: static far // ::= M # protected: virtual near // ::= N # protected: virtual far - // ::= O # protected: thunk near - // ::= P # protected: thunk far // ::= Q # public: near // ::= R # public: far // ::= S # public: static near // ::= T # public: static far // ::= U # public: virtual near // ::= V # public: virtual far - // ::= W # public: thunk near - // ::= X # public: thunk far // <global-function> ::= Y # global near // ::= Z # global far if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD)) { @@ -1843,12 +1837,61 @@ void MicrosoftMangleContextImpl::mangleCXXName(const NamedDecl *D, return Mangler.mangle(D); } +// <this-adjustment> ::= <no-adjustment> | <static-adjustment> | +// <virtual-adjustment> +// <no-adjustment> ::= A # private near +// ::= B # private far +// ::= I # protected near +// ::= J # protected far +// ::= Q # public near +// ::= R # public far +// <static-adjustment> ::= G <static-offset> # private near +// ::= H <static-offset> # private far +// ::= O <static-offset> # protected near +// ::= P <static-offset> # protected far +// ::= W <static-offset> # public near +// ::= X <static-offset> # public far +// <virtual-adjustment> ::= $0 <virtual-shift> <static-offset> # private near +// ::= $1 <virtual-shift> <static-offset> # private far +// ::= $2 <virtual-shift> <static-offset> # protected near +// ::= $3 <virtual-shift> <static-offset> # protected far +// ::= $4 <virtual-shift> <static-offset> # public near +// ::= $5 <virtual-shift> <static-offset> # public far +// <virtual-shift> ::= <vtordisp-shift> | <vtordispex-shift> +// <vtordisp-shift> ::= <offset-to-vtordisp> +// <vtordispex-shift> ::= <offset-to-vbptr> <vbase-offset-offset> +// <offset-to-vtordisp> static void mangleThunkThisAdjustment(const CXXMethodDecl *MD, const ThisAdjustment &Adjustment, MicrosoftCXXNameMangler &Mangler, raw_ostream &Out) { - // FIXME: add support for vtordisp thunks. - if (Adjustment.NonVirtual != 0) { + if (!Adjustment.Virtual.isEmpty()) { + Out << '$'; + char AccessSpec; + switch (MD->getAccess()) { + case AS_none: + llvm_unreachable("Unsupported access specifier"); + case AS_private: + AccessSpec = '0'; + break; + case AS_protected: + AccessSpec = '2'; + break; + case AS_public: + AccessSpec = '4'; + } + if (Adjustment.Virtual.Microsoft.VBPtrOffset) { + Out << 'R' << AccessSpec; + Mangler.mangleNumber(Adjustment.Virtual.Microsoft.VBPtrOffset); + Mangler.mangleNumber(Adjustment.Virtual.Microsoft.VBOffsetOffset); + Mangler.mangleNumber(Adjustment.Virtual.Microsoft.VtordispOffset); + Mangler.mangleNumber(Adjustment.NonVirtual); + } else { + Out << AccessSpec; + Mangler.mangleNumber(Adjustment.Virtual.Microsoft.VtordispOffset); + Mangler.mangleNumber(-Adjustment.NonVirtual); + } + } else if (Adjustment.NonVirtual != 0) { switch (MD->getAccess()) { case AS_none: llvm_unreachable("Unsupported access specifier"); @@ -1861,9 +1904,7 @@ static void mangleThunkThisAdjustment(const CXXMethodDecl *MD, case AS_public: Out << 'W'; } - llvm::APSInt APSNumber(/*BitWidth=*/32, /*isUnsigned=*/true); - APSNumber = -Adjustment.NonVirtual; - Mangler.mangleNumber(APSNumber); + Mangler.mangleNumber(-Adjustment.NonVirtual); } else { switch (MD->getAccess()) { case AS_none: diff --git a/clang/lib/AST/VTableBuilder.cpp b/clang/lib/AST/VTableBuilder.cpp index 69a2fb2136f..efaa313a67b 100644 --- a/clang/lib/AST/VTableBuilder.cpp +++ b/clang/lib/AST/VTableBuilder.cpp @@ -1304,7 +1304,7 @@ ThisAdjustment ItaniumVTableBuilder::ComputeThisAdjustment( VCallOffsets = Builder.getVCallOffsets(); } - Adjustment.VCallOffsetOffset = + Adjustment.Virtual.Itanium.VCallOffsetOffset = VCallOffsets.getVCallOffsetOffset(MD).getQuantity(); } @@ -1552,7 +1552,7 @@ void ItaniumVTableBuilder::AddMethods( ComputeThisAdjustment(OverriddenMD, BaseOffsetInLayoutClass, Overrider); - if (ThisAdjustment.VCallOffsetOffset && + if (ThisAdjustment.Virtual.Itanium.VCallOffsetOffset && Overrider.Method->getParent() == MostDerivedClass) { // There's no return adjustment from OverriddenMD and MD, @@ -2009,8 +2009,8 @@ void ItaniumVTableBuilder::dumpLayout(raw_ostream &Out) { Out << "\n [this adjustment: "; Out << Thunk.This.NonVirtual << " non-virtual"; - if (Thunk.This.VCallOffsetOffset) { - Out << ", " << Thunk.This.VCallOffsetOffset; + if (Thunk.This.Virtual.Itanium.VCallOffsetOffset) { + Out << ", " << Thunk.This.Virtual.Itanium.VCallOffsetOffset; Out << " vcall offset offset"; } @@ -2044,8 +2044,8 @@ void ItaniumVTableBuilder::dumpLayout(raw_ostream &Out) { Out << "\n [this adjustment: "; Out << Thunk.This.NonVirtual << " non-virtual"; - if (Thunk.This.VCallOffsetOffset) { - Out << ", " << Thunk.This.VCallOffsetOffset; + if (Thunk.This.Virtual.Itanium.VCallOffsetOffset) { + Out << ", " << Thunk.This.Virtual.Itanium.VCallOffsetOffset; Out << " vcall offset offset"; } @@ -2186,8 +2186,8 @@ void ItaniumVTableBuilder::dumpLayout(raw_ostream &Out) { Out << "this adjustment: "; Out << Thunk.This.NonVirtual << " non-virtual"; - if (Thunk.This.VCallOffsetOffset) { - Out << ", " << Thunk.This.VCallOffsetOffset; + if (Thunk.This.Virtual.Itanium.VCallOffsetOffset) { + Out << ", " << Thunk.This.Virtual.Itanium.VCallOffsetOffset; Out << " vcall offset offset"; } } @@ -2527,6 +2527,9 @@ private: BaseSubobject Base, FinalOverriders::OverriderInfo Overrider); + void CalculateVtordispAdjustment(FinalOverriders::OverriderInfo Overrider, + CharUnits ThisOffset, ThisAdjustment &TA); + /// AddMethod - Add a single virtual member function to the vftable /// components vector. void AddMethod(const CXXMethodDecl *MD, ThunkInfo TI) { @@ -2672,7 +2675,7 @@ VFTableBuilder::ComputeThisOffset(const CXXMethodDecl *MD, I != E; ++I) { const CXXBasePath &Path = (*I); CharUnits ThisOffset = Base.getBaseOffset(); - bool SeenVBase = false; + CharUnits LastVBaseOffset; // For each path from the overrider to the parents of the overridden methods, // traverse the path, calculating the this offset in the most derived class. @@ -2684,7 +2687,7 @@ VFTableBuilder::ComputeThisOffset(const CXXMethodDecl *MD, const ASTRecordLayout &Layout = Context.getASTRecordLayout(PrevRD); if (Element.Base->isVirtual()) { - SeenVBase = true; + LastVBaseOffset = MostDerivedClassLayout.getVBaseClassOffset(CurRD); if (Overrider.Method->getParent() == PrevRD) { // This one's interesting. If the final overrider is in a vbase B of the // most derived class and it overrides a method of the B's own vbase A, @@ -2695,23 +2698,25 @@ VFTableBuilder::ComputeThisOffset(const CXXMethodDecl *MD, // differently in the most derived class. ThisOffset += Layout.getVBaseClassOffset(CurRD); } else { - ThisOffset = MostDerivedClassLayout.getVBaseClassOffset(CurRD); + ThisOffset = LastVBaseOffset; } - - // A virtual destructor of a virtual base takes the address of the - // virtual base subobject as the "this" argument. - if (isa<CXXDestructorDecl>(MD)) - break; } else { ThisOffset += Layout.getBaseClassOffset(CurRD); } } - // If a "Base" class has at least one non-virtual base with a virtual - // destructor, the "Base" virtual destructor will take the address of the - // "Base" subobject as the "this" argument. - if (!SeenVBase && isa<CXXDestructorDecl>(MD)) - return Base.getBaseOffset(); + if (isa<CXXDestructorDecl>(MD)) { + if (LastVBaseOffset.isZero()) { + // If a "Base" class has at least one non-virtual base with a virtual + // destructor, the "Base" virtual destructor will take the address + // of the "Base" subobject as the "this" argument. + return Base.getBaseOffset(); + } else { + // A virtual destructor of a virtual base takes the address of the + // virtual base subobject as the "this" argument. + return LastVBaseOffset; + } + } if (Ret > ThisOffset || First) { First = false; @@ -2723,6 +2728,49 @@ VFTableBuilder::ComputeThisOffset(const CXXMethodDecl *MD, return Ret; } +void VFTableBuilder::CalculateVtordispAdjustment( + FinalOverriders::OverriderInfo Overrider, CharUnits ThisOffset, + ThisAdjustment &TA) { + const ASTRecordLayout::VBaseOffsetsMapTy &VBaseMap = + MostDerivedClassLayout.getVBaseOffsetsMap(); + const ASTRecordLayout::VBaseOffsetsMapTy::const_iterator &VBaseMapEntry = + VBaseMap.find(WhichVFPtr.LastVBase); + assert(VBaseMapEntry != VBaseMap.end()); + + // Check if we need a vtordisp adjustment at all. + if (!VBaseMapEntry->second.hasVtorDisp()) + return; + + CharUnits VFPtrVBaseOffset = VBaseMapEntry->second.VBaseOffset; + // The implicit vtordisp field is located right before the vbase. + TA.Virtual.Microsoft.VtordispOffset = + (VFPtrVBaseOffset - WhichVFPtr.VFPtrFullOffset).getQuantity() - 4; + + // If the final overrider is defined in either: + // - the most derived class or its non-virtual base or + // - the same vbase as the initial declaration, + // a simple vtordisp thunk will suffice. + const CXXRecordDecl *OverriderRD = Overrider.Method->getParent(); + if (OverriderRD == MostDerivedClass) + return; + + const CXXRecordDecl *OverriderVBase = + ComputeBaseOffset(Context, OverriderRD, MostDerivedClass).VirtualBase; + if (!OverriderVBase || OverriderVBase == WhichVFPtr.LastVBase) + return; + + // Otherwise, we need to do use the dynamic offset of the final overrider + // in order to get "this" adjustment right. + TA.Virtual.Microsoft.VBPtrOffset = + (VFPtrVBaseOffset + WhichVFPtr.VFPtrOffset - + MostDerivedClassLayout.getVBPtrOffset()).getQuantity(); + TA.Virtual.Microsoft.VBOffsetOffset = + Context.getTypeSizeInChars(Context.IntTy).getQuantity() * + VTables.getVBTableIndex(MostDerivedClass, OverriderVBase); + + TA.NonVirtual = (ThisOffset - Overrider.Offset).getQuantity(); +} + static void GroupNewVirtualOverloads( const CXXRecordDecl *RD, SmallVector<const CXXMethodDecl *, 10> &VirtualMethods) { @@ -2829,6 +2877,12 @@ void VFTableBuilder::AddMethods(BaseSubobject Base, unsigned BaseDepth, if (TI != WhichVFPtr.VFPtrFullOffset) { ThisAdjustmentOffset.NonVirtual = (TI - WhichVFPtr.VFPtrFullOffset).getQuantity(); + } + + if (WhichVFPtr.LastVBase) + CalculateVtordispAdjustment(Overrider, TI, ThisAdjustmentOffset); + + if (!ThisAdjustmentOffset.isEmpty()) { VTableThunks[OverriddenMethodInfo.VFTableIndex].This = ThisAdjustmentOffset; AddThunk(MD, VTableThunks[OverriddenMethodInfo.VFTableIndex]); @@ -2962,8 +3016,17 @@ static void dumpMicrosoftThunkAdjustment(const ThunkInfo &TI, raw_ostream &Out, if (Multiline || !ContinueFirstLine) Out << LinePrefix; Out << "[this adjustment: "; - assert(TI.This.VCallOffsetOffset == 0 && - "VtorDisp adjustment is not supported yet"); + if (!TI.This.Virtual.isEmpty()) { + assert(T.Virtual.Microsoft.VtordispOffset < 0); + Out << "vtordisp at " << T.Virtual.Microsoft.VtordispOffset << ", "; + if (T.Virtual.Microsoft.VBPtrOffset) { + Out << "vbptr at " << T.Virtual.Microsoft.VBPtrOffset + << " to the left, "; + assert(T.Virtual.Microsoft.VBOffsetOffset > 0); + Out << LinePrefix << " vboffset at " + << T.Virtual.Microsoft.VBOffsetOffset << " in the vbtable, "; + } + } Out << T.NonVirtual << " non-virtual]"; } } diff --git a/clang/lib/CodeGen/ItaniumCXXABI.cpp b/clang/lib/CodeGen/ItaniumCXXABI.cpp index 9b7cf17030a..0e8f31a4845 100644 --- a/clang/lib/CodeGen/ItaniumCXXABI.cpp +++ b/clang/lib/CodeGen/ItaniumCXXABI.cpp @@ -1118,7 +1118,8 @@ static llvm::Value *performTypeAdjustment(CodeGenFunction &CGF, llvm::Value *ItaniumCXXABI::performThisAdjustment(CodeGenFunction &CGF, llvm::Value *This, const ThisAdjustment &TA) { - return performTypeAdjustment(CGF, This, TA.NonVirtual, TA.VCallOffsetOffset, + return performTypeAdjustment(CGF, This, TA.NonVirtual, + TA.Virtual.Itanium.VCallOffsetOffset, /*IsReturnAdjustment=*/false); } diff --git a/clang/lib/CodeGen/MicrosoftCXXABI.cpp b/clang/lib/CodeGen/MicrosoftCXXABI.cpp index 7e3a47d9131..6415749e2df 100644 --- a/clang/lib/CodeGen/MicrosoftCXXABI.cpp +++ b/clang/lib/CodeGen/MicrosoftCXXABI.cpp @@ -988,8 +988,29 @@ llvm::Value *MicrosoftCXXABI::performThisAdjustment(CodeGenFunction &CGF, llvm::Value *V = CGF.Builder.CreateBitCast(This, CGF.Int8PtrTy); - assert(TA.VCallOffsetOffset == 0 && - "VtorDisp adjustment is not supported yet"); + if (!TA.Virtual.isEmpty()) { + assert(TA.Virtual.Microsoft.VtordispOffset < 0); + // Adjust the this argument based on the vtordisp value. + llvm::Value *VtorDispPtr = + CGF.Builder.CreateConstGEP1_32(V, TA.Virtual.Microsoft.VtordispOffset); + VtorDispPtr = + CGF.Builder.CreateBitCast(VtorDispPtr, CGF.Int32Ty->getPointerTo()); + llvm::Value *VtorDisp = CGF.Builder.CreateLoad(VtorDispPtr, "vtordisp"); + V = CGF.Builder.CreateGEP(V, CGF.Builder.CreateNeg(VtorDisp)); + + if (TA.Virtual.Microsoft.VBPtrOffset) { + // If the final overrider is defined in a virtual base other than the one + // that holds the vfptr, we have to use a vtordispex thunk which looks up + // the vbtable of the derived class. + assert(TA.Virtual.Microsoft.VBPtrOffset > 0); + assert(TA.Virtual.Microsoft.VBOffsetOffset >= 0); + llvm::Value *VBPtr; + llvm::Value *VBaseOffset = + GetVBaseOffsetFromVBPtr(CGF, V, -TA.Virtual.Microsoft.VBPtrOffset, + TA.Virtual.Microsoft.VBOffsetOffset, &VBPtr); + V = CGF.Builder.CreateInBoundsGEP(VBPtr, VBaseOffset); + } + } if (TA.NonVirtual) { // Non-virtual adjustment might result in a pointer outside the allocated |