emitThunk(GD, (*ThunkInfoVector)[I], /*ForVTable=*/false);
}
-llvm::Constant *
-CodeGenVTables::CreateVTableInitializer(const CXXRecordDecl *RD,
- const VTableComponent *Components,
- unsigned NumComponents,
- const VTableLayout::VTableThunkTy *VTableThunks,
- unsigned NumVTableThunks) {
+llvm::Constant *CodeGenVTables::CreateVTableInitializer(
+ const CXXRecordDecl *RD, const VTableComponent *Components,
+ unsigned NumComponents, const VTableLayout::VTableThunkTy *VTableThunks,
+ unsigned NumVTableThunks, llvm::Constant *RTTI) {
SmallVector<llvm::Constant *, 64> Inits;
llvm::Type *Int8PtrTy = CGM.Int8PtrTy;
llvm::Type *PtrDiffTy =
CGM.getTypes().ConvertType(CGM.getContext().getPointerDiffType());
- QualType ClassType = CGM.getContext().getTagDeclType(RD);
- llvm::Constant *RTTI = CGM.GetAddrOfRTTIDescriptor(ClassType);
-
unsigned NextVTableThunkIndex = 0;
llvm::Constant *PureVirtualFn = nullptr, *DeletedVirtualFn = nullptr;
// V-tables are always unnamed_addr.
VTable->setUnnamedAddr(true);
+ llvm::Constant *RTTI = CGM.GetAddrOfRTTIDescriptor(
+ CGM.getContext().getTagDeclType(Base.getBase()));
+
// Create and set the initializer.
- llvm::Constant *Init =
- CreateVTableInitializer(Base.getBase(),
- VTLayout->vtable_component_begin(),
- VTLayout->getNumVTableComponents(),
- VTLayout->vtable_thunk_begin(),
- VTLayout->getNumVTableThunks());
+ llvm::Constant *Init = CreateVTableInitializer(
+ Base.getBase(), VTLayout->vtable_component_begin(),
+ VTLayout->getNumVTableComponents(), VTLayout->vtable_thunk_begin(),
+ VTLayout->getNumVTableThunks(), RTTI);
VTable->setInitializer(Init);
return VTable;
private:
typedef std::pair<const CXXRecordDecl *, CharUnits> VFTableIdTy;
- typedef llvm::DenseMap<VFTableIdTy, llvm::GlobalVariable *> VFTablesMapTy;
+ typedef llvm::DenseMap<VFTableIdTy, llvm::GlobalVariable *> VTablesMapTy;
+ typedef llvm::DenseMap<VFTableIdTy, llvm::GlobalValue *> VFTablesMapTy;
/// \brief All the vftables that have been referenced.
VFTablesMapTy VFTablesMap;
+ VTablesMapTy VTablesMap;
/// \brief This set holds the record decls we've deferred vtable emission for.
llvm::SmallPtrSet<const CXXRecordDecl *, 4> DeferredVFTables;
const CXXRecordDecl *RD) {
MicrosoftVTableContext &VFTContext = CGM.getMicrosoftVTableContext();
VPtrInfoVector VFPtrs = VFTContext.getVFPtrOffsets(RD);
- llvm::GlobalVariable::LinkageTypes Linkage = CGM.getVTableLinkage(RD);
for (VPtrInfo *Info : VFPtrs) {
llvm::GlobalVariable *VTable = getAddrOfVTable(RD, Info->FullOffsetInMDC);
if (VTable->hasInitializer())
continue;
- if (getContext().getLangOpts().RTTI)
- CGM.getMSCompleteObjectLocator(RD, Info);
+
+ llvm::Constant *RTTI = CGM.getMSCompleteObjectLocator(RD, Info);
const VTableLayout &VTLayout =
VFTContext.getVFTableLayout(RD, Info->FullOffsetInMDC);
llvm::Constant *Init = CGVT.CreateVTableInitializer(
RD, VTLayout.vtable_component_begin(),
VTLayout.getNumVTableComponents(), VTLayout.vtable_thunk_begin(),
- VTLayout.getNumVTableThunks());
- VTable->setInitializer(Init);
+ VTLayout.getNumVTableThunks(), RTTI);
- VTable->setLinkage(Linkage);
-
- CGM.setGlobalVisibility(VTable, RD);
+ VTable->setInitializer(Init);
}
}
const CXXRecordDecl *NearestVBase, bool &NeedsVirtualOffset) {
NeedsVirtualOffset = (NearestVBase != nullptr);
- llvm::Value *VTableAddressPoint =
- getAddrOfVTable(VTableClass, Base.getBaseOffset());
+ (void)getAddrOfVTable(VTableClass, Base.getBaseOffset());
+ VFTableIdTy ID(VTableClass, Base.getBaseOffset());
+ llvm::GlobalValue *VTableAddressPoint = VFTablesMap[ID];
if (!VTableAddressPoint) {
assert(Base.getBase()->getNumVBases() &&
!CGM.getContext().getASTRecordLayout(Base.getBase()).hasOwnVFPtr());
llvm::Constant *MicrosoftCXXABI::getVTableAddressPointForConstExpr(
BaseSubobject Base, const CXXRecordDecl *VTableClass) {
- llvm::Constant *VTable = getAddrOfVTable(VTableClass, Base.getBaseOffset());
- assert(VTable && "Couldn't find a vftable for the given base?");
- return VTable;
+ (void)getAddrOfVTable(VTableClass, Base.getBaseOffset());
+ VFTableIdTy ID(VTableClass, Base.getBaseOffset());
+ llvm::GlobalValue *VFTable = VFTablesMap[ID];
+ assert(VFTable && "Couldn't find a vftable for the given base?");
+ return VFTable;
}
llvm::GlobalVariable *MicrosoftCXXABI::getAddrOfVTable(const CXXRecordDecl *RD,
// shouldn't be used in the given record type. We want to cache this result in
// VFTablesMap, thus a simple zero check is not sufficient.
VFTableIdTy ID(RD, VPtrOffset);
- VFTablesMapTy::iterator I;
+ VTablesMapTy::iterator I;
bool Inserted;
- std::tie(I, Inserted) = VFTablesMap.insert(std::make_pair(ID, nullptr));
+ std::tie(I, Inserted) = VTablesMap.insert(std::make_pair(ID, nullptr));
if (!Inserted)
return I->second;
for (size_t J = 0, F = VFPtrs.size(); J != F; ++J) {
if (VFPtrs[J]->FullOffsetInMDC != VPtrOffset)
continue;
+ SmallString<256> VFTableName;
+ mangleVFTableName(getMangleContext(), RD, VFPtrs[J], VFTableName);
+ StringRef VTableName = VFTableName;
- llvm::ArrayType *ArrayType = llvm::ArrayType::get(
- CGM.Int8PtrTy,
+ uint64_t NumVTableSlots =
VTContext.getVFTableLayout(RD, VFPtrs[J]->FullOffsetInMDC)
- .getNumVTableComponents());
-
- SmallString<256> Name;
- mangleVFTableName(getMangleContext(), RD, VFPtrs[J], Name);
- VTable = CGM.CreateOrReplaceCXXRuntimeVariable(
- Name.str(), ArrayType, llvm::GlobalValue::ExternalLinkage);
- VTable->setUnnamedAddr(true);
- if (RD->hasAttr<DLLImportAttr>())
- VTable->setDLLStorageClass(llvm::GlobalValue::DLLImportStorageClass);
- else if (RD->hasAttr<DLLExportAttr>())
- VTable->setDLLStorageClass(llvm::GlobalValue::DLLExportStorageClass);
+ .getNumVTableComponents();
+ llvm::GlobalValue::LinkageTypes VTableLinkage =
+ llvm::GlobalValue::ExternalLinkage;
+ llvm::ArrayType *VTableType =
+ llvm::ArrayType::get(CGM.Int8PtrTy, NumVTableSlots);
+ if (getContext().getLangOpts().RTTI) {
+ VTableLinkage = llvm::GlobalValue::PrivateLinkage;
+ VTableName = "";
+ }
+
+ VTable = CGM.getModule().getNamedGlobal(VFTableName);
+ if (!VTable) {
+ llvm::GlobalValue *VFTable = VTable = new llvm::GlobalVariable(
+ CGM.getModule(), VTableType, /*isConstant=*/true, VTableLinkage,
+ /*Initializer=*/nullptr, VTableName);
+ VTable->setUnnamedAddr(true);
+ if (getContext().getLangOpts().RTTI && !RD->hasAttr<DLLImportAttr>()) {
+ llvm::Value *GEPIndices[] = {llvm::ConstantInt::get(CGM.IntTy, 0),
+ llvm::ConstantInt::get(CGM.IntTy, 1)};
+ llvm::Constant *VTableGEP =
+ llvm::ConstantExpr::getInBoundsGetElementPtr(VTable, GEPIndices);
+ VFTable = llvm::GlobalAlias::create(
+ cast<llvm::SequentialType>(VTableGEP->getType())->getElementType(),
+ /*AddressSpace=*/0, llvm::GlobalValue::ExternalLinkage,
+ VFTableName.str(), VTableGEP, &CGM.getModule());
+ } else {
+ VTable->setName(VFTableName.str());
+ }
+
+ VFTable->setUnnamedAddr(true);
+ if (RD->hasAttr<DLLImportAttr>())
+ VFTable->setDLLStorageClass(llvm::GlobalValue::DLLImportStorageClass);
+ else if (RD->hasAttr<DLLExportAttr>())
+ VFTable->setDLLStorageClass(llvm::GlobalValue::DLLExportStorageClass);
+
+ llvm::GlobalValue::LinkageTypes VFTableLinkage = CGM.getVTableLinkage(RD);
+ if (VFTable != VTable) {
+ if (llvm::GlobalValue::isAvailableExternallyLinkage(VFTableLinkage)) {
+ // AvailableExternally implies that we grabbed the data from another
+ // executable. No need to stick the alias in a Comdat.
+ } else if (llvm::GlobalValue::isLocalLinkage(VFTableLinkage)) {
+ // If it's local, it means that the virtual function table can't be
+ // referenced in another translation unit. No need to stick the alias
+ // in a Comdat.
+ } else if (llvm::GlobalValue::isWeakODRLinkage(VFTableLinkage) ||
+ llvm::GlobalValue::isLinkOnceODRLinkage(VFTableLinkage)) {
+ // The alias is going to be dropped into a Comdat, no need to make it
+ // weak.
+ VFTableLinkage = llvm::GlobalValue::ExternalLinkage;
+ llvm::Comdat *C =
+ CGM.getModule().getOrInsertComdat(VFTable->getName());
+ C->setSelectionKind(llvm::Comdat::Largest);
+ VTable->setComdat(C);
+ } else {
+ llvm_unreachable("unexpected linkage for vftable!");
+ }
+ }
+ VFTable->setLinkage(VFTableLinkage);
+ CGM.setGlobalVisibility(VFTable, RD);
+ VFTablesMap[ID] = VFTable;
+ }
break;
}