From: Timur Iskhodzhanov Date: Tue, 5 Nov 2013 15:54:58 +0000 (+0000) Subject: Fix vbtable indices when a class shares the vbptr with a non-virtual base X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=5f0db587078b5af32fc9ac41fe4276b80918fd8d;p=clang Fix vbtable indices when a class shares the vbptr with a non-virtual base git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@194082 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/AST/VTableBuilder.h b/include/clang/AST/VTableBuilder.h index 82bcb9cbb0..6a87ab992a 100644 --- a/include/clang/AST/VTableBuilder.h +++ b/include/clang/AST/VTableBuilder.h @@ -20,6 +20,7 @@ #include "clang/AST/RecordLayout.h" #include "clang/Basic/ABI.h" #include "llvm/ADT/SetVector.h" +#include "llvm/ADT/DenseSet.h" #include namespace clang { @@ -358,16 +359,6 @@ public: const CXXRecordDecl *VBase); }; -/// \brief Computes the index of VBase in the vbtable of Derived. -/// VBase must be a morally virtual base of Derived. The vbtable is -/// an array of i32 offsets. The first entry is a self entry, and the rest are -/// offsets from the vbptr to virtual bases. The bases are ordered the same way -/// our vbases are ordered: as they appear in a left-to-right depth-first search -/// of the hierarchy. -// FIXME: make this a static method of VBTableBuilder when we move it to AST. -unsigned GetVBTableIndex(const CXXRecordDecl *Derived, - const CXXRecordDecl *VBase); - struct VFPtrInfo { typedef SmallVector BasePath; @@ -411,7 +402,7 @@ struct VFPtrInfo { CharUnits VFPtrFullOffset; }; -class MicrosoftVFTableContext : public VTableContextBase { +class MicrosoftVTableContext : public VTableContextBase { public: struct MethodVFTableLocation { /// If nonzero, holds the vbtable index of the virtual base with the vfptr. @@ -467,16 +458,34 @@ private: typedef llvm::DenseMap VFTableLayoutMapTy; VFTableLayoutMapTy VFTableLayouts; + typedef llvm::SmallSetVector BasesSetVectorTy; + void enumerateVFPtrs(const CXXRecordDecl *MostDerivedClass, + const ASTRecordLayout &MostDerivedClassLayout, + BaseSubobject Base, const CXXRecordDecl *LastVBase, + const VFPtrInfo::BasePath &PathFromCompleteClass, + BasesSetVectorTy &VisitedVBases, + MicrosoftVTableContext::VFPtrListTy &Result); + + void enumerateVFPtrs(const CXXRecordDecl *ForClass, + MicrosoftVTableContext::VFPtrListTy &Result); + void computeVTableRelatedInformation(const CXXRecordDecl *RD); void dumpMethodLocations(const CXXRecordDecl *RD, const MethodVFTableLocationsTy &NewMethods, raw_ostream &); + typedef std::pair ClassPairTy; + typedef llvm::DenseMap VBTableIndicesTy; + VBTableIndicesTy VBTableIndices; + llvm::DenseSet ComputedVBTableIndices; + + void computeVBTableRelatedInformation(const CXXRecordDecl *RD); + public: - MicrosoftVFTableContext(ASTContext &Context) : Context(Context) {} + MicrosoftVTableContext(ASTContext &Context) : Context(Context) {} - ~MicrosoftVFTableContext() { llvm::DeleteContainerSeconds(VFTableLayouts); } + ~MicrosoftVTableContext() { llvm::DeleteContainerSeconds(VFTableLayouts); } const VFPtrListTy &getVFPtrOffsets(const CXXRecordDecl *RD); @@ -492,6 +501,19 @@ public: return 0; return VTableContextBase::getThunkInfo(GD); } + + /// \brief Returns the index of VBase in the vbtable of Derived. + /// VBase must be a morally virtual base of Derived. + /// The vbtable is an array of i32 offsets. The first entry is a self entry, + /// and the rest are offsets from the vbptr to virtual bases. + unsigned getVBTableIndex(const CXXRecordDecl *Derived, + const CXXRecordDecl *VBase) { + computeVBTableRelatedInformation(Derived); + ClassPairTy Pair(Derived, VBase); + assert(VBTableIndices.count(Pair) == 1 && + "VBase must be a vbase of Derived"); + return VBTableIndices[Pair]; + } }; } diff --git a/lib/AST/VTableBuilder.cpp b/lib/AST/VTableBuilder.cpp index c2b33e6558..69a2fb2136 100644 --- a/lib/AST/VTableBuilder.cpp +++ b/lib/AST/VTableBuilder.cpp @@ -2397,18 +2397,6 @@ VTableLayout *ItaniumVTableContext::createConstructionVTableLayout( return CreateVTableLayout(Builder); } -unsigned clang::GetVBTableIndex(const CXXRecordDecl *Derived, - const CXXRecordDecl *VBase) { - unsigned VBTableIndex = 1; // Start with one to skip the self entry. - for (CXXRecordDecl::base_class_const_iterator I = Derived->vbases_begin(), - E = Derived->vbases_end(); I != E; ++I) { - if (I->getType()->getAsCXXRecordDecl() == VBase) - return VBTableIndex; - ++VBTableIndex; - } - llvm_unreachable("VBase must be a vbase of Derived"); -} - namespace { // Vtables in the Microsoft ABI are different from the Itanium ABI. @@ -2451,12 +2439,15 @@ namespace { class VFTableBuilder { public: - typedef MicrosoftVFTableContext::MethodVFTableLocation MethodVFTableLocation; + typedef MicrosoftVTableContext::MethodVFTableLocation MethodVFTableLocation; typedef llvm::DenseMap MethodVFTableLocationsTy; private: + /// VTables - Global vtable information. + MicrosoftVTableContext &VTables; + /// Context - The ASTContext which we will use for layout information. ASTContext &Context; @@ -2591,8 +2582,10 @@ private: } public: - VFTableBuilder(const CXXRecordDecl *MostDerivedClass, VFPtrInfo Which) - : Context(MostDerivedClass->getASTContext()), + VFTableBuilder(MicrosoftVTableContext &VTables, + const CXXRecordDecl *MostDerivedClass, VFPtrInfo Which) + : VTables(VTables), + Context(MostDerivedClass->getASTContext()), MostDerivedClass(MostDerivedClass), MostDerivedClassLayout(Context.getASTRecordLayout(MostDerivedClass)), WhichVFPtr(Which), @@ -2889,7 +2882,7 @@ void VFTableBuilder::AddMethods(BaseSubobject Base, unsigned BaseDepth, // If we got here, MD is a method not seen in any of the sub-bases or // it requires return adjustment. Insert the method info for this method. unsigned VBIndex = - LastVBase ? GetVBTableIndex(MostDerivedClass, LastVBase) : 0; + LastVBase ? VTables.getVBTableIndex(MostDerivedClass, LastVBase) : 0; MethodInfo MI(VBIndex, Components.size()); assert(!MethodInfoMap.count(MD) && @@ -2916,8 +2909,8 @@ void VFTableBuilder::AddMethods(BaseSubobject Base, unsigned BaseDepth, ReturnAdjustment.Virtual.Microsoft.VBPtrOffset = DerivedLayout.getVBPtrOffset().getQuantity(); ReturnAdjustment.Virtual.Microsoft.VBIndex = - GetVBTableIndex(ReturnAdjustmentOffset.DerivedClass, - ReturnAdjustmentOffset.VirtualBase); + VTables.getVBTableIndex(ReturnAdjustmentOffset.DerivedClass, + ReturnAdjustmentOffset.VirtualBase); } } @@ -3087,13 +3080,13 @@ void VFTableBuilder::dumpLayout(raw_ostream &Out) { } } -static void EnumerateVFPtrs( - ASTContext &Context, const CXXRecordDecl *MostDerivedClass, - const ASTRecordLayout &MostDerivedClassLayout, - BaseSubobject Base, const CXXRecordDecl *LastVBase, +void MicrosoftVTableContext::enumerateVFPtrs( + const CXXRecordDecl *MostDerivedClass, + const ASTRecordLayout &MostDerivedClassLayout, BaseSubobject Base, + const CXXRecordDecl *LastVBase, const VFPtrInfo::BasePath &PathFromCompleteClass, BasesSetVectorTy &VisitedVBases, - MicrosoftVFTableContext::VFPtrListTy &Result) { + VFPtrListTy &Result) { const CXXRecordDecl *CurrentClass = Base.getBase(); CharUnits OffsetInCompleteClass = Base.getBaseOffset(); const ASTRecordLayout &CurrentClassLayout = @@ -3101,7 +3094,7 @@ static void EnumerateVFPtrs( if (CurrentClassLayout.hasOwnVFPtr()) { if (LastVBase) { - uint64_t VBIndex = GetVBTableIndex(MostDerivedClass, LastVBase); + uint64_t VBIndex = getVBTableIndex(MostDerivedClass, LastVBase); assert(VBIndex > 0 && "vbases must have vbindex!"); CharUnits VFPtrOffset = OffsetInCompleteClass - @@ -3134,7 +3127,7 @@ static void EnumerateVFPtrs( NewPath.push_back(BaseDecl); BaseSubobject NextBase(BaseDecl, NextBaseOffset); - EnumerateVFPtrs(Context, MostDerivedClass, MostDerivedClassLayout, NextBase, + enumerateVFPtrs(MostDerivedClass, MostDerivedClassLayout, NextBase, NextLastVBase, NewPath, VisitedVBases, Result); } } @@ -3188,12 +3181,13 @@ CalculatePathToMangle(const CXXRecordDecl *RD, VFPtrInfo &VFPtr) { } } -static void EnumerateVFPtrs(ASTContext &Context, const CXXRecordDecl *ForClass, - MicrosoftVFTableContext::VFPtrListTy &Result) { +void MicrosoftVTableContext::enumerateVFPtrs( + const CXXRecordDecl *ForClass, + MicrosoftVTableContext::VFPtrListTy &Result) { Result.clear(); const ASTRecordLayout &ClassLayout = Context.getASTRecordLayout(ForClass); BasesSetVectorTy VisitedVBases; - EnumerateVFPtrs(Context, ForClass, ClassLayout, + enumerateVFPtrs(ForClass, ClassLayout, BaseSubobject(ForClass, CharUnits::Zero()), 0, VFPtrInfo::BasePath(), VisitedVBases, Result); if (Result.size() > 1) { @@ -3202,7 +3196,7 @@ static void EnumerateVFPtrs(ASTContext &Context, const CXXRecordDecl *ForClass, } } -void MicrosoftVFTableContext::computeVTableRelatedInformation( +void MicrosoftVTableContext::computeVTableRelatedInformation( const CXXRecordDecl *RD) { assert(RD->isDynamicClass()); @@ -3213,12 +3207,12 @@ void MicrosoftVFTableContext::computeVTableRelatedInformation( const VTableLayout::AddressPointsMapTy EmptyAddressPointsMap; VFPtrListTy &VFPtrs = VFPtrLocations[RD]; - EnumerateVFPtrs(Context, RD, VFPtrs); + enumerateVFPtrs(RD, VFPtrs); MethodVFTableLocationsTy NewMethodLocations; for (VFPtrListTy::iterator I = VFPtrs.begin(), E = VFPtrs.end(); I != E; ++I) { - VFTableBuilder Builder(RD, *I); + VFTableBuilder Builder(*this, RD, *I); VFTableIdTy id(RD, I->VFPtrFullOffset); assert(VFTableLayouts.count(id) == 0); @@ -3238,7 +3232,7 @@ void MicrosoftVFTableContext::computeVTableRelatedInformation( dumpMethodLocations(RD, NewMethodLocations, llvm::errs()); } -void MicrosoftVFTableContext::dumpMethodLocations( +void MicrosoftVTableContext::dumpMethodLocations( const CXXRecordDecl *RD, const MethodVFTableLocationsTy &NewMethods, raw_ostream &Out) { // Compute the vtable indices for all the member functions. @@ -3297,8 +3291,56 @@ void MicrosoftVFTableContext::dumpMethodLocations( } } -const MicrosoftVFTableContext::VFPtrListTy & -MicrosoftVFTableContext::getVFPtrOffsets(const CXXRecordDecl *RD) { +void MicrosoftVTableContext::computeVBTableRelatedInformation( + const CXXRecordDecl *RD) { + if (ComputedVBTableIndices.count(RD)) + return; + ComputedVBTableIndices.insert(RD); + + const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); + BasesSetVectorTy VisitedBases; + + // First, see if the Derived class shared the vbptr + // with the first non-virtual base. + for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(), + E = RD->bases_end(); I != E; ++I) { + if (I->isVirtual()) + continue; + + const CXXRecordDecl *CurBase = I->getType()->getAsCXXRecordDecl(); + CharUnits DerivedVBPtrOffset = Layout.getVBPtrOffset(), + BaseOffset = Layout.getBaseClassOffset(CurBase); + const ASTRecordLayout &BaseLayout = Context.getASTRecordLayout(CurBase); + if (!BaseLayout.hasVBPtr() || + DerivedVBPtrOffset != BaseOffset + BaseLayout.getVBPtrOffset()) + continue; + + // If the Derived class shares the vbptr with a non-virtual base, + // it inherits its vbase indices. + computeVBTableRelatedInformation(CurBase); + for (CXXRecordDecl::base_class_const_iterator J = CurBase->vbases_begin(), + F = CurBase->vbases_end(); J != F; ++J) { + const CXXRecordDecl *SubVBase = J->getType()->getAsCXXRecordDecl(); + assert(VBTableIndices.count(ClassPairTy(CurBase, SubVBase))); + VBTableIndices[ClassPairTy(RD, SubVBase)] = + VBTableIndices[ClassPairTy(CurBase, SubVBase)]; + VisitedBases.insert(SubVBase); + } + } + + // New vbases are added to the end of the vbtable. + // Skip the self entry and vbases visited in the non-virtual base, if any. + unsigned VBTableIndex = 1 + VisitedBases.size(); + for (CXXRecordDecl::base_class_const_iterator I = RD->vbases_begin(), + E = RD->vbases_end(); I != E; ++I) { + const CXXRecordDecl *CurVBase = I->getType()->getAsCXXRecordDecl(); + if (VisitedBases.insert(CurVBase)) + VBTableIndices[ClassPairTy(RD, CurVBase)] = VBTableIndex++; + } +} + +const MicrosoftVTableContext::VFPtrListTy & +MicrosoftVTableContext::getVFPtrOffsets(const CXXRecordDecl *RD) { computeVTableRelatedInformation(RD); assert(VFPtrLocations.count(RD) && "Couldn't find vfptr locations"); @@ -3306,8 +3348,8 @@ MicrosoftVFTableContext::getVFPtrOffsets(const CXXRecordDecl *RD) { } const VTableLayout & -MicrosoftVFTableContext::getVFTableLayout(const CXXRecordDecl *RD, - CharUnits VFPtrOffset) { +MicrosoftVTableContext::getVFTableLayout(const CXXRecordDecl *RD, + CharUnits VFPtrOffset) { computeVTableRelatedInformation(RD); VFTableIdTy id(RD, VFPtrOffset); @@ -3315,8 +3357,8 @@ MicrosoftVFTableContext::getVFTableLayout(const CXXRecordDecl *RD, return *VFTableLayouts[id]; } -const MicrosoftVFTableContext::MethodVFTableLocation & -MicrosoftVFTableContext::getMethodVFTableLocation(GlobalDecl GD) { +const MicrosoftVTableContext::MethodVFTableLocation & +MicrosoftVTableContext::getMethodVFTableLocation(GlobalDecl GD) { assert(cast(GD.getDecl())->isVirtual() && "Only use this method for virtual methods or dtors"); if (isa(GD.getDecl())) diff --git a/lib/CodeGen/CGCXX.cpp b/lib/CodeGen/CGCXX.cpp index 25f3e6f4da..31134be810 100644 --- a/lib/CodeGen/CGCXX.cpp +++ b/lib/CodeGen/CGCXX.cpp @@ -295,9 +295,9 @@ static llvm::Value *BuildAppleKextVirtualCall(CodeGenFunction &CGF, Ty = Ty->getPointerTo()->getPointerTo(); VTable = CGF.Builder.CreateBitCast(VTable, Ty); assert(VTable && "BuildVirtualCall = kext vtbl pointer is null"); - uint64_t VTableIndex = CGM.getVTableContext().getMethodVTableIndex(GD); + uint64_t VTableIndex = CGM.getItaniumVTableContext().getMethodVTableIndex(GD); uint64_t AddressPoint = - CGM.getVTableContext().getVTableLayout(RD) + CGM.getItaniumVTableContext().getVTableLayout(RD) .getAddressPoint(BaseSubobject(RD, CharUnits::Zero())); VTableIndex += AddressPoint; llvm::Value *VFuncPtr = diff --git a/lib/CodeGen/CGDebugInfo.cpp b/lib/CodeGen/CGDebugInfo.cpp index 540d4054c5..9b131fd10e 100644 --- a/lib/CodeGen/CGDebugInfo.cpp +++ b/lib/CodeGen/CGDebugInfo.cpp @@ -1062,7 +1062,7 @@ CGDebugInfo::CreateCXXMemberFunction(const CXXMethodDecl *Method, // lookup if we have multiple or virtual inheritance. if (!isa(Method) && !CGM.getTarget().getCXXABI().isMicrosoft()) - VIndex = CGM.getVTableContext().getMethodVTableIndex(Method); + VIndex = CGM.getItaniumVTableContext().getMethodVTableIndex(Method); ContainingType = RecordTy; } @@ -1168,7 +1168,7 @@ CollectCXXBases(const CXXRecordDecl *RD, llvm::DIFile Unit, // virtual base offset offset is -ve. The code generator emits dwarf // expression where it expects +ve number. BaseOffset = - 0 - CGM.getVTableContext() + 0 - CGM.getItaniumVTableContext() .getVirtualBaseOffsetOffset(RD, Base).getQuantity(); BFlags = llvm::DIDescriptor::FlagVirtual; } else diff --git a/lib/CodeGen/CGRTTI.cpp b/lib/CodeGen/CGRTTI.cpp index 72d4220789..aa687b9560 100644 --- a/lib/CodeGen/CGRTTI.cpp +++ b/lib/CodeGen/CGRTTI.cpp @@ -846,7 +846,7 @@ void RTTIBuilder::BuildVMIClassTypeInfo(const CXXRecordDecl *RD) { CharUnits Offset; if (Base->isVirtual()) Offset = - CGM.getVTableContext().getVirtualBaseOffsetOffset(RD, BaseDecl); + CGM.getItaniumVTableContext().getVirtualBaseOffsetOffset(RD, BaseDecl); else { const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD); Offset = Layout.getBaseClassOffset(BaseDecl); diff --git a/lib/CodeGen/CGVTT.cpp b/lib/CodeGen/CGVTT.cpp index 31beb02a52..bfff470588 100644 --- a/lib/CodeGen/CGVTT.cpp +++ b/lib/CodeGen/CGVTT.cpp @@ -65,8 +65,8 @@ CodeGenVTables::EmitVTTDefinition(llvm::GlobalVariable *VTT, uint64_t AddressPoint; if (VTTVT.getBase() == RD) { // Just get the address point for the regular vtable. - AddressPoint = VTContext.getVTableLayout(RD) - .getAddressPoint(i->VTableBase); + AddressPoint = + ItaniumVTContext.getVTableLayout(RD).getAddressPoint(i->VTableBase); assert(AddressPoint != 0 && "Did not find vtable address point!"); } else { AddressPoint = VTableAddressPoints[i->VTableIndex].lookup(i->VTableBase); diff --git a/lib/CodeGen/CGVTables.cpp b/lib/CodeGen/CGVTables.cpp index 996bd905f6..5d657b064a 100644 --- a/lib/CodeGen/CGVTables.cpp +++ b/lib/CodeGen/CGVTables.cpp @@ -30,12 +30,12 @@ using namespace clang; using namespace CodeGen; CodeGenVTables::CodeGenVTables(CodeGenModule &CGM) - : CGM(CGM), VTContext(CGM.getContext()) { + : CGM(CGM), ItaniumVTContext(CGM.getContext()) { if (CGM.getTarget().getCXXABI().isMicrosoft()) { // FIXME: Eventually, we should only have one of V*TContexts available. // Today we use both in the Microsoft ABI as MicrosoftVFTableContext // is not completely supported in CodeGen yet. - VFTContext.reset(new MicrosoftVFTableContext(CGM.getContext())); + MicrosoftVTContext.reset(new MicrosoftVTableContext(CGM.getContext())); } } @@ -439,10 +439,10 @@ void CodeGenVTables::EmitThunks(GlobalDecl GD) return; const VTableContextBase::ThunkInfoVectorTy *ThunkInfoVector; - if (VFTContext.isValid()) { - ThunkInfoVector = VFTContext->getThunkInfo(GD); + if (MicrosoftVTContext.isValid()) { + ThunkInfoVector = MicrosoftVTContext->getThunkInfo(GD); } else { - ThunkInfoVector = VTContext.getThunkInfo(GD); + ThunkInfoVector = ItaniumVTContext.getThunkInfo(GD); } if (!ThunkInfoVector) @@ -581,9 +581,8 @@ CodeGenVTables::GenerateConstructionVTable(const CXXRecordDecl *RD, DI->completeClassData(Base.getBase()); OwningPtr VTLayout( - VTContext.createConstructionVTableLayout(Base.getBase(), - Base.getBaseOffset(), - BaseIsVirtual, RD)); + ItaniumVTContext.createConstructionVTableLayout( + Base.getBase(), Base.getBaseOffset(), BaseIsVirtual, RD)); // Add the address points. AddressPoints = VTLayout->getAddressPoints(); diff --git a/lib/CodeGen/CGVTables.h b/lib/CodeGen/CGVTables.h index 7c94a07fd9..e8cd55eed8 100644 --- a/lib/CodeGen/CGVTables.h +++ b/lib/CodeGen/CGVTables.h @@ -31,10 +31,10 @@ namespace CodeGen { class CodeGenVTables { CodeGenModule &CGM; - // FIXME: Consider moving VTContext and VFTContext into respective CXXABI - // classes? - ItaniumVTableContext VTContext; - OwningPtr VFTContext; + // FIXME: Consider moving ItaniumVTContext and MicrosoftVTContext into + // respective CXXABI classes? + ItaniumVTableContext ItaniumVTContext; + OwningPtr MicrosoftVTContext; /// VTableAddressPointsMapTy - Address points for a single vtable. typedef llvm::DenseMap VTableAddressPointsMapTy; @@ -72,9 +72,11 @@ public: CodeGenVTables(CodeGenModule &CGM); - ItaniumVTableContext &getVTableContext() { return VTContext; } + ItaniumVTableContext &getItaniumVTableContext() { return ItaniumVTContext; } - MicrosoftVFTableContext &getVFTableContext() { return *VFTContext.get(); } + MicrosoftVTableContext &getMicrosoftVTableContext() { + return *MicrosoftVTContext.get(); + } /// getSubVTTIndex - Return the index of the sub-VTT for the base class of the /// given record decl. diff --git a/lib/CodeGen/CodeGenModule.h b/lib/CodeGen/CodeGenModule.h index 249ad33175..45a9e20a51 100644 --- a/lib/CodeGen/CodeGenModule.h +++ b/lib/CodeGen/CodeGenModule.h @@ -523,12 +523,12 @@ public: CodeGenVTables &getVTables() { return VTables; } - ItaniumVTableContext &getVTableContext() { - return VTables.getVTableContext(); + ItaniumVTableContext &getItaniumVTableContext() { + return VTables.getItaniumVTableContext(); } - MicrosoftVFTableContext &getVFTableContext() { - return VTables.getVFTableContext(); + MicrosoftVTableContext &getMicrosoftVTableContext() { + return VTables.getMicrosoftVTableContext(); } llvm::MDNode *getTBAAInfo(QualType QTy); diff --git a/lib/CodeGen/ItaniumCXXABI.cpp b/lib/CodeGen/ItaniumCXXABI.cpp index 03fea46736..9b7cf17030 100644 --- a/lib/CodeGen/ItaniumCXXABI.cpp +++ b/lib/CodeGen/ItaniumCXXABI.cpp @@ -570,7 +570,7 @@ llvm::Constant *ItaniumCXXABI::BuildMemberPointer(const CXXMethodDecl *MD, // Get the function pointer (or index if this is a virtual function). llvm::Constant *MemPtr[2]; if (MD->isVirtual()) { - uint64_t Index = CGM.getVTableContext().getMethodVTableIndex(MD); + uint64_t Index = CGM.getItaniumVTableContext().getMethodVTableIndex(MD); const ASTContext &Context = getContext(); CharUnits PointerWidth = @@ -780,7 +780,8 @@ ItaniumCXXABI::GetVirtualBaseClassOffset(CodeGenFunction &CGF, const CXXRecordDecl *BaseClassDecl) { llvm::Value *VTablePtr = CGF.GetVTablePtr(This, CGM.Int8PtrTy); CharUnits VBaseOffsetOffset = - CGM.getVTableContext().getVirtualBaseOffsetOffset(ClassDecl, BaseClassDecl); + CGM.getItaniumVTableContext().getVirtualBaseOffsetOffset(ClassDecl, + BaseClassDecl); llvm::Value *VBaseOffsetPtr = CGF.Builder.CreateConstGEP1_64(VTablePtr, VBaseOffsetOffset.getQuantity(), @@ -927,7 +928,7 @@ void ItaniumCXXABI::emitVTableDefinitions(CodeGenVTables &CGVT, if (VTable->hasInitializer()) return; - ItaniumVTableContext &VTContext = CGM.getVTableContext(); + ItaniumVTableContext &VTContext = CGM.getItaniumVTableContext(); const VTableLayout &VTLayout = VTContext.getVTableLayout(RD); llvm::GlobalVariable::LinkageTypes Linkage = CGM.getVTableLinkage(RD); @@ -977,8 +978,9 @@ llvm::Value *ItaniumCXXABI::getVTableAddressPointInStructor( } else { llvm::Constant *VTable = CGM.getCXXABI().getAddrOfVTable(VTableClass, CharUnits()); - uint64_t AddressPoint = CGM.getVTableContext().getVTableLayout(VTableClass) - .getAddressPoint(Base); + uint64_t AddressPoint = CGM.getItaniumVTableContext() + .getVTableLayout(VTableClass) + .getAddressPoint(Base); VTableAddressPoint = CGF.Builder.CreateConstInBoundsGEP2_64(VTable, 0, AddressPoint); } @@ -991,8 +993,9 @@ llvm::Constant *ItaniumCXXABI::getVTableAddressPointForConstExpr( llvm::Constant *VTable = getAddrOfVTable(VTableClass, CharUnits()); // Find the appropriate vtable within the vtable group. - uint64_t AddressPoint = - CGM.getVTableContext().getVTableLayout(VTableClass).getAddressPoint(Base); + uint64_t AddressPoint = CGM.getItaniumVTableContext() + .getVTableLayout(VTableClass) + .getAddressPoint(Base); llvm::Value *Indices[] = { llvm::ConstantInt::get(CGM.Int64Ty, 0), llvm::ConstantInt::get(CGM.Int64Ty, AddressPoint) @@ -1018,7 +1021,7 @@ llvm::GlobalVariable *ItaniumCXXABI::getAddrOfVTable(const CXXRecordDecl *RD, Out.flush(); StringRef Name = OutName.str(); - ItaniumVTableContext &VTContext = CGM.getVTableContext(); + ItaniumVTableContext &VTContext = CGM.getItaniumVTableContext(); llvm::ArrayType *ArrayType = llvm::ArrayType::get( CGM.Int8PtrTy, VTContext.getVTableLayout(RD).getNumVTableComponents()); @@ -1036,7 +1039,7 @@ llvm::Value *ItaniumCXXABI::getVirtualFunctionPointer(CodeGenFunction &CGF, Ty = Ty->getPointerTo()->getPointerTo(); llvm::Value *VTable = CGF.GetVTablePtr(This, Ty); - uint64_t VTableIndex = CGM.getVTableContext().getMethodVTableIndex(GD); + uint64_t VTableIndex = CGM.getItaniumVTableContext().getMethodVTableIndex(GD); llvm::Value *VFuncPtr = CGF.Builder.CreateConstInBoundsGEP1_64(VTable, VTableIndex, "vfn"); return CGF.Builder.CreateLoad(VFuncPtr); diff --git a/lib/CodeGen/MicrosoftCXXABI.cpp b/lib/CodeGen/MicrosoftCXXABI.cpp index de13116b87..7e3a47d913 100644 --- a/lib/CodeGen/MicrosoftCXXABI.cpp +++ b/lib/CodeGen/MicrosoftCXXABI.cpp @@ -120,8 +120,8 @@ public: const CXXRecordDecl *getThisArgumentTypeForMethod(const CXXMethodDecl *MD) { MD = MD->getCanonicalDecl(); if (MD->isVirtual() && !isa(MD)) { - MicrosoftVFTableContext::MethodVFTableLocation ML = - CGM.getVFTableContext().getMethodVFTableLocation(MD); + MicrosoftVTableContext::MethodVFTableLocation ML = + CGM.getMicrosoftVTableContext().getMethodVFTableLocation(MD); // The vbases might be ordered differently in the final overrider object // and the complete object, so the "this" argument may sometimes point to // memory that has no particular type (e.g. past the complete object). @@ -423,7 +423,9 @@ MicrosoftCXXABI::GetVirtualBaseClassOffset(CodeGenFunction &CGF, int64_t VBPtrChars = GetVBPtrOffsetFromBases(ClassDecl).getQuantity(); llvm::Value *VBPtrOffset = llvm::ConstantInt::get(CGM.PtrDiffTy, VBPtrChars); CharUnits IntSize = getContext().getTypeSizeInChars(getContext().IntTy); - CharUnits VBTableChars = IntSize * GetVBTableIndex(ClassDecl, BaseClassDecl); + CharUnits VBTableChars = + IntSize * + CGM.getMicrosoftVTableContext().getVBTableIndex(ClassDecl, BaseClassDecl); llvm::Value *VBTableOffset = llvm::ConstantInt::get(CGM.IntTy, VBTableChars.getQuantity()); @@ -593,8 +595,8 @@ llvm::Value *MicrosoftCXXABI::adjustThisArgumentForVirtualCall( // with the base one, so look up the deleting one instead. LookupGD = GlobalDecl(DD, Dtor_Deleting); } - MicrosoftVFTableContext::MethodVFTableLocation ML = - CGM.getVFTableContext().getMethodVFTableLocation(LookupGD); + MicrosoftVTableContext::MethodVFTableLocation ML = + CGM.getMicrosoftVTableContext().getMethodVFTableLocation(LookupGD); unsigned AS = cast(This->getType())->getAddressSpace(); llvm::Type *charPtrTy = CGF.Int8Ty->getPointerTo(AS); @@ -719,8 +721,8 @@ llvm::Value *MicrosoftCXXABI::adjustThisParameterInVirtualFunctionPrologue( // to the final overrider subobject before use. // See comments in the MicrosoftVFTableContext implementation for the details. - MicrosoftVFTableContext::MethodVFTableLocation ML = - CGM.getVFTableContext().getMethodVFTableLocation(LookupGD); + MicrosoftVTableContext::MethodVFTableLocation ML = + CGM.getMicrosoftVTableContext().getMethodVFTableLocation(LookupGD); CharUnits Adjustment = ML.VFTableOffset; if (ML.VBase) { const ASTRecordLayout &DerivedLayout = @@ -801,11 +803,11 @@ void MicrosoftCXXABI::EmitConstructorCall(CodeGenFunction &CGF, void MicrosoftCXXABI::emitVTableDefinitions(CodeGenVTables &CGVT, const CXXRecordDecl *RD) { - MicrosoftVFTableContext &VFTContext = CGM.getVFTableContext(); - MicrosoftVFTableContext::VFPtrListTy VFPtrs = VFTContext.getVFPtrOffsets(RD); + MicrosoftVTableContext &VFTContext = CGM.getMicrosoftVTableContext(); + MicrosoftVTableContext::VFPtrListTy VFPtrs = VFTContext.getVFPtrOffsets(RD); llvm::GlobalVariable::LinkageTypes Linkage = CGM.getVTableLinkage(RD); - for (MicrosoftVFTableContext::VFPtrListTy::iterator I = VFPtrs.begin(), + for (MicrosoftVTableContext::VFPtrListTy::iterator I = VFPtrs.begin(), E = VFPtrs.end(); I != E; ++I) { llvm::GlobalVariable *VTable = getAddrOfVTable(RD, I->VFPtrFullOffset); if (VTable->hasInitializer()) @@ -867,9 +869,9 @@ llvm::GlobalVariable *MicrosoftCXXABI::getAddrOfVTable(const CXXRecordDecl *RD, llvm::GlobalVariable *&VTable = I->second; - MicrosoftVFTableContext &VFTContext = CGM.getVFTableContext(); - const MicrosoftVFTableContext::VFPtrListTy &VFPtrs = - VFTContext.getVFPtrOffsets(RD); + MicrosoftVTableContext &VTContext = CGM.getMicrosoftVTableContext(); + const MicrosoftVTableContext::VFPtrListTy &VFPtrs = + VTContext.getVFPtrOffsets(RD); if (DeferredVFTables.insert(RD)) { // We haven't processed this record type before. @@ -895,7 +897,7 @@ llvm::GlobalVariable *MicrosoftCXXABI::getAddrOfVTable(const CXXRecordDecl *RD, llvm::ArrayType *ArrayType = llvm::ArrayType::get( CGM.Int8PtrTy, - VFTContext.getVFTableLayout(RD, VFPtrs[J].VFPtrFullOffset) + VTContext.getVFTableLayout(RD, VFPtrs[J].VFPtrFullOffset) .getNumVTableComponents()); SmallString<256> Name; @@ -920,8 +922,8 @@ llvm::Value *MicrosoftCXXABI::getVirtualFunctionPointer(CodeGenFunction &CGF, llvm::Value *VPtr = adjustThisArgumentForVirtualCall(CGF, GD, This); llvm::Value *VTable = CGF.GetVTablePtr(VPtr, Ty); - MicrosoftVFTableContext::MethodVFTableLocation ML = - CGM.getVFTableContext().getMethodVFTableLocation(GD); + MicrosoftVTableContext::MethodVFTableLocation ML = + CGM.getMicrosoftVTableContext().getMethodVFTableLocation(GD); llvm::Value *VFuncPtr = Builder.CreateConstInBoundsGEP1_64(VTable, ML.Index, "vfn"); return Builder.CreateLoad(VFuncPtr); diff --git a/lib/CodeGen/MicrosoftVBTables.cpp b/lib/CodeGen/MicrosoftVBTables.cpp index b4b98d3357..dabf52c1cc 100644 --- a/lib/CodeGen/MicrosoftVBTables.cpp +++ b/lib/CodeGen/MicrosoftVBTables.cpp @@ -195,15 +195,13 @@ void VBTableInfo::EmitVBTableDefinition( const ASTRecordLayout &DerivedLayout = CGM.getContext().getASTRecordLayout(RD); - SmallVector Offsets; + SmallVector Offsets(1 + ReusingBase->getNumVBases(), 0); // The offset from ReusingBase's vbptr to itself always leads. CharUnits VBPtrOffset = BaseLayout.getVBPtrOffset(); - Offsets.push_back( - llvm::ConstantInt::get(CGM.IntTy, -VBPtrOffset.getQuantity())); + Offsets[0] = llvm::ConstantInt::get(CGM.IntTy, -VBPtrOffset.getQuantity()); - // These are laid out in the same order as in Itanium, which is the same as - // the order of the vbase iterator. + MicrosoftVTableContext &Context = CGM.getMicrosoftVTableContext(); for (CXXRecordDecl::base_class_const_iterator I = ReusingBase->vbases_begin(), E = ReusingBase->vbases_end(); I != E; ++I) { const CXXRecordDecl *VBase = I->getType()->getAsCXXRecordDecl(); @@ -211,7 +209,9 @@ void VBTableInfo::EmitVBTableDefinition( assert(!Offset.isNegative()); // Make it relative to the subobject vbptr. Offset -= VBPtrSubobject.getBaseOffset() + VBPtrOffset; - Offsets.push_back(llvm::ConstantInt::get(CGM.IntTy, Offset.getQuantity())); + unsigned VBIndex = Context.getVBTableIndex(ReusingBase, VBase); + assert(Offsets[VBIndex] == 0 && "The same vbindex seen twice?"); + Offsets[VBIndex] = llvm::ConstantInt::get(CGM.IntTy, Offset.getQuantity()); } assert(Offsets.size() == diff --git a/test/CodeGenCXX/microsoft-abi-vbtables.cpp b/test/CodeGenCXX/microsoft-abi-vbtables.cpp index 1d95672a90..6de556b1d8 100644 --- a/test/CodeGenCXX/microsoft-abi-vbtables.cpp +++ b/test/CodeGenCXX/microsoft-abi-vbtables.cpp @@ -410,3 +410,70 @@ H h; // CHECK-DAG: @"\01??_8B@Test21@@7B@" = // CHECK-DAG: @"\01??_8C@Test21@@7B@" = } + +namespace Test22 { +struct A { int a; }; +struct B : virtual A { int b; }; +struct C { int c; }; +struct D : B, virtual C { int d; }; +D d; + +// CHECK-DAG: @"\01??_8D@Test22@@7B@" = linkonce_odr unnamed_addr constant [3 x i32] [i32 0, i32 12, i32 16] +// CHECK-DAG: @"\01??_8B@Test22@@7B@" = linkonce_odr unnamed_addr constant [2 x i32] [i32 0, i32 8] +} + +namespace Test23 { +struct A { int a; }; +struct B : virtual A { int b; }; +struct C { int c; }; +// Note the unusual order of bases. It forces C to be laid out before A. +struct D : virtual C, B { int d; }; +D d; + +// CHECK-DAG: @"\01??_8D@Test23@@7B@" = linkonce_odr unnamed_addr constant [3 x i32] [i32 0, i32 16, i32 12] +// CHECK-DAG: @"\01??_8B@Test23@@7B@" = linkonce_odr unnamed_addr constant [2 x i32] [i32 0, i32 8] +} + +namespace Test24 { +struct A { int a; }; +struct B : virtual A { int b; }; +struct C { int c; }; +struct D : virtual C, B { + virtual void f(); // Issues a vfptr, but the vbptr is still shared with B. + int d; +}; +D d; + +// CHECK-DAG: @"\01??_8D@Test24@@7B@" = linkonce_odr unnamed_addr constant [3 x i32] [i32 0, i32 16, i32 12] +// CHECK-DAG: @"\01??_8B@Test24@@7B@" = linkonce_odr unnamed_addr constant [2 x i32] [i32 0, i32 8] +} + +namespace Test25 { +struct A { int a; }; +struct B : virtual A { + virtual void f(); // Issues a vfptr. + int b; +}; +struct C { int c; }; +struct D : virtual C, B { int d; }; +D d; + +// CHECK-DAG: @"\01??_8D@Test25@@7B@" = linkonce_odr unnamed_addr constant [3 x i32] [i32 -4, i32 16, i32 12] +// CHECK-DAG: @"\01??_8B@Test25@@7B@" = linkonce_odr unnamed_addr constant [2 x i32] [i32 -4, i32 8] +} + +namespace Test26 { +struct A { int a; }; +struct B { int b; }; +struct C { int c; }; +struct D : virtual A { int d; }; +struct E : virtual B { + virtual void foo(); // Issues a vfptr. + int e; +}; +struct F: virtual C, D, E { int f; }; +F f; +// F reuses the D's vbptr, even though D is laid out after E. +// CHECK-DAG: @"\01??_8F@Test26@@7BD@1@@" = linkonce_odr unnamed_addr constant [4 x i32] [i32 0, i32 16, i32 12, i32 20] +// CHECK-DAG: @"\01??_8F@Test26@@7BE@1@@" = linkonce_odr unnamed_addr constant [2 x i32] [i32 -4, i32 28] +}