Index: include/clang/AST/VTableBuilder.h =================================================================== --- include/clang/AST/VTableBuilder.h +++ include/clang/AST/VTableBuilder.h @@ -224,9 +224,12 @@ typedef llvm::iterator_range vtable_component_range; - typedef llvm::DenseMap AddressPointsMapTy; + typedef llvm::DenseMap> + AddressPointsMapTy; private: + std::vector VTableIndices; + uint64_t NumVTableComponents; std::unique_ptr VTableComponents; @@ -240,12 +243,10 @@ bool IsMicrosoftABI; public: - VTableLayout(uint64_t NumVTableComponents, + VTableLayout(ArrayRef VTableIndices, uint64_t NumVTableComponents, const VTableComponent *VTableComponents, - uint64_t NumVTableThunks, - const VTableThunkTy *VTableThunks, - const AddressPointsMapTy &AddressPoints, - bool IsMicrosoftABI); + uint64_t NumVTableThunks, const VTableThunkTy *VTableThunks, + const AddressPointsMapTy &AddressPoints, bool IsMicrosoftABI); ~VTableLayout(); ArrayRef vtable_components() const { @@ -256,12 +257,12 @@ return {VTableThunks.get(), NumVTableThunks}; } - uint64_t getAddressPoint(BaseSubobject Base) const { + std::pair getAddressPoint(BaseSubobject Base) const { assert(AddressPoints.count(Base) && "Did not find address point!"); - uint64_t AddressPoint = AddressPoints.lookup(Base); - assert(AddressPoint != 0 || IsMicrosoftABI); + std::pair AddressPoint = AddressPoints.lookup(Base); + assert(AddressPoint.second != 0 || IsMicrosoftABI); (void)IsMicrosoftABI; return AddressPoint; @@ -270,6 +271,12 @@ const AddressPointsMapTy &getAddressPoints() const { return AddressPoints; } + + /// Get the component indices of the first component of each virtual table in + /// the virtual table group. + ArrayRef getVTableIndices() const { + return VTableIndices; + } }; class VTableContextBase { Index: lib/AST/VTableBuilder.cpp =================================================================== --- lib/AST/VTableBuilder.cpp +++ lib/AST/VTableBuilder.cpp @@ -777,9 +777,8 @@ typedef llvm::DenseMap VBaseOffsetOffsetsMapTy; - - typedef llvm::DenseMap - AddressPointsMapTy; + + typedef VTableLayout::AddressPointsMapTy AddressPointsMapTy; typedef llvm::DenseMap MethodVTableIndicesTy; @@ -817,7 +816,7 @@ /// VBaseOffsetOffsets - Contains the offsets of the virtual base offsets for /// the most derived class. VBaseOffsetOffsetsMapTy VBaseOffsetOffsets; - + /// Components - The components of the vtable being built. SmallVector Components; @@ -982,6 +981,10 @@ } public: + /// Component indices of the first component of each of the vtables in the + /// vtable group. + std::vector VTableIndices; + ItaniumVTableBuilder(ItaniumVTableContext &VTables, const CXXRecordDecl *MostDerivedClass, CharUnits MostDerivedClassOffset, @@ -1639,6 +1642,9 @@ bool BaseIsVirtualInLayoutClass, CharUnits OffsetInLayoutClass) { assert(Base.getBase()->isDynamicClass() && "class does not have a vtable!"); + unsigned VTableIndex = Components.size(); + VTableIndices.push_back(VTableIndex); + // Add vcall and vbase offsets for this vtable. VCallAndVBaseOffsetBuilder Builder(MostDerivedClass, LayoutClass, &Overriders, Base, BaseIsVirtualInLayoutClass, @@ -1696,8 +1702,9 @@ // Add all address points. while (true) { AddressPoints.insert(std::make_pair( - BaseSubobject(RD, OffsetInLayoutClass), - AddressPoint)); + BaseSubobject(RD, OffsetInLayoutClass), + std::pair{VTableIndices.size() - 1, + AddressPoint - VTableIndex})); const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase(); @@ -1901,7 +1908,7 @@ std::multimap AddressPointsByIndex; for (const auto &AP : AddressPoints) { const BaseSubobject &Base = AP.first; - uint64_t Index = AP.second; + uint64_t Index = VTableIndices[AP.second.first] + AP.second.second; AddressPointsByIndex.insert(std::make_pair(Index, Base)); } @@ -2203,18 +2210,18 @@ } } -VTableLayout::VTableLayout(uint64_t NumVTableComponents, +VTableLayout::VTableLayout(ArrayRef VTableIndices, + uint64_t NumVTableComponents, const VTableComponent *VTableComponents, uint64_t NumVTableThunks, const VTableThunkTy *VTableThunks, const AddressPointsMapTy &AddressPoints, bool IsMicrosoftABI) - : NumVTableComponents(NumVTableComponents), - VTableComponents(new VTableComponent[NumVTableComponents]), - NumVTableThunks(NumVTableThunks), - VTableThunks(new VTableThunkTy[NumVTableThunks]), - AddressPoints(AddressPoints), - IsMicrosoftABI(IsMicrosoftABI) { + : VTableIndices(VTableIndices), NumVTableComponents(NumVTableComponents), + VTableComponents(new VTableComponent[NumVTableComponents]), + NumVTableThunks(NumVTableThunks), + VTableThunks(new VTableThunkTy[NumVTableThunks]), + AddressPoints(AddressPoints), IsMicrosoftABI(IsMicrosoftABI) { std::copy(VTableComponents, VTableComponents+NumVTableComponents, this->VTableComponents.get()); std::copy(VTableThunks, VTableThunks+NumVTableThunks, @@ -2284,11 +2291,10 @@ SmallVector VTableThunks(Builder.vtable_thunks_begin(), Builder.vtable_thunks_end()); - return new VTableLayout(Builder.getNumVTableComponents(), - Builder.vtable_component_begin(), - VTableThunks.size(), - VTableThunks.data(), - Builder.getAddressPoints(), + return new VTableLayout(Builder.VTableIndices, + Builder.getNumVTableComponents(), + Builder.vtable_component_begin(), VTableThunks.size(), + VTableThunks.data(), Builder.getAddressPoints(), /*IsMicrosoftABI=*/false); } @@ -3592,7 +3598,7 @@ SmallVector VTableThunks( Builder.vtable_thunks_begin(), Builder.vtable_thunks_end()); VFTableLayouts[id] = new VTableLayout( - Builder.getNumVTableComponents(), Builder.vtable_component_begin(), + {0}, Builder.getNumVTableComponents(), Builder.vtable_component_begin(), VTableThunks.size(), VTableThunks.data(), EmptyAddressPointsMap, true); Thunks.insert(Builder.thunks_begin(), Builder.thunks_end()); Index: lib/CodeGen/CGCXX.cpp =================================================================== --- lib/CodeGen/CGCXX.cpp +++ lib/CodeGen/CGCXX.cpp @@ -273,10 +273,11 @@ VTable = CGF.Builder.CreateBitCast(VTable, Ty); assert(VTable && "BuildVirtualCall = kext vtbl pointer is null"); uint64_t VTableIndex = CGM.getItaniumVTableContext().getMethodVTableIndex(GD); - uint64_t AddressPoint = - CGM.getItaniumVTableContext().getVTableLayout(RD) - .getAddressPoint(BaseSubobject(RD, CharUnits::Zero())); - VTableIndex += AddressPoint; + const VTableLayout &VTLayout = CGM.getItaniumVTableContext().getVTableLayout(RD); + std::pair AddressPoint = + VTLayout.getAddressPoint(BaseSubobject(RD, CharUnits::Zero())); + VTableIndex += + VTLayout.getVTableIndices()[AddressPoint.first] + AddressPoint.second; llvm::Value *VFuncPtr = CGF.Builder.CreateConstInBoundsGEP1_64(VTable, VTableIndex, "vfnkxt"); return CGF.Builder.CreateAlignedLoad(VFuncPtr, CGF.PointerAlignInBytes); Index: lib/CodeGen/CGVTT.cpp =================================================================== --- lib/CodeGen/CGVTT.cpp +++ lib/CodeGen/CGVTT.cpp @@ -23,7 +23,7 @@ const CXXRecordDecl *MostDerivedClass, const VTTVTable &VTable, llvm::GlobalVariable::LinkageTypes Linkage, - llvm::DenseMap &AddressPoints) { + VTableLayout::AddressPointsMapTy &AddressPoints) { if (VTable.getBase() == MostDerivedClass) { assert(VTable.getBaseOffset().isZero() && "Most derived class vtable must have a zero offset!"); @@ -62,25 +62,28 @@ *e = Builder.getVTTComponents().end(); i != e; ++i) { const VTTVTable &VTTVT = Builder.getVTTVTables()[i->VTableIndex]; llvm::GlobalVariable *VTable = VTables[i->VTableIndex]; - uint64_t AddressPoint; + std::pair AddressPoint; if (VTTVT.getBase() == RD) { // Just get the address point for the regular vtable. AddressPoint = getItaniumVTableContext().getVTableLayout(RD).getAddressPoint( i->VTableBase); - assert(AddressPoint != 0 && "Did not find vtable address point!"); + assert(AddressPoint.second != 0 && "Did not find vtable address point!"); } else { AddressPoint = VTableAddressPoints[i->VTableIndex].lookup(i->VTableBase); - assert(AddressPoint != 0 && "Did not find ctor vtable address point!"); + assert(AddressPoint.second != 0 && + "Did not find ctor vtable address point!"); } llvm::Value *Idxs[] = { llvm::ConstantInt::get(Int32Ty, 0), - llvm::ConstantInt::get(Int32Ty, AddressPoint) + llvm::ConstantInt::get(Int32Ty, AddressPoint.first), + llvm::ConstantInt::get(Int32Ty, AddressPoint.second), }; - llvm::Constant *Init = llvm::ConstantExpr::getInBoundsGetElementPtr( - VTable->getValueType(), VTable, Idxs); + llvm::Constant *Init = llvm::ConstantExpr::getGetElementPtr( + VTable->getValueType(), VTable, Idxs, /*InBounds=*/true, + /*InRangeIndex=*/1); Init = llvm::ConstantExpr::getBitCast(Init, Int8PtrTy); Index: lib/CodeGen/CGVTables.h =================================================================== --- lib/CodeGen/CGVTables.h +++ lib/CodeGen/CGVTables.h @@ -34,7 +34,7 @@ VTableContextBase *VTContext; /// VTableAddressPointsMapTy - Address points for a single vtable. - typedef llvm::DenseMap VTableAddressPointsMapTy; + typedef VTableLayout::AddressPointsMapTy VTableAddressPointsMapTy; typedef std::pair BaseSubobjectPairTy; typedef llvm::DenseMap SubVTTIndiciesMapTy; @@ -117,6 +117,12 @@ void GenerateClassData(const CXXRecordDecl *RD); bool isVTableExternal(const CXXRecordDecl *RD); + + /// Returns the type of a vtable with the given layout. Normally a struct of + /// arrays of pointers, with one struct element for each vtable in the vtable + /// group. + llvm::Type *GetVTableType(const CXXRecordDecl *RD, + const VTableLayout &VTLayout); }; } // end namespace CodeGen Index: lib/CodeGen/CGVTables.cpp =================================================================== --- lib/CodeGen/CGVTables.cpp +++ lib/CodeGen/CGVTables.cpp @@ -621,21 +621,44 @@ } } +llvm::Type *CodeGenVTables::GetVTableType(const CXXRecordDecl *RD, + const VTableLayout &VTLayout) { + ArrayRef Idxs = VTLayout.getVTableIndices(); + + std::vector Tys; + for (unsigned I = 0, E = Idxs.size(); I != E; ++I) { + size_t ThisIndex = Idxs[I]; + size_t NextIndex = + (I + 1 == E) ? VTLayout.vtable_components().size() : Idxs[I + 1]; + Tys.push_back(llvm::ArrayType::get(CGM.Int8PtrTy, NextIndex - ThisIndex)); + } + + return llvm::StructType::get(CGM.getLLVMContext(), Tys); +} + llvm::Constant * CodeGenVTables::CreateVTableInitializer(const VTableLayout &VTLayout, llvm::Constant *RTTI) { SmallVector Inits; unsigned NextVTableThunkIndex = 0; - for (unsigned I = 0, E = VTLayout.vtable_components().size(); I != E; ++I) { - llvm::Constant *Init = - CreateVTableComponent(I, VTLayout, RTTI, NextVTableThunkIndex); - Inits.push_back(llvm::ConstantExpr::getBitCast(Init, CGM.Int8PtrTy)); + ArrayRef Idxs = VTLayout.getVTableIndices(); + for (unsigned I = 0, E = Idxs.size(); I != E; ++I) { + size_t ThisIndex = Idxs[I]; + size_t NextIndex = + (I + 1 == E) ? VTLayout.vtable_components().size() : Idxs[I + 1]; + SmallVector ArrayInits; + for (unsigned I = ThisIndex; I != NextIndex; ++I) { + llvm::Constant *Init = + CreateVTableComponent(I, VTLayout, RTTI, NextVTableThunkIndex); + ArrayInits.push_back(llvm::ConstantExpr::getBitCast(Init, CGM.Int8PtrTy)); + } + llvm::ArrayType *ArrayType = + llvm::ArrayType::get(CGM.Int8PtrTy, NextIndex - ThisIndex); + Inits.push_back(llvm::ConstantArray::get(ArrayType, ArrayInits)); } - llvm::ArrayType *ArrayType = - llvm::ArrayType::get(CGM.Int8PtrTy, VTLayout.vtable_components().size()); - return llvm::ConstantArray::get(ArrayType, Inits); + return llvm::ConstantStruct::getAnon(Inits); } llvm::GlobalVariable * @@ -662,8 +685,7 @@ Base.getBase(), Out); StringRef Name = OutName.str(); - llvm::ArrayType *ArrayType = - llvm::ArrayType::get(CGM.Int8PtrTy, VTLayout->vtable_components().size()); + llvm::Type *VTType = GetVTableType(RD, *VTLayout); // Construction vtable symbols are not part of the Itanium ABI, so we cannot // guarantee that they actually will be available externally. Instead, when @@ -675,7 +697,7 @@ // Create the variable that will hold the construction vtable. llvm::GlobalVariable *VTable = - CGM.CreateOrReplaceCXXRuntimeVariable(Name, ArrayType, Linkage); + CGM.CreateOrReplaceCXXRuntimeVariable(Name, VTType, Linkage); CGM.setGlobalVisibility(VTable, RD); // V-tables are always unnamed_addr. @@ -928,7 +950,9 @@ std::vector BitsetEntries; // Create a bit set entry for each address point. for (auto &&AP : VTLayout.getAddressPoints()) - BitsetEntries.push_back(std::make_pair(AP.first.getBase(), AP.second)); + BitsetEntries.push_back(std::make_pair( + AP.first.getBase(), + VTLayout.getVTableIndices()[AP.second.first] + AP.second.second)); // Sort the bit set entries for determinism. std::sort(BitsetEntries.begin(), BitsetEntries.end(), Index: lib/CodeGen/ItaniumCXXABI.cpp =================================================================== --- lib/CodeGen/ItaniumCXXABI.cpp +++ lib/CodeGen/ItaniumCXXABI.cpp @@ -1515,17 +1515,20 @@ const CXXRecordDecl *VTableClass) { llvm::GlobalValue *VTable = getAddrOfVTable(VTableClass, CharUnits()); - // Find the appropriate vtable within the vtable group. - uint64_t AddressPoint = CGM.getItaniumVTableContext() - .getVTableLayout(VTableClass) - .getAddressPoint(Base); + // Find the appropriate vtable within the vtable group, and the address point + // within that vtable. + std::pair AddressPoint = CGM.getItaniumVTableContext() + .getVTableLayout(VTableClass) + .getAddressPoint(Base); llvm::Value *Indices[] = { llvm::ConstantInt::get(CGM.Int32Ty, 0), - llvm::ConstantInt::get(CGM.Int32Ty, AddressPoint) + llvm::ConstantInt::get(CGM.Int32Ty, AddressPoint.first), + llvm::ConstantInt::get(CGM.Int32Ty, AddressPoint.second), }; - return llvm::ConstantExpr::getInBoundsGetElementPtr(VTable->getValueType(), - VTable, Indices); + return llvm::ConstantExpr::getGetElementPtr(VTable->getValueType(), VTable, + Indices, /*InBounds=*/true, + /*InRangeIndex=*/1); } llvm::Value *ItaniumCXXABI::getVTableAddressPointInStructorWithVTT( @@ -1567,12 +1570,12 @@ llvm::raw_svector_ostream Out(Name); getMangleContext().mangleCXXVTable(RD, Out); - ItaniumVTableContext &VTContext = CGM.getItaniumVTableContext(); - llvm::ArrayType *ArrayType = llvm::ArrayType::get( - CGM.Int8PtrTy, VTContext.getVTableLayout(RD).vtable_components().size()); + const VTableLayout &VTLayout = + CGM.getItaniumVTableContext().getVTableLayout(RD); + llvm::Type *VTableType = CGM.getVTables().GetVTableType(RD, VTLayout); VTable = CGM.CreateOrReplaceCXXRuntimeVariable( - Name, ArrayType, llvm::GlobalValue::ExternalLinkage); + Name, VTableType, llvm::GlobalValue::ExternalLinkage); VTable->setUnnamedAddr(llvm::GlobalValue::UnnamedAddr::Global); if (RD->hasAttr()) Index: lib/CodeGen/MicrosoftCXXABI.cpp =================================================================== --- lib/CodeGen/MicrosoftCXXABI.cpp +++ lib/CodeGen/MicrosoftCXXABI.cpp @@ -1686,17 +1686,14 @@ return VTable; } - uint64_t NumVTableSlots = - VTContext.getVFTableLayout(RD, VFPtr->FullOffsetInMDC) - .vtable_components() - .size(); + const VTableLayout &VTLayout = + VTContext.getVFTableLayout(RD, VFPtr->FullOffsetInMDC); llvm::GlobalValue::LinkageTypes VTableLinkage = VTableAliasIsRequred ? llvm::GlobalValue::PrivateLinkage : VFTableLinkage; StringRef VTableName = VTableAliasIsRequred ? StringRef() : VFTableName.str(); - llvm::ArrayType *VTableType = - llvm::ArrayType::get(CGM.Int8PtrTy, NumVTableSlots); + llvm::Type *VTableType = CGM.getVTables().GetVTableType(RD, VTLayout); // Create a backing variable for the contents of VTable. The VTable may // or may not include space for a pointer to RTTI data. @@ -1717,8 +1714,9 @@ // importing it. We never reference the RTTI data directly so there is no // need to make room for it. if (VTableAliasIsRequred) { - llvm::Value *GEPIndices[] = {llvm::ConstantInt::get(CGM.IntTy, 0), - llvm::ConstantInt::get(CGM.IntTy, 1)}; + llvm::Value *GEPIndices[] = {llvm::ConstantInt::get(CGM.Int32Ty, 0), + llvm::ConstantInt::get(CGM.Int32Ty, 0), + llvm::ConstantInt::get(CGM.Int32Ty, 1)}; // Create a GEP which points just after the first entry in the VFTable, // this should be the location of the first virtual method. llvm::Constant *VTableGEP = llvm::ConstantExpr::getInBoundsGetElementPtr(