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/AST/VTableBuilder.cpp | |
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/AST/VTableBuilder.cpp')
-rw-r--r-- | clang/lib/AST/VTableBuilder.cpp | 109 |
1 files changed, 86 insertions, 23 deletions
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]"; } } |