Skip to content
This repository was archived by the owner on Nov 1, 2021. It is now read-only.

Commit a53d7a0

Browse files
committed
Abstract out the emission of vtables, add basic support for vtable emission when using -cxx-abi microsoft
Reviewed at http://llvm-reviews.chandlerc.com/D1532 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@191523 91177308-0d34-0410-b5e6-96231b3b80d8
1 parent acf8e90 commit a53d7a0

24 files changed

+639
-309
lines changed

include/clang/AST/Mangle.h

+8
Original file line numberDiff line numberDiff line change
@@ -106,8 +106,16 @@ class MangleContext {
106106
raw_ostream &) = 0;
107107
virtual void mangleReferenceTemporary(const VarDecl *D,
108108
raw_ostream &) = 0;
109+
// FIXME: Some of these objects only exist in select ABIs. We should probably
110+
// only declare them in ABI-specific manglers?
109111
virtual void mangleCXXVTable(const CXXRecordDecl *RD,
110112
raw_ostream &) = 0;
113+
/// \brief Mangle vftable symbols. Only a subset of the bases along the path
114+
/// to the vftable are included in the name. It's up to the caller to pick
115+
/// them correctly.
116+
virtual void mangleCXXVFTable(const CXXRecordDecl *Derived,
117+
ArrayRef<const CXXRecordDecl *> BasePath,
118+
raw_ostream &Out) = 0;
111119
virtual void mangleCXXVTT(const CXXRecordDecl *RD,
112120
raw_ostream &) = 0;
113121
/// \brief Mangle vbtable symbols. Only a subset of the bases along the path

include/clang/AST/VTableBuilder.h

+7-8
Original file line numberDiff line numberDiff line change
@@ -329,13 +329,6 @@ class VTableContext : public VTableContextBase {
329329
VTableContext(ASTContext &Context);
330330
~VTableContext();
331331

332-
bool isMicrosoftABI() const {
333-
// FIXME: Currently, this method is only used in the VTableContext and
334-
// VTableBuilder code which is ABI-specific. Probably we can remove it
335-
// when we add a layer of abstraction for vtable generation.
336-
return IsMicrosoftABI;
337-
}
338-
339332
const VTableLayout &getVTableLayout(const CXXRecordDecl *RD) {
340333
computeVTableRelatedInformation(RD);
341334
assert(VTableLayouts.count(RD) && "No layout for this record decl!");
@@ -377,11 +370,13 @@ unsigned GetVBTableIndex(const CXXRecordDecl *Derived,
377370
struct VFPtrInfo {
378371
typedef SmallVector<const CXXRecordDecl *, 1> BasePath;
379372

373+
// Don't pass the PathToMangle as it should be calculated later.
380374
VFPtrInfo(CharUnits VFPtrOffset, const BasePath &PathToBaseWithVFPtr)
381375
: VBTableIndex(0), LastVBase(0), VFPtrOffset(VFPtrOffset),
382376
PathToBaseWithVFPtr(PathToBaseWithVFPtr), VFPtrFullOffset(VFPtrOffset) {
383377
}
384378

379+
// Don't pass the PathToMangle as it should be calculated later.
385380
VFPtrInfo(uint64_t VBTableIndex, const CXXRecordDecl *LastVBase,
386381
CharUnits VFPtrOffset, const BasePath &PathToBaseWithVFPtr,
387382
CharUnits VFPtrFullOffset)
@@ -404,9 +399,13 @@ struct VFPtrInfo {
404399
CharUnits VFPtrOffset;
405400

406401
/// This holds the base classes path from the complete type to the first base
407-
/// with the given vfptr offset.
402+
/// with the given vfptr offset, in the base-to-derived order.
408403
BasePath PathToBaseWithVFPtr;
409404

405+
/// This holds the subset of records that need to be mangled into the vftable
406+
/// symbol name in order to get a unique name, in the derived-to-base order.
407+
BasePath PathToMangle;
408+
410409
/// This is the full offset of the vfptr from the start of the complete type.
411410
CharUnits VFPtrFullOffset;
412411
};

lib/AST/ItaniumMangle.cpp

+11
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,9 @@ class ItaniumMangleContext : public MangleContext {
137137
raw_ostream &);
138138
void mangleCXXVTable(const CXXRecordDecl *RD,
139139
raw_ostream &);
140+
void mangleCXXVFTable(const CXXRecordDecl *Derived,
141+
ArrayRef<const CXXRecordDecl *> BasePath,
142+
raw_ostream &Out);
140143
void mangleCXXVTT(const CXXRecordDecl *RD,
141144
raw_ostream &);
142145
void mangleCXXVBTable(const CXXRecordDecl *Derived,
@@ -3772,6 +3775,14 @@ void ItaniumMangleContext::mangleCXXVTable(const CXXRecordDecl *RD,
37723775
Mangler.mangleNameOrStandardSubstitution(RD);
37733776
}
37743777

3778+
void
3779+
ItaniumMangleContext::mangleCXXVFTable(const CXXRecordDecl *Derived,
3780+
ArrayRef<const CXXRecordDecl *> BasePath,
3781+
raw_ostream &Out) {
3782+
llvm_unreachable(
3783+
"The Itanium C++ ABI does not have vftables (use vtables instead)!");
3784+
}
3785+
37753786
void ItaniumMangleContext::mangleCXXVTT(const CXXRecordDecl *RD,
37763787
raw_ostream &Out) {
37773788
// <special-name> ::= TT <type> # VTT structure

lib/AST/MicrosoftMangle.cpp

+17-4
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,9 @@ class MicrosoftMangleContext : public MangleContext {
188188
raw_ostream &);
189189
virtual void mangleCXXVTable(const CXXRecordDecl *RD,
190190
raw_ostream &);
191+
virtual void mangleCXXVFTable(const CXXRecordDecl *Derived,
192+
ArrayRef<const CXXRecordDecl *> BasePath,
193+
raw_ostream &Out);
191194
virtual void mangleCXXVTT(const CXXRecordDecl *RD,
192195
raw_ostream &);
193196
virtual void mangleCXXVBTable(const CXXRecordDecl *Derived,
@@ -1900,16 +1903,26 @@ void MicrosoftMangleContext::mangleCXXDtorThunk(const CXXDestructorDecl *DD,
19001903

19011904
void MicrosoftMangleContext::mangleCXXVTable(const CXXRecordDecl *RD,
19021905
raw_ostream &Out) {
1906+
llvm_unreachable(
1907+
"The Microsoft C++ ABI does not have vtables (use vftables instead)!");
1908+
}
1909+
1910+
void MicrosoftMangleContext::mangleCXXVFTable(
1911+
const CXXRecordDecl *Derived, ArrayRef<const CXXRecordDecl *> BasePath,
1912+
raw_ostream &Out) {
19031913
// <mangled-name> ::= ?_7 <class-name> <storage-class>
19041914
// <cvr-qualifiers> [<name>] @
19051915
// NOTE: <cvr-qualifiers> here is always 'B' (const). <storage-class>
19061916
// is always '6' for vftables.
19071917
MicrosoftCXXNameMangler Mangler(*this, Out);
19081918
Mangler.getStream() << "\01??_7";
1909-
Mangler.mangleName(RD);
1910-
Mangler.getStream() << "6B"; // '6' for vftable, 'B' for const.
1911-
// TODO: If the class has more than one vtable, mangle in the class it came
1912-
// from.
1919+
Mangler.mangleName(Derived);
1920+
Mangler.getStream() << "6B"; // '6' for vftable, 'B' for const.
1921+
for (ArrayRef<const CXXRecordDecl *>::iterator I = BasePath.begin(),
1922+
E = BasePath.end();
1923+
I != E; ++I) {
1924+
Mangler.mangleName(*I);
1925+
}
19131926
Mangler.getStream() << '@';
19141927
}
19151928

lib/AST/VTableBuilder.cpp

+74-52
Original file line numberDiff line numberDiff line change
@@ -999,10 +999,6 @@ class VTableBuilder {
999999
dumpLayout(llvm::errs());
10001000
}
10011001

1002-
bool isMicrosoftABI() const {
1003-
return VTables.isMicrosoftABI();
1004-
}
1005-
10061002
uint64_t getNumThunks() const {
10071003
return Thunks.size();
10081004
}
@@ -1157,7 +1153,7 @@ void VTableBuilder::ComputeThisAdjustments() {
11571153
// Add it.
11581154
VTableThunks[VTableIndex].This = ThisAdjustment;
11591155

1160-
if (isa<CXXDestructorDecl>(MD) && !isMicrosoftABI()) {
1156+
if (isa<CXXDestructorDecl>(MD)) {
11611157
// Add an adjustment for the deleting destructor as well.
11621158
VTableThunks[VTableIndex + 1].This = ThisAdjustment;
11631159
}
@@ -1188,8 +1184,6 @@ void VTableBuilder::ComputeThisAdjustments() {
11881184
break;
11891185
case VTableComponent::CK_DeletingDtorPointer:
11901186
// We've already added the thunk when we saw the complete dtor pointer.
1191-
// FIXME: check how this works in the Microsoft ABI
1192-
// while working on the multiple inheritance patch.
11931187
continue;
11941188
}
11951189

@@ -1326,15 +1320,9 @@ VTableBuilder::AddMethod(const CXXMethodDecl *MD,
13261320
assert(ReturnAdjustment.isEmpty() &&
13271321
"Destructor can't have return adjustment!");
13281322

1329-
// FIXME: Should probably add a layer of abstraction for vtable generation.
1330-
if (!isMicrosoftABI()) {
1331-
// Add both the complete destructor and the deleting destructor.
1332-
Components.push_back(VTableComponent::MakeCompleteDtor(DD));
1333-
Components.push_back(VTableComponent::MakeDeletingDtor(DD));
1334-
} else {
1335-
// Add the scalar deleting destructor.
1336-
Components.push_back(VTableComponent::MakeDeletingDtor(DD));
1337-
}
1323+
// Add both the complete destructor and the deleting destructor.
1324+
Components.push_back(VTableComponent::MakeCompleteDtor(DD));
1325+
Components.push_back(VTableComponent::MakeDeletingDtor(DD));
13381326
} else {
13391327
// Add the return adjustment if necessary.
13401328
if (!ReturnAdjustment.isEmpty())
@@ -1693,18 +1681,12 @@ VTableBuilder::LayoutPrimaryAndSecondaryVTables(BaseSubobject Base,
16931681
if (Base.getBase() == MostDerivedClass)
16941682
VBaseOffsetOffsets = Builder.getVBaseOffsetOffsets();
16951683

1696-
// FIXME: Should probably add a layer of abstraction for vtable generation.
1697-
if (!isMicrosoftABI()) {
1698-
// Add the offset to top.
1699-
CharUnits OffsetToTop = MostDerivedClassOffset - OffsetInLayoutClass;
1700-
Components.push_back(VTableComponent::MakeOffsetToTop(OffsetToTop));
1684+
// Add the offset to top.
1685+
CharUnits OffsetToTop = MostDerivedClassOffset - OffsetInLayoutClass;
1686+
Components.push_back(VTableComponent::MakeOffsetToTop(OffsetToTop));
17011687

1702-
// Next, add the RTTI.
1703-
Components.push_back(VTableComponent::MakeRTTI(MostDerivedClass));
1704-
} else {
1705-
// FIXME: unclear what to do with RTTI in MS ABI as emitting it anywhere
1706-
// breaks the vftable layout. Just skip RTTI for now, can't mangle anyway.
1707-
}
1688+
// Next, add the RTTI.
1689+
Components.push_back(VTableComponent::MakeRTTI(MostDerivedClass));
17081690

17091691
uint64_t AddressPoint = Components.size();
17101692

@@ -1722,16 +1704,10 @@ VTableBuilder::LayoutPrimaryAndSecondaryVTables(BaseSubobject Base,
17221704
const CXXMethodDecl *MD = I->first;
17231705
const MethodInfo &MI = I->second;
17241706
if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(MD)) {
1725-
// FIXME: Should probably add a layer of abstraction for vtable generation.
1726-
if (!isMicrosoftABI()) {
1727-
MethodVTableIndices[GlobalDecl(DD, Dtor_Complete)]
1728-
= MI.VTableIndex - AddressPoint;
1729-
MethodVTableIndices[GlobalDecl(DD, Dtor_Deleting)]
1730-
= MI.VTableIndex + 1 - AddressPoint;
1731-
} else {
1732-
MethodVTableIndices[GlobalDecl(DD, Dtor_Deleting)]
1733-
= MI.VTableIndex - AddressPoint;
1734-
}
1707+
MethodVTableIndices[GlobalDecl(DD, Dtor_Complete)]
1708+
= MI.VTableIndex - AddressPoint;
1709+
MethodVTableIndices[GlobalDecl(DD, Dtor_Deleting)]
1710+
= MI.VTableIndex + 1 - AddressPoint;
17351711
} else {
17361712
MethodVTableIndices[MD] = MI.VTableIndex - AddressPoint;
17371713
}
@@ -2044,8 +2020,6 @@ void VTableBuilder::dumpLayout(raw_ostream& Out) {
20442020
Out << DD->getQualifiedNameAsString();
20452021
if (IsComplete)
20462022
Out << "() [complete]";
2047-
else if (isMicrosoftABI())
2048-
Out << "() [scalar deleting]";
20492023
else
20502024
Out << "() [deleting]";
20512025

@@ -2230,18 +2204,11 @@ void VTableBuilder::dumpLayout(raw_ostream& Out) {
22302204
MD);
22312205

22322206
if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(MD)) {
2233-
// FIXME: Should add a layer of abstraction for vtable generation.
2234-
if (!isMicrosoftABI()) {
2235-
GlobalDecl GD(DD, Dtor_Complete);
2236-
assert(MethodVTableIndices.count(GD));
2237-
uint64_t VTableIndex = MethodVTableIndices[GD];
2238-
IndicesMap[VTableIndex] = MethodName + " [complete]";
2239-
IndicesMap[VTableIndex + 1] = MethodName + " [deleting]";
2240-
} else {
2241-
GlobalDecl GD(DD, Dtor_Deleting);
2242-
assert(MethodVTableIndices.count(GD));
2243-
IndicesMap[MethodVTableIndices[GD]] = MethodName + " [scalar deleting]";
2244-
}
2207+
GlobalDecl GD(DD, Dtor_Complete);
2208+
assert(MethodVTableIndices.count(GD));
2209+
uint64_t VTableIndex = MethodVTableIndices[GD];
2210+
IndicesMap[VTableIndex] = MethodName + " [complete]";
2211+
IndicesMap[VTableIndex + 1] = MethodName + " [deleting]";
22452212
} else {
22462213
assert(MethodVTableIndices.count(MD));
22472214
IndicesMap[MethodVTableIndices[MD]] = MethodName;
@@ -2352,10 +2319,12 @@ static VTableLayout *CreateVTableLayout(const VTableBuilder &Builder) {
23522319
VTableThunks.size(),
23532320
VTableThunks.data(),
23542321
Builder.getAddressPoints(),
2355-
Builder.isMicrosoftABI());
2322+
/*IsMicrosoftABI=*/false);
23562323
}
23572324

23582325
void VTableContext::computeVTableRelatedInformation(const CXXRecordDecl *RD) {
2326+
assert(!IsMicrosoftABI && "Shouldn't be called in this ABI!");
2327+
23592328
const VTableLayout *&Entry = VTableLayouts[RD];
23602329

23612330
// Check if we've computed this information before.
@@ -3132,6 +3101,55 @@ static void EnumerateVFPtrs(
31323101
}
31333102
}
31343103

3104+
/// CalculatePathToMangle - Calculate the subset of records that should be used
3105+
/// to mangle the vftable for the given vfptr.
3106+
/// Should only be called if a class has multiple vftables.
3107+
static void
3108+
CalculatePathToMangle(const CXXRecordDecl *RD, VFPtrInfo &VFPtr) {
3109+
// FIXME: In some rare cases this code produces a slightly incorrect mangling.
3110+
// It's very likely that the vbtable mangling code can be adjusted to mangle
3111+
// both vftables and vbtables correctly.
3112+
3113+
VFPtrInfo::BasePath &FullPath = VFPtr.PathToBaseWithVFPtr;
3114+
if (FullPath.empty()) {
3115+
// Mangle the class's own vftable.
3116+
assert(RD->getNumVBases() &&
3117+
"Something's wrong: if the most derived "
3118+
"class has more than one vftable, it can only have its own "
3119+
"vftable if it has vbases");
3120+
VFPtr.PathToMangle.push_back(RD);
3121+
return;
3122+
}
3123+
3124+
unsigned Begin = 0;
3125+
3126+
// First, skip all the bases before the vbase.
3127+
if (VFPtr.LastVBase) {
3128+
while (FullPath[Begin] != VFPtr.LastVBase) {
3129+
Begin++;
3130+
assert(Begin < FullPath.size());
3131+
}
3132+
}
3133+
3134+
// Then, put the rest of the base path in the reverse order.
3135+
for (unsigned I = FullPath.size(); I != Begin; --I) {
3136+
const CXXRecordDecl *CurBase = FullPath[I - 1],
3137+
*ItsBase = (I == 1) ? RD : FullPath[I - 2];
3138+
bool BaseIsVirtual = false;
3139+
for (CXXRecordDecl::base_class_const_iterator J = ItsBase->bases_begin(),
3140+
F = ItsBase->bases_end(); J != F; ++J) {
3141+
if (J->getType()->getAsCXXRecordDecl() == CurBase) {
3142+
BaseIsVirtual = J->isVirtual();
3143+
break;
3144+
}
3145+
}
3146+
3147+
// Should skip the current base if it is a non-virtual base with no siblings.
3148+
if (BaseIsVirtual || ItsBase->getNumBases() != 1)
3149+
VFPtr.PathToMangle.push_back(CurBase);
3150+
}
3151+
}
3152+
31353153
static void EnumerateVFPtrs(ASTContext &Context, const CXXRecordDecl *ForClass,
31363154
MicrosoftVFTableContext::VFPtrListTy &Result) {
31373155
Result.clear();
@@ -3140,6 +3158,10 @@ static void EnumerateVFPtrs(ASTContext &Context, const CXXRecordDecl *ForClass,
31403158
EnumerateVFPtrs(Context, ForClass, ClassLayout,
31413159
BaseSubobject(ForClass, CharUnits::Zero()), 0,
31423160
VFPtrInfo::BasePath(), VisitedVBases, Result);
3161+
if (Result.size() > 1) {
3162+
for (unsigned I = 0, E = Result.size(); I != E; ++I)
3163+
CalculatePathToMangle(ForClass, Result[I]);
3164+
}
31433165
}
31443166

31453167
void MicrosoftVFTableContext::computeVTableRelatedInformation(

lib/CodeGen/CGCXX.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -280,7 +280,7 @@ static llvm::Value *BuildAppleKextVirtualCall(CodeGenFunction &CGF,
280280
"No kext in Microsoft ABI");
281281
GD = GD.getCanonicalDecl();
282282
CodeGenModule &CGM = CGF.CGM;
283-
llvm::Value *VTable = CGM.getVTables().GetAddrOfVTable(RD);
283+
llvm::Value *VTable = CGM.getCXXABI().getAddrOfVTable(RD, CharUnits());
284284
Ty = Ty->getPointerTo()->getPointerTo();
285285
VTable = CGF.Builder.CreateBitCast(VTable, Ty);
286286
assert(VTable && "BuildVirtualCall = kext vtbl pointer is null");

lib/CodeGen/CGCXXABI.h

+24-3
Original file line numberDiff line numberDiff line change
@@ -303,6 +303,29 @@ class CGCXXABI {
303303
CallExpr::const_arg_iterator ArgBeg,
304304
CallExpr::const_arg_iterator ArgEnd) = 0;
305305

306+
/// Emits the VTable definitions required for the given record type.
307+
virtual void emitVTableDefinitions(CodeGenVTables &CGVT,
308+
const CXXRecordDecl *RD) = 0;
309+
310+
/// Get the address point of the vtable for the given base subobject while
311+
/// building a constructor or a destructor. On return, NeedsVirtualOffset
312+
/// tells if a virtual base adjustment is needed in order to get the offset
313+
/// of the base subobject.
314+
virtual llvm::Value *getVTableAddressPointInStructor(
315+
CodeGenFunction &CGF, const CXXRecordDecl *RD, BaseSubobject Base,
316+
const CXXRecordDecl *NearestVBase, bool &NeedsVirtualOffset) = 0;
317+
318+
/// Get the address point of the vtable for the given base subobject while
319+
/// building a constexpr.
320+
virtual llvm::Constant *
321+
getVTableAddressPointForConstExpr(BaseSubobject Base,
322+
const CXXRecordDecl *VTableClass) = 0;
323+
324+
/// Get the address of the vtable for the given record decl which should be
325+
/// used for the vptr at the given offset in RD.
326+
virtual llvm::GlobalVariable *getAddrOfVTable(const CXXRecordDecl *RD,
327+
CharUnits VPtrOffset) = 0;
328+
306329
/// Build a virtual function pointer in the ABI-specific way.
307330
virtual llvm::Value *getVirtualFunctionPointer(CodeGenFunction &CGF,
308331
GlobalDecl GD,
@@ -319,9 +342,7 @@ class CGCXXABI {
319342
/// Emit any tables needed to implement virtual inheritance. For Itanium,
320343
/// this emits virtual table tables. For the MSVC++ ABI, this emits virtual
321344
/// base tables.
322-
virtual void
323-
EmitVirtualInheritanceTables(llvm::GlobalVariable::LinkageTypes Linkage,
324-
const CXXRecordDecl *RD) = 0;
345+
virtual void emitVirtualInheritanceTables(const CXXRecordDecl *RD) = 0;
325346

326347
virtual void EmitReturnFromThunk(CodeGenFunction &CGF,
327348
RValue RV, QualType ResultType);

0 commit comments

Comments
 (0)