19 #include "llvm/ADT/SetOperations.h"
20 #include "llvm/ADT/SetVector.h"
21 #include "llvm/ADT/SmallPtrSet.h"
22 #include "llvm/Support/Format.h"
23 #include "llvm/Support/raw_ostream.h"
27 using namespace clang;
29 #define DUMP_OVERRIDERS 0
50 BaseOffset() : DerivedClass(
nullptr), VirtualBase(
nullptr),
54 : DerivedClass(DerivedClass), VirtualBase(VirtualBase),
55 NonVirtualOffset(NonVirtualOffset) { }
57 bool isEmpty()
const {
return NonVirtualOffset.
isZero() && !VirtualBase; }
62 class FinalOverriders {
65 struct OverriderInfo {
76 OverriderInfo() : Method(
nullptr), VirtualBase(
nullptr),
102 typedef std::pair<const CXXMethodDecl *, CharUnits> MethodBaseOffsetPairTy;
104 typedef llvm::DenseMap<MethodBaseOffsetPairTy,
105 OverriderInfo> OverridersMapTy;
109 OverridersMapTy OverridersMap;
114 typedef llvm::DenseMap<std::pair<const CXXRecordDecl *, unsigned>,
117 typedef llvm::DenseMap<const CXXRecordDecl *, unsigned> SubobjectCountMapTy;
123 SubobjectOffsetMapTy &SubobjectOffsets,
124 SubobjectOffsetMapTy &SubobjectLayoutClassOffsets,
125 SubobjectCountMapTy &SubobjectCounts);
132 VisitedVirtualBasesSetTy& VisitedVirtualBases);
143 assert(OverridersMap.count(std::make_pair(MD, BaseOffset)) &&
144 "Did not find overrider!");
146 return OverridersMap.lookup(std::make_pair(MD, BaseOffset));
151 VisitedVirtualBasesSetTy VisitedVirtualBases;
153 VisitedVirtualBases);
158 FinalOverriders::FinalOverriders(
const CXXRecordDecl *MostDerivedClass,
161 : MostDerivedClass(MostDerivedClass),
162 MostDerivedClassOffset(MostDerivedClassOffset), LayoutClass(LayoutClass),
167 SubobjectOffsetMapTy SubobjectOffsets;
168 SubobjectOffsetMapTy SubobjectLayoutClassOffsets;
169 SubobjectCountMapTy SubobjectCounts;
172 MostDerivedClassOffset,
173 SubobjectOffsets, SubobjectLayoutClassOffsets,
180 for (
const auto &Overrider : FinalOverriders) {
184 for (
const auto &M : Methods) {
185 unsigned SubobjectNumber = M.first;
186 assert(SubobjectOffsets.count(std::make_pair(MD->
getParent(),
188 "Did not find subobject offset!");
193 assert(M.second.size() == 1 &&
"Final overrider is not unique!");
197 assert(SubobjectLayoutClassOffsets.count(
198 std::make_pair(OverriderRD, Method.
Subobject))
199 &&
"Did not find subobject offset!");
201 SubobjectLayoutClassOffsets[std::make_pair(OverriderRD,
204 OverriderInfo& Overrider = OverridersMap[std::make_pair(MD, BaseOffset)];
205 assert(!Overrider.Method &&
"Overrider should not exist yet!");
207 Overrider.Offset = OverriderOffset;
208 Overrider.Method = Method.
Method;
219 static BaseOffset ComputeBaseOffset(
const ASTContext &Context,
224 unsigned NonVirtualStart = 0;
228 for (
int I = Path.size(), E = 0; I != E; --I) {
240 for (
unsigned I = NonVirtualStart, E = Path.size(); I != E; ++I) {
254 return BaseOffset(DerivedRD, VirtualBase, NonVirtualOffset);
258 static BaseOffset ComputeBaseOffset(
const ASTContext &Context,
265 llvm_unreachable(
"Class must be derived from the passed in base class!");
267 return ComputeBaseOffset(Context, DerivedRD, Paths.front());
271 ComputeReturnAdjustmentBaseOffset(
ASTContext &Context,
283 assert(CanDerivedReturnType->getTypeClass() ==
284 CanBaseReturnType->getTypeClass() &&
285 "Types must have same type class!");
287 if (CanDerivedReturnType == CanBaseReturnType) {
292 if (isa<ReferenceType>(CanDerivedReturnType)) {
293 CanDerivedReturnType =
294 CanDerivedReturnType->getAs<
ReferenceType>()->getPointeeType();
297 }
else if (isa<PointerType>(CanDerivedReturnType)) {
298 CanDerivedReturnType =
299 CanDerivedReturnType->getAs<
PointerType>()->getPointeeType();
303 llvm_unreachable(
"Unexpected return type!");
309 if (CanDerivedReturnType.getUnqualifiedType() ==
316 cast<CXXRecordDecl>(cast<RecordType>(CanDerivedReturnType)->getDecl());
319 cast<CXXRecordDecl>(cast<RecordType>(CanBaseReturnType)->getDecl());
321 return ComputeBaseOffset(Context, BaseRD, DerivedRD);
327 SubobjectOffsetMapTy &SubobjectOffsets,
328 SubobjectOffsetMapTy &SubobjectLayoutClassOffsets,
329 SubobjectCountMapTy &SubobjectCounts) {
332 unsigned SubobjectNumber = 0;
334 SubobjectNumber = ++SubobjectCounts[RD];
337 assert(!SubobjectOffsets.count(std::make_pair(RD, SubobjectNumber))
338 &&
"Subobject offset already exists!");
339 assert(!SubobjectLayoutClassOffsets.count(std::make_pair(RD, SubobjectNumber))
340 &&
"Subobject offset already exists!");
342 SubobjectOffsets[std::make_pair(RD, SubobjectNumber)] =
Base.getBaseOffset();
343 SubobjectLayoutClassOffsets[std::make_pair(RD, SubobjectNumber)] =
347 for (
const auto &B : RD->
bases()) {
348 const CXXRecordDecl *BaseDecl = B.getType()->getAsCXXRecordDecl();
354 if (SubobjectOffsets.count(std::make_pair(BaseDecl, 0)))
360 BaseOffset = MostDerivedClassLayout.getVBaseClassOffset(BaseDecl);
361 BaseOffsetInLayoutClass =
368 BaseOffsetInLayoutClass = OffsetInLayoutClass +
Offset;
372 B.isVirtual(), BaseOffsetInLayoutClass,
373 SubobjectOffsets, SubobjectLayoutClassOffsets,
379 VisitedVirtualBasesSetTy &VisitedVirtualBases) {
383 for (
const auto &B : RD->
bases()) {
384 const CXXRecordDecl *BaseDecl = B.getType()->getAsCXXRecordDecl();
392 if (!VisitedVirtualBases.insert(BaseDecl).second) {
397 BaseOffset = MostDerivedClassLayout.getVBaseClassOffset(BaseDecl);
405 Out <<
"Final overriders for (";
408 Out <<
Base.getBaseOffset().getQuantity() <<
")\n";
411 for (
const auto *MD : RD->
methods()) {
414 MD = MD->getCanonicalDecl();
416 OverriderInfo Overrider = getOverrider(MD,
Base.getBaseOffset());
419 MD->printQualifiedName(Out);
421 Overrider.Method->printQualifiedName(Out);
422 Out <<
", " << Overrider.Offset.getQuantity() <<
')';
425 if (!Overrider.Method->isPure())
426 Offset = ComputeReturnAdjustmentBaseOffset(Context, Overrider.Method, MD);
429 Out <<
" [ret-adj: ";
431 Offset.VirtualBase->printQualifiedName(Out);
435 Out <<
Offset.NonVirtualOffset.getQuantity() <<
" nv]";
443 struct VCallOffsetMap {
445 typedef std::pair<const CXXMethodDecl *, CharUnits> MethodAndOffsetPairTy;
453 static bool MethodsCanShareVCallOffset(
const CXXMethodDecl *LHS,
467 bool empty()
const {
return Offsets.empty(); }
470 static bool HasSameVirtualSignature(
const CXXMethodDecl *LHS,
478 if (
LT == RT)
return true;
488 bool VCallOffsetMap::MethodsCanShareVCallOffset(
const CXXMethodDecl *LHS,
494 if (isa<CXXDestructorDecl>(LHS))
495 return isa<CXXDestructorDecl>(RHS);
502 if (LHSName != RHSName)
506 return HasSameVirtualSignature(LHS, RHS);
512 for (
const auto &OffsetPair : Offsets) {
513 if (MethodsCanShareVCallOffset(OffsetPair.first, MD))
518 Offsets.push_back(MethodAndOffsetPairTy(MD, OffsetOffset));
524 for (
const auto &OffsetPair : Offsets) {
525 if (MethodsCanShareVCallOffset(OffsetPair.first, MD))
526 return OffsetPair.second;
529 llvm_unreachable(
"Should always find a vcall offset offset!");
533 class VCallAndVBaseOffsetBuilder {
535 typedef llvm::DenseMap<const CXXRecordDecl *, CharUnits>
536 VBaseOffsetOffsetsMapTy;
555 VTableComponentVectorTy Components;
561 VCallOffsetMap VCallOffsets;
566 VBaseOffsetOffsetsMapTy VBaseOffsetOffsets;
570 const FinalOverriders *Overriders;
586 CharUnits getCurrentOffsetOffset()
const;
592 const FinalOverriders *Overriders,
595 : VTables(VTables), MostDerivedClass(MostDerivedClass),
596 LayoutClass(LayoutClass), Context(MostDerivedClass->
getASTContext()),
597 Overriders(Overriders) {
600 AddVCallAndVBaseOffsets(
Base, BaseIsVirtual, OffsetInLayoutClass);
604 typedef VTableComponentVectorTy::const_reverse_iterator const_iterator;
605 const_iterator components_begin()
const {
return Components.rbegin(); }
606 const_iterator components_end()
const {
return Components.rend(); }
608 const VCallOffsetMap &getVCallOffsets()
const {
return VCallOffsets; }
609 const VBaseOffsetOffsetsMapTy &getVBaseOffsetOffsets()
const {
610 return VBaseOffsetOffsets;
635 if (PrimaryBaseIsVirtual) {
637 "Primary vbase should have a zero offset!");
646 "Primary base should have a zero offset!");
648 PrimaryBaseOffset =
Base.getBaseOffset();
651 AddVCallAndVBaseOffsets(
653 PrimaryBaseIsVirtual, RealBaseOffset);
656 AddVBaseOffsets(
Base.getBase(), RealBaseOffset);
660 AddVCallOffsets(
Base, RealBaseOffset);
663 CharUnits VCallAndVBaseOffsetBuilder::getCurrentOffsetOffset()
const {
673 VTables.isRelativeLayout() ? 32
675 CharUnits OffsetOffset = OffsetWidth * OffsetIndex;
693 "Primary base should have a zero offset!");
700 for (
const auto *MD : RD->
methods()) {
705 CharUnits OffsetOffset = getCurrentOffsetOffset();
709 if (!VCallOffsets.AddVCallOffset(MD, OffsetOffset))
716 FinalOverriders::OverriderInfo Overrider =
717 Overriders->getOverrider(MD,
Base.getBaseOffset());
721 Offset = Overrider.Offset - VBaseOffset;
724 Components.push_back(
729 for (
const auto &B : RD->
bases()) {
733 const CXXRecordDecl *BaseDecl = B.getType()->getAsCXXRecordDecl();
734 if (BaseDecl == PrimaryBase)
747 VCallAndVBaseOffsetBuilder::AddVBaseOffsets(
const CXXRecordDecl *RD,
753 for (
const auto &B : RD->
bases()) {
754 const CXXRecordDecl *BaseDecl = B.getType()->getAsCXXRecordDecl();
757 if (B.isVirtual() && VisitedVirtualBases.insert(BaseDecl).second) {
762 assert(!VBaseOffsetOffsets.count(BaseDecl) &&
763 "vbase offset offset already exists!");
765 CharUnits VBaseOffsetOffset = getCurrentOffsetOffset();
766 VBaseOffsetOffsets.insert(
767 std::make_pair(BaseDecl, VBaseOffsetOffset));
769 Components.push_back(
774 AddVBaseOffsets(BaseDecl, OffsetInLayoutClass);
779 class ItaniumVTableBuilder {
784 PrimaryBasesSetVectorTy;
786 typedef llvm::DenseMap<const CXXRecordDecl *, CharUnits>
787 VBaseOffsetOffsetsMapTy;
791 typedef llvm::DenseMap<GlobalDecl, int64_t> MethodVTableIndicesTy;
807 bool MostDerivedClassIsVirtual;
818 const FinalOverriders Overriders;
822 llvm::DenseMap<const CXXRecordDecl *, VCallOffsetMap> VCallOffsetsForVBases;
826 VBaseOffsetOffsetsMapTy VBaseOffsetOffsets;
832 AddressPointsMapTy AddressPoints;
850 : BaseOffset(BaseOffset),
851 BaseOffsetInLayoutClass(BaseOffsetInLayoutClass),
852 VTableIndex(VTableIndex) { }
859 MethodInfo(MethodInfo
const&) =
default;
862 typedef llvm::DenseMap<const CXXMethodDecl *, MethodInfo> MethodInfoMapTy;
866 MethodInfoMapTy MethodInfoMap;
870 MethodVTableIndicesTy MethodVTableIndices;
872 typedef llvm::DenseMap<uint64_t, ThunkInfo> VTableThunksMapTy;
876 VTableThunksMapTy VTableThunks;
879 typedef llvm::DenseMap<const CXXMethodDecl *, ThunkInfoVectorTy> ThunksMapTy;
890 void ComputeThisAdjustments();
896 VisitedVirtualBasesSetTy PrimaryVirtualBases;
913 FinalOverriders::OverriderInfo Overrider);
941 CharUnits FirstBaseOffsetInLayoutClass)
const;
949 PrimaryBasesSetVectorTy &PrimaryBases);
964 bool BaseIsMorallyVirtual,
965 bool BaseIsVirtualInLayoutClass,
980 VisitedVirtualBasesSetTy &VBases);
985 VisitedVirtualBasesSetTy &VBases);
989 bool isBuildingConstructorVTable()
const {
990 return MostDerivedClass != LayoutClass;
1001 bool MostDerivedClassIsVirtual,
1003 : VTables(VTables), MostDerivedClass(MostDerivedClass),
1004 MostDerivedClassOffset(MostDerivedClassOffset),
1005 MostDerivedClassIsVirtual(MostDerivedClassIsVirtual),
1006 LayoutClass(LayoutClass), Context(MostDerivedClass->
getASTContext()),
1007 Overriders(MostDerivedClass, MostDerivedClassOffset, LayoutClass) {
1013 dumpLayout(llvm::outs());
1017 return Thunks.size();
1020 ThunksMapTy::const_iterator thunks_begin()
const {
1021 return Thunks.begin();
1024 ThunksMapTy::const_iterator thunks_end()
const {
1025 return Thunks.end();
1028 const VBaseOffsetOffsetsMapTy &getVBaseOffsetOffsets()
const {
1029 return VBaseOffsetOffsets;
1032 const AddressPointsMapTy &getAddressPoints()
const {
1033 return AddressPoints;
1036 MethodVTableIndicesTy::const_iterator vtable_indices_begin()
const {
1037 return MethodVTableIndices.begin();
1040 MethodVTableIndicesTy::const_iterator vtable_indices_end()
const {
1041 return MethodVTableIndices.end();
1046 AddressPointsMapTy::const_iterator address_points_begin()
const {
1047 return AddressPoints.begin();
1050 AddressPointsMapTy::const_iterator address_points_end()
const {
1051 return AddressPoints.end();
1054 VTableThunksMapTy::const_iterator vtable_thunks_begin()
const {
1055 return VTableThunks.begin();
1058 VTableThunksMapTy::const_iterator vtable_thunks_end()
const {
1059 return VTableThunks.end();
1063 void dumpLayout(raw_ostream&);
1066 void ItaniumVTableBuilder::AddThunk(
const CXXMethodDecl *MD,
1068 assert(!isBuildingConstructorVTable() &&
1069 "Can't add thunks for construction vtable");
1074 if (llvm::is_contained(ThunksVector, Thunk))
1077 ThunksVector.push_back(Thunk);
1086 template <
class VisitorTy>
1088 visitAllOverriddenMethods(
const CXXMethodDecl *MD, VisitorTy &Visitor) {
1092 if (!Visitor(OverriddenMD))
1094 visitAllOverriddenMethods(OverriddenMD, Visitor);
1102 OverriddenMethodsSetTy& OverriddenMethods) {
1103 auto OverriddenMethodsCollector = [&](
const CXXMethodDecl *MD) {
1105 return OverriddenMethods.insert(MD).second;
1107 visitAllOverriddenMethods(MD, OverriddenMethodsCollector);
1110 void ItaniumVTableBuilder::ComputeThisAdjustments() {
1113 for (
const auto &MI : MethodInfoMap) {
1115 const MethodInfo &MethodInfo = MI.second;
1118 uint64_t VTableIndex = MethodInfo.VTableIndex;
1119 if (Components[VTableIndex].
getKind() ==
1124 FinalOverriders::OverriderInfo Overrider =
1125 Overriders.getOverrider(MD, MethodInfo.BaseOffset);
1128 if (MethodInfo.BaseOffsetInLayoutClass == Overrider.Offset) {
1134 if (VTableThunks.lookup(VTableIndex).Return.isEmpty())
1139 ComputeThisAdjustment(MD, MethodInfo.BaseOffsetInLayoutClass, Overrider);
1147 if (isa<CXXDestructorDecl>(MD)) {
1154 MethodInfoMap.clear();
1156 if (isBuildingConstructorVTable()) {
1161 for (
const auto &TI : VTableThunks) {
1166 switch (Component.
getKind()) {
1168 llvm_unreachable(
"Unexpected vtable component kind!");
1180 if (MD->
getParent() == MostDerivedClass)
1181 AddThunk(MD, Thunk);
1186 ItaniumVTableBuilder::ComputeReturnAdjustment(BaseOffset
Offset) {
1190 if (
Offset.VirtualBase) {
1192 if (
Offset.DerivedClass == MostDerivedClass) {
1195 VBaseOffsetOffsets.lookup(
Offset.VirtualBase).getQuantity();
1198 VTables.getVirtualBaseOffsetOffset(
Offset.DerivedClass,
1199 Offset.VirtualBase).getQuantity();
1209 BaseOffset ItaniumVTableBuilder::ComputeThisAdjustmentBaseOffset(
1218 llvm_unreachable(
"Class must be derived from the passed in base class!");
1223 BaseOffset
Offset = ComputeBaseOffset(Context, DerivedRD, Path);
1227 if (
Offset.VirtualBase) {
1235 OffsetToBaseSubobject +=
1244 if (OffsetToBaseSubobject ==
Base.getBaseOffset()) {
1252 return BaseOffset();
1257 FinalOverriders::OverriderInfo Overrider) {
1259 if (Overrider.Method->isPure())
1263 BaseOffsetInLayoutClass);
1265 BaseSubobject OverriderBaseSubobject(Overrider.Method->getParent(),
1269 BaseOffset
Offset = ComputeThisAdjustmentBaseOffset(OverriddenBaseSubobject,
1270 OverriderBaseSubobject);
1276 if (
Offset.VirtualBase) {
1278 VCallOffsetMap &VCallOffsets = VCallOffsetsForVBases[
Offset.VirtualBase];
1280 if (VCallOffsets.empty()) {
1283 VCallAndVBaseOffsetBuilder Builder(
1284 VTables, MostDerivedClass, MostDerivedClass,
1291 VCallOffsets = Builder.getVCallOffsets();
1295 VCallOffsets.getVCallOffsetOffset(MD).getQuantity();
1304 void ItaniumVTableBuilder::AddMethod(
const CXXMethodDecl *MD,
1308 "Destructor can't have return adjustment!");
1334 static bool OverridesIndirectMethodInBases(
1342 if (OverridesIndirectMethodInBases(OverriddenMD, Bases))
1349 bool ItaniumVTableBuilder::IsOverriderUsed(
1352 CharUnits FirstBaseOffsetInLayoutClass)
const {
1355 if (BaseOffsetInLayoutClass == FirstBaseOffsetInLayoutClass)
1364 if (Overrider->
getParent() == FirstBaseInPrimaryBaseChain)
1370 PrimaryBases.insert(RD);
1383 "Primary base should always be at offset 0!");
1391 FirstBaseOffsetInLayoutClass) {
1397 "Primary base should always be at offset 0!");
1400 if (!PrimaryBases.insert(PrimaryBase))
1401 llvm_unreachable(
"Found a duplicate primary base!");
1408 return OverridesIndirectMethodInBases(Overrider, PrimaryBases);
1418 BasesSetVectorTy &Bases) {
1419 OverriddenMethodsSetTy OverriddenMethods;
1420 ComputeAllOverriddenMethods(MD, OverriddenMethods);
1422 for (
const CXXRecordDecl *PrimaryBase : llvm::reverse(Bases)) {
1424 for (
const CXXMethodDecl *OverriddenMD : OverriddenMethods) {
1426 if (OverriddenMD->getParent() == PrimaryBase)
1427 return OverriddenMD;
1434 void ItaniumVTableBuilder::AddMethods(
1438 PrimaryBasesSetVectorTy &PrimaryBases) {
1453 CharUnits PrimaryBaseOffsetInLayoutClass;
1456 "Primary vbase should have a zero offset!");
1467 PrimaryBaseOffsetInLayoutClass =
1471 "Primary base should have a zero offset!");
1473 PrimaryBaseOffset =
Base.getBaseOffset();
1474 PrimaryBaseOffsetInLayoutClass = BaseOffsetInLayoutClass;
1478 PrimaryBaseOffsetInLayoutClass, FirstBaseInPrimaryBaseChain,
1479 FirstBaseOffsetInLayoutClass, PrimaryBases);
1481 if (!PrimaryBases.insert(PrimaryBase))
1482 llvm_unreachable(
"Found a duplicate primary base!");
1486 NewVirtualFunctionsTy NewVirtualFunctions;
1491 for (
const auto *MD : RD->
methods()) {
1497 FinalOverriders::OverriderInfo Overrider =
1498 Overriders.getOverrider(MD,
Base.getBaseOffset());
1504 FindNearestOverriddenMethod(MD, PrimaryBases)) {
1505 if (ComputeReturnAdjustmentBaseOffset(Context, MD,
1506 OverriddenMD).isEmpty()) {
1509 assert(MethodInfoMap.count(OverriddenMD) &&
1510 "Did not find the overridden method!");
1511 MethodInfo &OverriddenMethodInfo = MethodInfoMap[OverriddenMD];
1513 MethodInfo MethodInfo(
Base.getBaseOffset(), BaseOffsetInLayoutClass,
1514 OverriddenMethodInfo.VTableIndex);
1516 assert(!MethodInfoMap.count(MD) &&
1517 "Should not have method info for this method yet!");
1519 MethodInfoMap.insert(std::make_pair(MD, MethodInfo));
1520 MethodInfoMap.erase(OverriddenMD);
1526 if (!isBuildingConstructorVTable() && OverriddenMD != MD) {
1529 ComputeThisAdjustment(OverriddenMD, BaseOffsetInLayoutClass,
1533 Overrider.Method->getParent() == MostDerivedClass) {
1538 BaseOffset ReturnAdjustmentOffset =
1539 ComputeReturnAdjustmentBaseOffset(Context, Overrider.Method, MD);
1541 ComputeReturnAdjustment(ReturnAdjustmentOffset);
1544 AddThunk(Overrider.Method,
1554 NewImplicitVirtualFunctions.push_back(MD);
1556 NewVirtualFunctions.push_back(MD);
1560 NewImplicitVirtualFunctions.begin(), NewImplicitVirtualFunctions.end(),
1562 if (A->isCopyAssignmentOperator() != B->isCopyAssignmentOperator())
1563 return A->isCopyAssignmentOperator();
1564 if (A->isMoveAssignmentOperator() != B->isMoveAssignmentOperator())
1565 return A->isMoveAssignmentOperator();
1566 if (isa<CXXDestructorDecl>(A) != isa<CXXDestructorDecl>(B))
1567 return isa<CXXDestructorDecl>(A);
1568 assert(A->getOverloadedOperator() == OO_EqualEqual &&
1569 B->getOverloadedOperator() == OO_EqualEqual &&
1570 "unexpected or duplicate implicit virtual function");
1575 NewVirtualFunctions.append(NewImplicitVirtualFunctions.begin(),
1576 NewImplicitVirtualFunctions.end());
1580 FinalOverriders::OverriderInfo Overrider =
1581 Overriders.getOverrider(MD,
Base.getBaseOffset());
1584 MethodInfo MethodInfo(
Base.getBaseOffset(), BaseOffsetInLayoutClass,
1587 assert(!MethodInfoMap.count(MD) &&
1588 "Should not have method info for this method yet!");
1589 MethodInfoMap.insert(std::make_pair(MD, MethodInfo));
1593 if (!IsOverriderUsed(OverriderMD, BaseOffsetInLayoutClass,
1594 FirstBaseInPrimaryBaseChain,
1595 FirstBaseOffsetInLayoutClass)) {
1602 BaseOffset ReturnAdjustmentOffset;
1603 if (!OverriderMD->
isPure()) {
1604 ReturnAdjustmentOffset =
1605 ComputeReturnAdjustmentBaseOffset(Context, OverriderMD, MD);
1609 ComputeReturnAdjustment(ReturnAdjustmentOffset);
1615 void ItaniumVTableBuilder::LayoutVTable() {
1616 LayoutPrimaryAndSecondaryVTables(
BaseSubobject(MostDerivedClass,
1619 MostDerivedClassIsVirtual,
1620 MostDerivedClassOffset);
1622 VisitedVirtualBasesSetTy VBases;
1625 DeterminePrimaryVirtualBases(MostDerivedClass, MostDerivedClassOffset,
1629 LayoutVTablesForVirtualBases(MostDerivedClass, VBases);
1632 bool IsAppleKext = Context.
getLangOpts().AppleKext;
1637 void ItaniumVTableBuilder::LayoutPrimaryAndSecondaryVTables(
1639 bool BaseIsVirtualInLayoutClass,
CharUnits OffsetInLayoutClass) {
1640 assert(
Base.getBase()->isDynamicClass() &&
"class does not have a vtable!");
1642 unsigned VTableIndex = Components.size();
1643 VTableIndices.push_back(VTableIndex);
1646 VCallAndVBaseOffsetBuilder Builder(
1647 VTables, MostDerivedClass, LayoutClass, &Overriders,
Base,
1648 BaseIsVirtualInLayoutClass, OffsetInLayoutClass);
1649 Components.append(Builder.components_begin(), Builder.components_end());
1652 if (BaseIsVirtualInLayoutClass && !Builder.getVCallOffsets().empty()) {
1653 VCallOffsetMap &VCallOffsets = VCallOffsetsForVBases[
Base.getBase()];
1655 if (VCallOffsets.empty())
1656 VCallOffsets = Builder.getVCallOffsets();
1661 if (
Base.getBase() == MostDerivedClass)
1662 VBaseOffsetOffsets = Builder.getVBaseOffsetOffsets();
1665 CharUnits OffsetToTop = MostDerivedClassOffset - OffsetInLayoutClass;
1671 uint64_t AddressPoint = Components.size();
1674 PrimaryBasesSetVectorTy PrimaryBases;
1675 AddMethods(
Base, OffsetInLayoutClass,
1676 Base.getBase(), OffsetInLayoutClass,
1680 if (RD == MostDerivedClass) {
1681 assert(MethodVTableIndices.empty());
1682 for (
const auto &I : MethodInfoMap) {
1684 const MethodInfo &MI = I.second;
1687 = MI.VTableIndex - AddressPoint;
1689 = MI.VTableIndex + 1 - AddressPoint;
1691 MethodVTableIndices[MD] = MI.VTableIndex - AddressPoint;
1697 ComputeThisAdjustments();
1701 AddressPoints.insert(
1704 unsigned(VTableIndices.size() - 1),
1705 unsigned(AddressPoint - VTableIndex)}));
1720 OffsetInLayoutClass) {
1730 LayoutSecondaryVTables(
Base, BaseIsMorallyVirtual, OffsetInLayoutClass);
1735 bool BaseIsMorallyVirtual,
1746 for (
const auto &B : RD->
bases()) {
1751 const CXXRecordDecl *BaseDecl = B.getType()->getAsCXXRecordDecl();
1757 if (isBuildingConstructorVTable()) {
1763 if (!BaseIsMorallyVirtual && !BaseDecl->
getNumVBases())
1769 CharUnits BaseOffset =
Base.getBaseOffset() + RelativeBaseOffset;
1772 OffsetInLayoutClass + RelativeBaseOffset;
1776 if (BaseDecl == PrimaryBase) {
1778 BaseIsMorallyVirtual, BaseOffsetInLayoutClass);
1783 LayoutPrimaryAndSecondaryVTables(
1785 BaseIsMorallyVirtual,
1787 BaseOffsetInLayoutClass);
1791 void ItaniumVTableBuilder::DeterminePrimaryVirtualBases(
1793 VisitedVirtualBasesSetTy &VBases) {
1801 bool IsPrimaryVirtualBase =
true;
1803 if (isBuildingConstructorVTable()) {
1809 CharUnits PrimaryBaseOffsetInLayoutClass =
1814 if (PrimaryBaseOffsetInLayoutClass != OffsetInLayoutClass)
1815 IsPrimaryVirtualBase =
false;
1818 if (IsPrimaryVirtualBase)
1819 PrimaryVirtualBases.insert(PrimaryBase);
1824 for (
const auto &B : RD->
bases()) {
1825 const CXXRecordDecl *BaseDecl = B.getType()->getAsCXXRecordDecl();
1829 if (B.isVirtual()) {
1830 if (!VBases.insert(BaseDecl).second)
1836 BaseOffsetInLayoutClass =
1839 BaseOffsetInLayoutClass =
1843 DeterminePrimaryVirtualBases(BaseDecl, BaseOffsetInLayoutClass, VBases);
1847 void ItaniumVTableBuilder::LayoutVTablesForVirtualBases(
1848 const CXXRecordDecl *RD, VisitedVirtualBasesSetTy &VBases) {
1853 for (
const auto &B : RD->
bases()) {
1854 const CXXRecordDecl *BaseDecl = B.getType()->getAsCXXRecordDecl();
1859 !PrimaryVirtualBases.count(BaseDecl) &&
1860 VBases.insert(BaseDecl).second) {
1871 LayoutPrimaryAndSecondaryVTables(
1875 BaseOffsetInLayoutClass);
1881 LayoutVTablesForVirtualBases(BaseDecl, VBases);
1886 void ItaniumVTableBuilder::dumpLayout(raw_ostream &Out) {
1890 if (isBuildingConstructorVTable()) {
1891 Out <<
"Construction vtable for ('";
1894 Out << MostDerivedClassOffset.
getQuantity() <<
") in '";
1897 Out <<
"Vtable for '";
1900 Out <<
"' (" << Components.size() <<
" entries).\n";
1906 std::multimap<uint64_t, BaseSubobject> AddressPointsByIndex;
1907 for (
const auto &AP : AddressPoints) {
1910 VTableIndices[AP.second.VTableIndex] + AP.second.AddressPointIndex;
1912 AddressPointsByIndex.insert(std::make_pair(Index,
Base));
1915 for (
unsigned I = 0, E = Components.size(); I != E; ++I) {
1918 Out << llvm::format(
"%4d | ", I);
1923 switch (Component.
getKind()) {
1926 Out <<
"vcall_offset ("
1932 Out <<
"vbase_offset ("
1938 Out <<
"offset_to_top ("
1959 Out <<
" [deleted]";
1961 ThunkInfo Thunk = VTableThunks.lookup(I);
1965 Out <<
"\n [return adjustment: ";
1970 Out <<
" vbase offset offset";
1978 Out <<
"\n [this adjustment: ";
1983 Out <<
" vcall offset offset";
2002 Out <<
"() [complete]";
2004 Out <<
"() [deleting]";
2009 ThunkInfo Thunk = VTableThunks.lookup(I);
2013 Out <<
"\n [this adjustment: ";
2018 Out <<
" vcall offset offset";
2034 Out <<
"[unused] " << Str;
2045 if (AddressPointsByIndex.count(NextIndex)) {
2046 if (AddressPointsByIndex.count(NextIndex) == 1) {
2048 AddressPointsByIndex.find(NextIndex)->second;
2051 Base.getBase()->printQualifiedName(Out);
2052 Out <<
", " <<
Base.getBaseOffset().getQuantity();
2053 Out <<
") vtable address --\n";
2056 AddressPointsByIndex.lower_bound(NextIndex)->second.getBaseOffset();
2059 std::set<std::string> ClassNames;
2060 for (
const auto &I :
2061 llvm::make_range(AddressPointsByIndex.equal_range(NextIndex))) {
2062 assert(I.second.getBaseOffset() == BaseOffset &&
2063 "Invalid base offset!");
2069 Out <<
" -- (" << Name;
2070 Out <<
", " << BaseOffset.
getQuantity() <<
") vtable address --\n";
2078 if (isBuildingConstructorVTable())
2085 std::map<std::string, CharUnits> ClassNamesAndOffsets;
2086 for (
const auto &I : VBaseOffsetOffsets) {
2087 std::string ClassName = I.first->getQualifiedNameAsString();
2089 ClassNamesAndOffsets.insert(std::make_pair(ClassName, OffsetOffset));
2092 Out <<
"Virtual base offset offsets for '";
2095 Out << ClassNamesAndOffsets.size();
2096 Out << (ClassNamesAndOffsets.size() == 1 ?
" entry" :
" entries") <<
").\n";
2098 for (
const auto &I : ClassNamesAndOffsets)
2099 Out <<
" " << I.first <<
" | " << I.second.getQuantity() <<
'\n';
2104 if (!Thunks.empty()) {
2106 std::map<std::string, const CXXMethodDecl *> MethodNamesAndDecls;
2108 for (
const auto &I : Thunks) {
2114 MethodNamesAndDecls.insert(std::make_pair(MethodName, MD));
2117 for (
const auto &I : MethodNamesAndDecls) {
2121 ThunkInfoVectorTy ThunksVector = Thunks[MD];
2123 assert(LHS.
Method ==
nullptr && RHS.
Method ==
nullptr);
2127 Out <<
"Thunks for '" << MethodName <<
"' (" << ThunksVector.size();
2128 Out << (ThunksVector.size() == 1 ?
" entry" :
" entries") <<
").\n";
2130 for (
unsigned I = 0, E = ThunksVector.size(); I != E; ++I) {
2131 const ThunkInfo &Thunk = ThunksVector[I];
2133 Out << llvm::format(
"%4d | ", I);
2138 Out <<
" non-virtual";
2141 Out <<
" vbase offset offset";
2150 Out <<
"this adjustment: ";
2155 Out <<
" vcall offset offset";
2168 std::map<uint64_t, std::string> IndicesMap;
2170 for (
const auto *MD : MostDerivedClass->
methods()) {
2182 assert(MethodVTableIndices.count(GD));
2183 uint64_t VTableIndex = MethodVTableIndices[GD];
2184 IndicesMap[VTableIndex] = MethodName +
" [complete]";
2185 IndicesMap[VTableIndex + 1] = MethodName +
" [deleting]";
2187 assert(MethodVTableIndices.count(MD));
2188 IndicesMap[MethodVTableIndices[MD]] = MethodName;
2193 if (!IndicesMap.empty()) {
2194 Out <<
"VTable indices for '";
2196 Out <<
"' (" << IndicesMap.size() <<
" entries).\n";
2198 for (
const auto &I : IndicesMap) {
2202 Out << llvm::format(
"%4" PRIu64
" | ", VTableIndex) << MethodName
2213 unsigned numVTables) {
2216 for (
auto it = addressPoints.begin(); it != addressPoints.end(); ++it) {
2217 const auto &addressPointLoc = it->second;
2218 unsigned vtableIndex = addressPointLoc.VTableIndex;
2219 unsigned addressPoint = addressPointLoc.AddressPointIndex;
2220 if (indexMap[vtableIndex]) {
2223 assert(indexMap[vtableIndex] == addressPoint &&
2224 "Every vtable index should have a unique address point. Found a "
2225 "vtable that has two different address points.");
2227 indexMap[vtableIndex] = addressPoint;
2242 : VTableComponents(VTableComponents), VTableThunks(VTableThunks),
2244 AddressPoints, VTableIndices.size())) {
2245 if (VTableIndices.size() <= 1)
2246 assert(VTableIndices.size() == 1 && VTableIndices[0] == 0);
2252 assert((LHS.first != RHS.first || LHS.second == RHS.second) &&
2253 "Different thunks should have unique indices!");
2254 return LHS.first < RHS.first;
2272 MethodVTableIndicesTy::iterator I = MethodVTableIndices.find(GD);
2273 if (I != MethodVTableIndices.end())
2278 computeVTableRelatedInformation(RD);
2280 I = MethodVTableIndices.find(GD);
2281 assert(I != MethodVTableIndices.end() &&
"Did not find index!");
2288 ClassPairTy ClassPair(RD, VBase);
2290 VirtualBaseClassOffsetOffsetsMapTy::iterator I =
2291 VirtualBaseClassOffsetOffsets.find(ClassPair);
2292 if (I != VirtualBaseClassOffsetOffsets.end())
2295 VCallAndVBaseOffsetBuilder Builder(*
this, RD, RD,
nullptr,
2300 for (
const auto &I : Builder.getVBaseOffsetOffsets()) {
2302 ClassPairTy ClassPair(RD, I.first);
2304 VirtualBaseClassOffsetOffsets.insert(std::make_pair(ClassPair, I.second));
2307 I = VirtualBaseClassOffsetOffsets.find(ClassPair);
2308 assert(I != VirtualBaseClassOffsetOffsets.end() &&
"Did not find index!");
2313 static std::unique_ptr<VTableLayout>
2316 VTableThunks(Builder.vtable_thunks_begin(), Builder.vtable_thunks_end());
2318 return std::make_unique<VTableLayout>(
2319 Builder.VTableIndices, Builder.vtable_components(), VTableThunks,
2320 Builder.getAddressPoints());
2324 ItaniumVTableContext::computeVTableRelatedInformation(
const CXXRecordDecl *RD) {
2325 std::unique_ptr<const VTableLayout> &Entry = VTableLayouts[RD];
2335 MethodVTableIndices.insert(Builder.vtable_indices_begin(),
2336 Builder.vtable_indices_end());
2339 Thunks.insert(Builder.thunks_begin(), Builder.thunks_end());
2350 if (VirtualBaseClassOffsetOffsets.count(std::make_pair(RD, VBase)))
2353 for (
const auto &I : Builder.getVBaseOffsetOffsets()) {
2355 ClassPairTy ClassPair(RD, I.first);
2357 VirtualBaseClassOffsetOffsets.insert(std::make_pair(ClassPair, I.second));
2361 std::unique_ptr<VTableLayout>
2364 bool MostDerivedClassIsVirtual,
const CXXRecordDecl *LayoutClass) {
2365 ItaniumVTableBuilder Builder(*
this, MostDerivedClass, MostDerivedClassOffset,
2366 MostDerivedClassIsVirtual, LayoutClass);
2414 class VFTableBuilder {
2416 typedef llvm::DenseMap<GlobalDecl, MethodVFTableLocation>
2417 MethodVFTableLocationsTy;
2419 typedef llvm::iterator_range<MethodVFTableLocationsTy::const_iterator>
2420 method_locations_range;
2438 const FinalOverriders Overriders;
2443 MethodVFTableLocationsTy MethodVFTableLocations;
2446 bool HasRTTIComponent =
false;
2468 bool UsesExtraSlot =
false)
2469 : VBTableIndex(VBTableIndex), VFTableIndex(VFTableIndex),
2470 Shadowed(
false), UsesExtraSlot(UsesExtraSlot) {}
2473 : VBTableIndex(0), VFTableIndex(0), Shadowed(
false),
2474 UsesExtraSlot(
false) {}
2477 typedef llvm::DenseMap<const CXXMethodDecl *, MethodInfo> MethodInfoMapTy;
2481 MethodInfoMapTy MethodInfoMap;
2483 typedef llvm::DenseMap<uint64_t, ThunkInfo> VTableThunksMapTy;
2487 VTableThunksMapTy VTableThunks;
2490 typedef llvm::DenseMap<const CXXMethodDecl *, ThunkInfoVectorTy> ThunksMapTy;
2501 if (llvm::is_contained(ThunksVector, Thunk))
2504 ThunksVector.push_back(Thunk);
2509 CharUnits ComputeThisOffset(FinalOverriders::OverriderInfo Overrider);
2511 void CalculateVtordispAdjustment(FinalOverriders::OverriderInfo Overrider,
2518 VTableThunks[Components.size()] = TI;
2523 "Destructor can't have return adjustment!");
2534 BasesSetVectorTy &VisitedBases);
2536 void LayoutVFTable() {
2538 if (HasRTTIComponent)
2541 BasesSetVectorTy VisitedBases;
2546 assert(!Components.empty() &&
"vftable can't be empty");
2548 assert(MethodVFTableLocations.empty());
2549 for (
const auto &I : MethodInfoMap) {
2551 const MethodInfo &MI = I.second;
2556 if (MD->
getParent() != MostDerivedClass || MI.Shadowed)
2563 MethodVFTableLocations[MD] = Loc;
2572 Context(MostDerivedClass->getASTContext()),
2573 MostDerivedClass(MostDerivedClass),
2574 MostDerivedClassLayout(Context.getASTRecordLayout(MostDerivedClass)),
2576 Overriders(MostDerivedClass,
CharUnits(), MostDerivedClass) {
2583 HasRTTIComponent =
true;
2588 dumpLayout(llvm::outs());
2591 uint64_t getNumThunks()
const {
return Thunks.size(); }
2593 ThunksMapTy::const_iterator thunks_begin()
const {
return Thunks.begin(); }
2595 ThunksMapTy::const_iterator thunks_end()
const {
return Thunks.end(); }
2597 method_locations_range vtable_locations()
const {
2598 return method_locations_range(MethodVFTableLocations.begin(),
2599 MethodVFTableLocations.end());
2604 VTableThunksMapTy::const_iterator vtable_thunks_begin()
const {
2605 return VTableThunks.begin();
2608 VTableThunksMapTy::const_iterator vtable_thunks_end()
const {
2609 return VTableThunks.end();
2612 void dumpLayout(raw_ostream &);
2672 VFTableBuilder::ComputeThisOffset(FinalOverriders::OverriderInfo Overrider) {
2673 BasesSetVectorTy Bases;
2677 OverriddenMethodsSetTy VisitedOverriddenMethods;
2678 auto InitialOverriddenDefinitionCollector = [&](
2680 if (OverriddenMD->size_overridden_methods() == 0)
2681 Bases.insert(OverriddenMD->getParent());
2683 return VisitedOverriddenMethods.insert(OverriddenMD).second;
2685 visitAllOverriddenMethods(Overrider.Method,
2686 InitialOverriddenDefinitionCollector);
2691 if (Bases.size() == 0)
2692 return Overrider.Offset;
2695 Overrider.Method->getParent()->lookupInBases(
2697 return Bases.count(
Specifier->getType()->getAsCXXRecordDecl());
2711 CharUnits ThisOffset = Overrider.Offset;
2718 QualType CurTy = Element.Base->getType();
2723 if (Element.Base->isVirtual()) {
2734 LastVBaseOffset = ThisOffset =
2741 if (isa<CXXDestructorDecl>(Overrider.Method)) {
2742 if (LastVBaseOffset.
isZero()) {
2746 ThisOffset = Overrider.Offset;
2750 ThisOffset = LastVBaseOffset;
2754 if (
Ret > ThisOffset || First) {
2760 assert(!First &&
"Method not found in the given subobject?");
2862 void VFTableBuilder::CalculateVtordispAdjustment(
2863 FinalOverriders::OverriderInfo Overrider,
CharUnits ThisOffset,
2867 const ASTRecordLayout::VBaseOffsetsMapTy::const_iterator &VBaseMapEntry =
2869 assert(VBaseMapEntry != VBaseMap.end());
2873 if (!VBaseMapEntry->second.hasVtorDisp() ||
2879 CharUnits OffsetOfVBaseWithVFPtr = VBaseMapEntry->second.VBaseOffset;
2881 (OffsetOfVBaseWithVFPtr - WhichVFPtr.
FullOffsetInMDC).getQuantity() - 4;
2885 if (Overrider.Method->getParent() == MostDerivedClass ||
2886 !Overrider.VirtualBase)
2898 TA.
NonVirtual = (ThisOffset - Overrider.Offset).getQuantity();
2912 typedef llvm::DenseMap<DeclarationName, unsigned> VisitedGroupIndicesTy;
2913 VisitedGroupIndicesTy VisitedGroupIndices;
2914 for (
const auto *D : RD->
decls()) {
2915 const auto *ND = dyn_cast<NamedDecl>(D);
2918 VisitedGroupIndicesTy::iterator J;
2920 std::tie(J, Inserted) = VisitedGroupIndices.insert(
2921 std::make_pair(ND->getDeclName(), Groups.size()));
2923 Groups.push_back(MethodGroup());
2924 if (
const auto *MD = dyn_cast<CXXMethodDecl>(ND))
2929 for (
const MethodGroup &
Group : Groups)
2930 VirtualMethods.append(
Group.rbegin(),
Group.rend());
2934 for (
const auto &B : RD->
bases()) {
2935 if (B.isVirtual() && B.getType()->getAsCXXRecordDecl() ==
Base)
2943 BasesSetVectorTy &VisitedBases) {
2953 const CXXRecordDecl *NextBase =
nullptr, *NextLastVBase = LastVBase;
2958 NextLastVBase = NextBase;
2966 "No primary virtual bases in this ABI");
2967 NextBase = PrimaryBase;
2968 NextBaseOffset =
Base.getBaseOffset();
2972 AddMethods(
BaseSubobject(NextBase, NextBaseOffset), BaseDepth + 1,
2973 NextLastVBase, VisitedBases);
2974 if (!VisitedBases.insert(NextBase))
2975 llvm_unreachable(
"Found a duplicate primary base!");
2991 FinalOverriders::OverriderInfo FinalOverrider =
2992 Overriders.getOverrider(MD,
Base.getBaseOffset());
2993 const CXXMethodDecl *FinalOverriderMD = FinalOverrider.Method;
2995 FindNearestOverriddenMethod(MD, VisitedBases);
2998 bool ReturnAdjustingThunk =
false, ForceReturnAdjustmentMangling =
false;
2999 CharUnits ThisOffset = ComputeThisOffset(FinalOverrider);
3002 if ((OverriddenMD || FinalOverriderMD != MD) &&
3004 CalculateVtordispAdjustment(FinalOverrider, ThisOffset,
3005 ThisAdjustmentOffset);
3013 MethodInfoMapTy::iterator OverriddenMDIterator =
3014 MethodInfoMap.find(OverriddenMD);
3017 if (OverriddenMDIterator == MethodInfoMap.end())
3020 MethodInfo &OverriddenMethodInfo = OverriddenMDIterator->second;
3022 VBIndex = OverriddenMethodInfo.VBTableIndex;
3029 ReturnAdjustingThunk = !ComputeReturnAdjustmentBaseOffset(
3030 Context, MD, OverriddenMD).isEmpty() ||
3031 OverriddenMethodInfo.UsesExtraSlot;
3033 if (!ReturnAdjustingThunk) {
3036 MethodInfo MI(VBIndex, OverriddenMethodInfo.VFTableIndex);
3037 MethodInfoMap.erase(OverriddenMDIterator);
3039 assert(!MethodInfoMap.count(MD) &&
3040 "Should not have method info for this method yet!");
3041 MethodInfoMap.insert(std::make_pair(MD, MI));
3047 OverriddenMethodInfo.Shadowed =
true;
3051 ForceReturnAdjustmentMangling =
3052 !(MD == FinalOverriderMD && ThisAdjustmentOffset.
isEmpty());
3063 MethodInfo MI(VBIndex,
3064 HasRTTIComponent ? Components.size() - 1 : Components.size(),
3065 ReturnAdjustingThunk);
3067 assert(!MethodInfoMap.count(MD) &&
3068 "Should not have method info for this method yet!");
3069 MethodInfoMap.insert(std::make_pair(MD, MI));
3073 BaseOffset ReturnAdjustmentOffset;
3075 if (!FinalOverriderMD->
isPure()) {
3076 ReturnAdjustmentOffset =
3077 ComputeReturnAdjustmentBaseOffset(Context, FinalOverriderMD, MD);
3079 if (!ReturnAdjustmentOffset.isEmpty()) {
3080 ForceReturnAdjustmentMangling =
true;
3082 ReturnAdjustmentOffset.NonVirtualOffset.getQuantity();
3083 if (ReturnAdjustmentOffset.VirtualBase) {
3090 ReturnAdjustmentOffset.VirtualBase);
3094 AddMethod(FinalOverriderMD,
3096 ForceReturnAdjustmentMangling ? MD :
nullptr));
3103 Elem->printQualifiedName(Out);
3109 bool ContinueFirstLine) {
3111 bool Multiline =
false;
3112 const char *LinePrefix =
"\n ";
3114 if (!ContinueFirstLine)
3116 Out <<
"[return adjustment (to type '"
3128 if (Multiline || !ContinueFirstLine)
3130 Out <<
"[this adjustment: ";
3138 Out << LinePrefix <<
" vboffset at "
3146 void VFTableBuilder::dumpLayout(raw_ostream &Out) {
3147 Out <<
"VFTable for ";
3151 Out <<
"' (" << Components.size()
3152 << (Components.size() == 1 ?
" entry" :
" entries") <<
").\n";
3154 for (
unsigned I = 0, E = Components.size(); I != E; ++I) {
3155 Out << llvm::format(
"%4d | ", I);
3160 switch (Component.
getKind()) {
3178 Out <<
" [deleted]";
3180 ThunkInfo Thunk = VTableThunks.lookup(I);
3191 Out <<
"() [scalar deleting]";
3196 ThunkInfo Thunk = VTableThunks.lookup(I);
3199 "No return adjustment needed for destructors!");
3210 "Unexpected vftable component type %0 for component number %1");
3220 if (!Thunks.empty()) {
3222 std::map<std::string, const CXXMethodDecl *> MethodNamesAndDecls;
3224 for (
const auto &I : Thunks) {
3229 MethodNamesAndDecls.insert(std::make_pair(MethodName, MD));
3232 for (
const auto &MethodNameAndDecl : MethodNamesAndDecls) {
3233 const std::string &MethodName = MethodNameAndDecl.first;
3236 ThunkInfoVectorTy ThunksVector = Thunks[MD];
3237 llvm::stable_sort(ThunksVector, [](
const ThunkInfo &LHS,
3244 Out <<
"Thunks for '" << MethodName <<
"' (" << ThunksVector.size();
3245 Out << (ThunksVector.size() == 1 ?
" entry" :
" entries") <<
").\n";
3247 for (
unsigned I = 0, E = ThunksVector.size(); I != E; ++I) {
3248 const ThunkInfo &Thunk = ThunksVector[I];
3250 Out << llvm::format(
"%4d | ", I);
3294 void MicrosoftVTableContext::computeVTablePaths(
bool ForVBTables,
3297 assert(Paths.empty());
3302 Paths.push_back(std::make_unique<VPtrInfo>(RD));
3307 for (
const auto &B : RD->
bases()) {
3309 if (B.isVirtual() && VBasesSeen.count(
Base))
3312 if (!
Base->isDynamicClass())
3318 for (
const std::unique_ptr<VPtrInfo> &BaseInfo : BasePaths) {
3325 auto P = std::make_unique<VPtrInfo>(*BaseInfo);
3329 if (
P->MangledPath.empty() ||
P->MangledPath.back() !=
Base)
3330 P->NextBaseToMangle =
Base;
3335 if (
P->ObjectWithVPtr ==
Base &&
3338 P->ObjectWithVPtr = RD;
3343 P->ContainingVBases.push_back(
Base);
3344 else if (
P->ContainingVBases.empty())
3348 P->FullOffsetInMDC =
P->NonVirtualOffset;
3352 Paths.push_back(std::move(
P));
3356 VBasesSeen.insert(
Base);
3360 for (
const auto &VB :
Base->vbases())
3361 VBasesSeen.insert(VB.getType()->getAsCXXRecordDecl());
3372 if (
P.NextBaseToMangle) {
3373 P.MangledPath.push_back(
P.NextBaseToMangle);
3374 P.NextBaseToMangle =
nullptr;
3388 llvm::make_pointee_range(Paths));
3392 bool Changed =
false;
3393 for (
size_t I = 0, E = PathsSorted.size(); I != E;) {
3395 size_t BucketStart = I;
3399 PathsSorted[BucketStart].get().MangledPath ==
3400 PathsSorted[I].get().MangledPath);
3403 if (I - BucketStart > 1) {
3404 for (
size_t II = BucketStart; II != I; ++II)
3406 assert(Changed &&
"no paths were extended to fix ambiguity");
3415 typedef llvm::SetVector<BaseSubobject, std::vector<BaseSubobject>,
3425 FullPathTy &FullPath,
3426 std::list<FullPathTy> &Paths) {
3428 Paths.push_back(FullPath);
3441 IntroducingObject, FullPath, Paths);
3442 FullPath.pop_back();
3448 FullPaths.remove_if([&](
const FullPathTy &SpecificPath) {
3449 for (
const FullPathTy &OtherPath : FullPaths) {
3450 if (&SpecificPath == &OtherPath)
3452 if (llvm::all_of(SpecificPath, [&](
const BaseSubobject &BSO) {
3453 return OtherPath.contains(BSO);
3464 const FullPathTy &FullPath) {
3472 assert(
Offset.getQuantity() == -1);
3476 assert(
Offset.getQuantity() != -1);
3482 return BS.getType()->getAsCXXRecordDecl() == Base;
3497 std::list<FullPathTy> &FullPaths) {
3499 if (FullPaths.empty())
3501 if (FullPaths.size() == 1)
3502 return &FullPaths.front();
3504 const FullPathTy *BestPath =
nullptr;
3505 typedef std::set<const CXXMethodDecl *> OverriderSetTy;
3506 OverriderSetTy LastOverrides;
3507 for (
const FullPathTy &SpecificPath : FullPaths) {
3508 assert(!SpecificPath.empty());
3509 OverriderSetTy CurrentOverrides;
3510 const CXXRecordDecl *TopLevelRD = SpecificPath.begin()->getBase();
3515 FinalOverriders Overriders(TopLevelRD,
CharUnits::Zero(), TopLevelRD);
3519 FinalOverriders::OverriderInfo OI =
3524 if (ComputeReturnAdjustmentBaseOffset(Context, OverridingMethod, MD)
3530 if (llvm::none_of(SpecificPath, [&](
const BaseSubobject &BSO) {
3531 return BSO.
getBase() == OverridingParent;
3534 CurrentOverrides.insert(OverridingMethod);
3536 OverriderSetTy NewOverrides =
3537 llvm::set_difference(CurrentOverrides, LastOverrides);
3538 if (NewOverrides.empty())
3540 OverriderSetTy MissingOverrides =
3541 llvm::set_difference(LastOverrides, CurrentOverrides);
3542 if (MissingOverrides.empty()) {
3544 BestPath = &SpecificPath;
3545 std::swap(CurrentOverrides, LastOverrides);
3550 const CXXMethodDecl *ConflictMD = *MissingOverrides.begin();
3561 return BestPath ? BestPath : &FullPaths.front();
3568 FullPathTy FullPath;
3569 std::list<FullPathTy> FullPaths;
3570 for (
const std::unique_ptr<VPtrInfo>& Info : Paths) {
3573 BaseSubobject(Info->IntroducingObject, Info->FullOffsetInMDC), FullPath,
3577 Info->PathToIntroducingObject.clear();
3578 if (
const FullPathTy *BestPath =
3581 Info->PathToIntroducingObject.push_back(BSO.getBase());
3598 void MicrosoftVTableContext::computeVTableRelatedInformation(
3603 if (VFPtrLocations.count(RD))
3609 auto VFPtrs = std::make_unique<VPtrInfoVector>();
3610 computeVTablePaths(
false, RD, *VFPtrs);
3612 VFPtrLocations[RD] = std::move(VFPtrs);
3615 MethodVFTableLocationsTy NewMethodLocations;
3616 for (
const std::unique_ptr<VPtrInfo> &VFPtr : *VFPtrLocations[RD]) {
3617 VFTableBuilder Builder(*
this, RD, *VFPtr);
3619 VFTableIdTy id(RD, VFPtr->FullOffsetInMDC);
3620 assert(VFTableLayouts.count(
id) == 0);
3622 Builder.vtable_thunks_begin(), Builder.vtable_thunks_end());
3623 VFTableLayouts[id] = std::make_unique<VTableLayout>(
3625 EmptyAddressPointsMap);
3626 Thunks.insert(Builder.thunks_begin(), Builder.thunks_end());
3629 for (
const auto &Loc : Builder.vtable_locations()) {
3630 auto Insert = NewMethodLocations.insert(Loc);
3640 MethodVFTableLocations.insert(NewMethodLocations.begin(),
3641 NewMethodLocations.end());
3643 dumpMethodLocations(RD, NewMethodLocations, llvm::outs());
3646 void MicrosoftVTableContext::dumpMethodLocations(
3647 const CXXRecordDecl *RD,
const MethodVFTableLocationsTy &NewMethods,
3651 std::map<MethodVFTableLocation, std::string> IndicesMap;
3652 bool HasNonzeroOffset =
false;
3654 for (
const auto &I : NewMethods) {
3655 const CXXMethodDecl *MD = cast<const CXXMethodDecl>(I.first.getDecl());
3661 if (isa<CXXDestructorDecl>(MD)) {
3662 IndicesMap[I.second] = MethodName +
" [scalar deleting]";
3664 IndicesMap[I.second] = MethodName;
3667 if (!I.second.VFPtrOffset.isZero() || I.second.VBTableIndex != 0)
3668 HasNonzeroOffset =
true;
3672 if (!IndicesMap.empty()) {
3673 Out <<
"VFTable indices for ";
3676 Out <<
"' (" << IndicesMap.size()
3677 << (IndicesMap.size() == 1 ?
" entry" :
" entries") <<
").\n";
3681 for (
const auto &I : IndicesMap) {
3682 CharUnits VFPtrOffset = I.first.VFPtrOffset;
3683 uint64_t VBIndex = I.first.VBTableIndex;
3684 if (HasNonzeroOffset &&
3685 (VFPtrOffset != LastVFPtrOffset || VBIndex != LastVBIndex)) {
3686 assert(VBIndex > LastVBIndex || VFPtrOffset > LastVFPtrOffset);
3687 Out <<
" -- accessible via ";
3689 Out <<
"vbtable index " << VBIndex <<
", ";
3690 Out <<
"vfptr at offset " << VFPtrOffset.
getQuantity() <<
" --\n";
3691 LastVFPtrOffset = VFPtrOffset;
3692 LastVBIndex = VBIndex;
3695 uint64_t VTableIndex = I.first.Index;
3697 Out << llvm::format(
"%4" PRIu64
" | ", VTableIndex) << MethodName <<
'\n';
3705 const VirtualBaseInfo &MicrosoftVTableContext::computeVBTableRelatedInformation(
3712 std::unique_ptr<VirtualBaseInfo> &Entry = VBaseInfo[RD];
3715 Entry = std::make_unique<VirtualBaseInfo>();
3719 computeVTablePaths(
true, RD, VBI->
VBPtrPaths);
3727 computeVBTableRelatedInformation(VBPtrBase);
3735 for (
const auto &VB : RD->
vbases()) {
3736 const CXXRecordDecl *CurVBase = VB.getType()->getAsCXXRecordDecl();
3746 const VirtualBaseInfo &VBInfo = computeVBTableRelatedInformation(Derived);
3753 return computeVBTableRelatedInformation(RD).
VBPtrPaths;
3758 computeVTableRelatedInformation(RD);
3760 assert(VFPtrLocations.count(RD) &&
"Couldn't find vfptr locations");
3761 return *VFPtrLocations[RD];
3767 computeVTableRelatedInformation(RD);
3769 VFTableIdTy id(RD, VFPtrOffset);
3770 assert(VFTableLayouts.count(
id) &&
"Couldn't find a VFTable at this offset");
3771 return *VFTableLayouts[id];
3777 "Only use this method for virtual methods or dtors");
3778 if (isa<CXXDestructorDecl>(GD.
getDecl()))
3783 MethodVFTableLocationsTy::iterator I = MethodVFTableLocations.find(GD);
3784 if (I != MethodVFTableLocations.end())
3789 computeVTableRelatedInformation(RD);
3791 I = MethodVFTableLocations.find(GD);
3792 assert(I != MethodVFTableLocations.end() &&
"Did not find index!");