clang: lib/AST/VTableBuilder.cpp Source File (original) (raw)
1
2
3
4
5
6
7
8
9
10
11
12
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"
24#include
25#include
26
27using namespace clang;
28
29#define DUMP_OVERRIDERS 0
30
31namespace {
32
33
34
35struct BaseOffset {
36
38
39
40
41
43
44
45
46
47
49
50 BaseOffset() : DerivedClass(nullptr), VirtualBase(nullptr),
55 NonVirtualOffset(NonVirtualOffset) { }
56
57 bool isEmpty() const { return NonVirtualOffset.isZero() && ; }
58};
59
60
61
62class FinalOverriders {
63public:
64
65 struct OverriderInfo {
66
68
69
70
72
73
75
76 OverriderInfo() : Method(nullptr), VirtualBase(nullptr),
78 };
79
80private:
81
82
84
85
86
87
88 const CharUnits MostDerivedClassOffset;
89
90
91
92
94
96
97
99
100
101
102 typedef std::pair<const CXXMethodDecl *, CharUnits> MethodBaseOffsetPairTy;
103
104 typedef llvm::DenseMap<MethodBaseOffsetPairTy,
105 OverriderInfo> OverridersMapTy;
106
107
108
109 OverridersMapTy OverridersMap;
110
111
112
113
114 typedef llvm::DenseMap<std::pair<const CXXRecordDecl *, unsigned>,
116
117 typedef llvm::DenseMap<const CXXRecordDecl *, unsigned> SubobjectCountMapTy;
118
119
120
123 SubobjectOffsetMapTy &SubobjectOffsets,
124 SubobjectOffsetMapTy &SubobjectLayoutClassOffsets,
125 SubobjectCountMapTy &SubobjectCounts);
126
128
129
130
132 VisitedVirtualBasesSetTy& VisitedVirtualBases);
133
134public:
135 FinalOverriders(const CXXRecordDecl *MostDerivedClass,
136 CharUnits MostDerivedClassOffset,
138
139
140
141 OverriderInfo getOverrider(const CXXMethodDecl *MD,
143 assert(OverridersMap.count(std::make_pair(MD, BaseOffset)) &&
144 "Did not find overrider!");
145
146 return OverridersMap.lookup(std::make_pair(MD, BaseOffset));
147 }
148
149
150 void dump() {
151 VisitedVirtualBasesSetTy VisitedVirtualBases;
153 VisitedVirtualBases);
154 }
155
156};
157
158FinalOverriders::FinalOverriders(const CXXRecordDecl *MostDerivedClass,
159 CharUnits MostDerivedClassOffset,
161 : MostDerivedClass(MostDerivedClass),
162 MostDerivedClassOffset(MostDerivedClassOffset), LayoutClass(LayoutClass),
164 MostDerivedClassLayout(Context.getASTRecordLayout(MostDerivedClass)) {
165
166
167 SubobjectOffsetMapTy SubobjectOffsets;
168 SubobjectOffsetMapTy SubobjectLayoutClassOffsets;
169 SubobjectCountMapTy SubobjectCounts;
171 false,
172 MostDerivedClassOffset,
173 SubobjectOffsets, SubobjectLayoutClassOffsets,
174 SubobjectCounts);
175
176
179
180 for (const auto &Overrider : FinalOverriders) {
183
184 for (const auto &M : Methods) {
185 unsigned SubobjectNumber = M.first;
186 assert(SubobjectOffsets.count(std::make_pair(MD->getParent(),
187 SubobjectNumber)) &&
188 "Did not find subobject offset!");
189
190 CharUnits BaseOffset = SubobjectOffsets[std::make_pair(MD->getParent(),
191 SubobjectNumber)];
192
193 assert(M.second.size() == 1 && "Final overrider is not unique!");
195
197 assert(SubobjectLayoutClassOffsets.count(
198 std::make_pair(OverriderRD, Method.Subobject))
199 && "Did not find subobject offset!");
201 SubobjectLayoutClassOffsets[std::make_pair(OverriderRD,
203
204 OverriderInfo& Overrider = OverridersMap[std::make_pair(MD, BaseOffset)];
205 assert(!Overrider.Method && "Overrider should not exist yet!");
206
207 Overrider.Offset = OverriderOffset;
208 Overrider.Method = Method.Method;
210 }
211 }
212
213#if DUMP_OVERRIDERS
214
216#endif
217}
218
219static BaseOffset ComputeBaseOffset(const ASTContext &Context,
223
224 unsigned NonVirtualStart = 0;
226
227
228 for (int I = Path.size(), E = 0; I != E; --I) {
230
231 if (Element.Base->isVirtual()) {
232 NonVirtualStart = I;
233 QualType VBaseType = Element.Base->getType();
235 break;
236 }
237 }
238
239
240 for (unsigned I = NonVirtualStart, E = Path.size(); I != E; ++I) {
242
243
245
246 const CXXRecordDecl *Base = Element.Base->getType()->getAsCXXRecordDecl();
247
249 }
250
251
252
253
254 return BaseOffset(DerivedRD, VirtualBase, NonVirtualOffset);
255
256}
257
258static BaseOffset ComputeBaseOffset(const ASTContext &Context,
261 CXXBasePaths Paths(false,
262 true, false);
263
265 llvm_unreachable("Class must be derived from the passed in base class!");
266
267 return ComputeBaseOffset(Context, DerivedRD, Paths.front());
268}
269
270static BaseOffset
271ComputeReturnAdjustmentBaseOffset(ASTContext &Context,
276
277
282
283 assert(CanDerivedReturnType->getTypeClass() ==
284 CanBaseReturnType->getTypeClass() &&
285 "Types must have same type class!");
286
287 if (CanDerivedReturnType == CanBaseReturnType) {
288
289 return BaseOffset();
290 }
291
292 if (isa(CanDerivedReturnType)) {
293 CanDerivedReturnType =
295 CanBaseReturnType =
297 } else if (isa(CanDerivedReturnType)) {
298 CanDerivedReturnType =
300 CanBaseReturnType =
302 } else {
303 llvm_unreachable("Unexpected return type!");
304 }
305
306
307
308
309 if (CanDerivedReturnType.getUnqualifiedType() ==
311
312 return BaseOffset();
313 }
314
316 cast(cast(CanDerivedReturnType)->getDecl());
317
319 cast(cast(CanBaseReturnType)->getDecl());
320
321 return ComputeBaseOffset(Context, BaseRD, DerivedRD);
322}
323
324void
325FinalOverriders::ComputeBaseOffsets(BaseSubobject Base, bool IsVirtual,
327 SubobjectOffsetMapTy &SubobjectOffsets,
328 SubobjectOffsetMapTy &SubobjectLayoutClassOffsets,
329 SubobjectCountMapTy &SubobjectCounts) {
331
332 unsigned SubobjectNumber = 0;
333 if (!IsVirtual)
334 SubobjectNumber = ++SubobjectCounts[RD];
335
336
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!");
341
342 SubobjectOffsets[std::make_pair(RD, SubobjectNumber)] = Base.getBaseOffset();
343 SubobjectLayoutClassOffsets[std::make_pair(RD, SubobjectNumber)] =
344 OffsetInLayoutClass;
345
346
347 for (const auto &B : RD->bases()) {
348 const CXXRecordDecl *BaseDecl = B.getType()->getAsCXXRecordDecl();
349
351 CharUnits BaseOffsetInLayoutClass;
352 if (B.isVirtual()) {
353
354 if (SubobjectOffsets.count(std::make_pair(BaseDecl, 0)))
355 continue;
356
359
360 BaseOffset = MostDerivedClassLayout.getVBaseClassOffset(BaseDecl);
361 BaseOffsetInLayoutClass =
363 } else {
366
367 BaseOffset = Base.getBaseOffset() + Offset;
368 BaseOffsetInLayoutClass = OffsetInLayoutClass + Offset;
369 }
370
371 ComputeBaseOffsets(BaseSubobject(BaseDecl, BaseOffset),
372 B.isVirtual(), BaseOffsetInLayoutClass,
373 SubobjectOffsets, SubobjectLayoutClassOffsets,
374 SubobjectCounts);
375 }
376}
377
379 VisitedVirtualBasesSetTy &VisitedVirtualBases) {
382
383 for (const auto &B : RD->bases()) {
384 const CXXRecordDecl *BaseDecl = B.getType()->getAsCXXRecordDecl();
385
386
388 continue;
389
391 if (B.isVirtual()) {
392 if (!VisitedVirtualBases.insert(BaseDecl).second) {
393
394 continue;
395 }
396
397 BaseOffset = MostDerivedClassLayout.getVBaseClassOffset(BaseDecl);
398 } else {
400 }
401
402 dump(Out, BaseSubobject(BaseDecl, BaseOffset), VisitedVirtualBases);
403 }
404
405 Out << "Final overriders for (";
407 Out << ", ";
408 Out << Base.getBaseOffset().getQuantity() << ")\n";
409
410
411 for (const auto *MD : RD->methods()) {
413 continue;
414 MD = MD->getCanonicalDecl();
415
416 OverriderInfo Overrider = getOverrider(MD, Base.getBaseOffset());
417
418 Out << " ";
419 MD->printQualifiedName(Out);
420 Out << " - (";
421 Overrider.Method->printQualifiedName(Out);
422 Out << ", " << Overrider.Offset.getQuantity() << ')';
423
424 BaseOffset Offset;
425 if (!Overrider.Method->isPureVirtual())
426 Offset = ComputeReturnAdjustmentBaseOffset(Context, Overrider.Method, MD);
427
428 if (!Offset.isEmpty()) {
429 Out << " [ret-adj: ";
430 if (Offset.VirtualBase) {
431 Offset.VirtualBase->printQualifiedName(Out);
432 Out << " vbase, ";
433 }
434
435 Out << Offset.NonVirtualOffset.getQuantity() << " nv]";
436 }
437
438 Out << "\n";
439 }
440}
441
442
443struct VCallOffsetMap {
444
445 typedef std::pair<const CXXMethodDecl *, CharUnits> MethodAndOffsetPairTy;
446
447
448
450
451
452
453 static bool MethodsCanShareVCallOffset(const CXXMethodDecl *LHS,
455
456public:
457
458
459
461
462
463
465
466
467 bool empty() const { return Offsets.empty(); }
468};
469
470static bool HasSameVirtualSignature(const CXXMethodDecl *LHS,
476
477
478 if (LT == RT) return true;
479
480
481
482
484 return false;
486}
487
488bool VCallOffsetMap::MethodsCanShareVCallOffset(const CXXMethodDecl *LHS,
492
493
494 if (isa(LHS))
495 return isa(RHS);
496
497
498
499
502 if (LHSName != RHSName)
503 return false;
504
505
506 return HasSameVirtualSignature(LHS, RHS);
507}
508
509bool VCallOffsetMap::AddVCallOffset(const CXXMethodDecl *MD,
511
512 for (const auto &OffsetPair : Offsets) {
513 if (MethodsCanShareVCallOffset(OffsetPair.first, MD))
514 return false;
515 }
516
517
518 Offsets.push_back(MethodAndOffsetPairTy(MD, OffsetOffset));
519 return true;
520}
521
523
524 for (const auto &OffsetPair : Offsets) {
525 if (MethodsCanShareVCallOffset(OffsetPair.first, MD))
526 return OffsetPair.second;
527 }
528
529 llvm_unreachable("Should always find a vcall offset offset!");
530}
531
532
533class VCallAndVBaseOffsetBuilder {
534public:
535 typedef llvm::DenseMap<const CXXRecordDecl *, CharUnits>
536 VBaseOffsetOffsetsMapTy;
537
538private:
540
541
542
544
545
546
547
549
550
552
553
555 VTableComponentVectorTy Components;
556
557
559
560
561 VCallOffsetMap VCallOffsets;
562
563
564
565
566 VBaseOffsetOffsetsMapTy VBaseOffsetOffsets;
567
568
569
570 const FinalOverriders *Overriders;
571
572
573
574 void AddVCallAndVBaseOffsets(BaseSubobject Base, bool BaseIsVirtual,
576
577
579
580
583
584
585
586 CharUnits getCurrentOffsetOffset() const;
587
588public:
592 const FinalOverriders *Overriders,
595 : VTables(VTables), MostDerivedClass(MostDerivedClass),
596 LayoutClass(LayoutClass), Context(MostDerivedClass->getASTContext()),
597 Overriders(Overriders) {
598
599
600 AddVCallAndVBaseOffsets(Base, BaseIsVirtual, OffsetInLayoutClass);
601 }
602
603
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(); }
607
608 const VCallOffsetMap &getVCallOffsets() const { return VCallOffsets; }
609 const VBaseOffsetOffsetsMapTy &getVBaseOffsetOffsets() const {
610 return VBaseOffsetOffsets;
611 }
612};
613
614void
615VCallAndVBaseOffsetBuilder::AddVCallAndVBaseOffsets(BaseSubobject Base,
616 bool BaseIsVirtual,
619
620
621
622
623
624
625
626
627
628
631
633
634
635 if (PrimaryBaseIsVirtual) {
637 "Primary vbase should have a zero offset!");
638
641
642 PrimaryBaseOffset =
644 } else {
646 "Primary base should have a zero offset!");
647
648 PrimaryBaseOffset = Base.getBaseOffset();
649 }
650
651 AddVCallAndVBaseOffsets(
653 PrimaryBaseIsVirtual, RealBaseOffset);
654 }
655
656 AddVBaseOffsets(Base.getBase(), RealBaseOffset);
657
658
659 if (BaseIsVirtual)
660 AddVCallOffsets(Base, RealBaseOffset);
661}
662
663CharUnits VCallAndVBaseOffsetBuilder::getCurrentOffsetOffset() const {
664
665
666
667
668 size_t NumComponentsAboveAddrPoint = 3;
669 if (Context.getLangOpts().OmitVTableRTTI)
670 NumComponentsAboveAddrPoint--;
671 int64_t OffsetIndex =
672 -(int64_t)(NumComponentsAboveAddrPoint + Components.size());
673
674
675
677 VTables.isRelativeLayout()
678 ? 32
680 CharUnits OffsetOffset = OffsetWidth * OffsetIndex;
681
682 return OffsetOffset;
683}
684
685void VCallAndVBaseOffsetBuilder::AddVCallOffsets(BaseSubobject Base,
689
691
692
693
694
696
698 "Primary base should have a zero offset!");
699
700 AddVCallOffsets(BaseSubobject(PrimaryBase, Base.getBaseOffset()),
701 VBaseOffset);
702 }
703
704
705 for (const auto *MD : RD->methods()) {
707 continue;
709
710 CharUnits OffsetOffset = getCurrentOffsetOffset();
711
712
713
714 if (!VCallOffsets.AddVCallOffset(MD, OffsetOffset))
715 continue;
716
718
719 if (Overriders) {
720
721 FinalOverriders::OverriderInfo Overrider =
722 Overriders->getOverrider(MD, Base.getBaseOffset());
723
724
725
726 Offset = Overrider.Offset - VBaseOffset;
727 }
728
729 Components.push_back(
731 }
732
733
734 for (const auto &B : RD->bases()) {
735 if (B.isVirtual())
736 continue;
737
738 const CXXRecordDecl *BaseDecl = B.getType()->getAsCXXRecordDecl();
739 if (BaseDecl == PrimaryBase)
740 continue;
741
742
745
746 AddVCallOffsets(BaseSubobject(BaseDecl, BaseOffset),
747 VBaseOffset);
748 }
749}
750
751void
752VCallAndVBaseOffsetBuilder::AddVBaseOffsets(const CXXRecordDecl *RD,
756
757
758 for (const auto &B : RD->bases()) {
759 const CXXRecordDecl *BaseDecl = B.getType()->getAsCXXRecordDecl();
760
761
762 if (B.isVirtual() && VisitedVirtualBases.insert(BaseDecl).second) {
765
766
767 assert(!VBaseOffsetOffsets.count(BaseDecl) &&
768 "vbase offset offset already exists!");
769
770 CharUnits VBaseOffsetOffset = getCurrentOffsetOffset();
771 VBaseOffsetOffsets.insert(
772 std::make_pair(BaseDecl, VBaseOffsetOffset));
773
774 Components.push_back(
776 }
777
778
779 AddVBaseOffsets(BaseDecl, OffsetInLayoutClass);
780 }
781}
782
783
784class ItaniumVTableBuilder {
785public:
786
787
789 PrimaryBasesSetVectorTy;
790
791 typedef llvm::DenseMap<const CXXRecordDecl *, CharUnits>
792 VBaseOffsetOffsetsMapTy;
793
795
796 typedef llvm::DenseMap<GlobalDecl, int64_t> MethodVTableIndicesTy;
797
798private:
799
801
802
803
805
806
807
808 const CharUnits MostDerivedClassOffset;
809
810
811
812 bool MostDerivedClassIsVirtual;
813
814
815
816
818
819
821
822
823 const FinalOverriders Overriders;
824
825
826
827 llvm::DenseMap<const CXXRecordDecl *, VCallOffsetMap> VCallOffsetsForVBases;
828
829
830
831 VBaseOffsetOffsetsMapTy VBaseOffsetOffsets;
832
833
835
836
837 AddressPointsMapTy AddressPoints;
838
839
840
841 struct MethodInfo {
842
844
845
846
847 const CharUnits BaseOffsetInLayoutClass;
848
849
850
851 const uint64_t VTableIndex;
852
854 uint64_t VTableIndex)
855 : BaseOffset(BaseOffset),
856 BaseOffsetInLayoutClass(BaseOffsetInLayoutClass),
857 VTableIndex(VTableIndex) { }
858
859 MethodInfo()
862 VTableIndex(0) { }
863
864 MethodInfo(MethodInfo const&) = default;
865 };
866
867 typedef llvm::DenseMap<const CXXMethodDecl *, MethodInfo> MethodInfoMapTy;
868
869
870
871 MethodInfoMapTy MethodInfoMap;
872
873
874
875 MethodVTableIndicesTy MethodVTableIndices;
876
877 typedef llvm::DenseMap<uint64_t, ThunkInfo> VTableThunksMapTy;
878
879
880
881 VTableThunksMapTy VTableThunks;
882
884 typedef llvm::DenseMap<const CXXMethodDecl *, ThunkInfoVectorTy> ThunksMapTy;
885
886
887
888 ThunksMapTy Thunks;
889
890
892
893
894
895 void ComputeThisAdjustments();
896
898
899
900
901 VisitedVirtualBasesSetTy PrimaryVirtualBases;
902
903
904
906
907
908
911
912
913
914
917 CharUnits BaseOffsetInLayoutClass,
918 FinalOverriders::OverriderInfo Overrider);
919
920
921
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943 bool IsOverriderUsed(const CXXMethodDecl *Overrider,
944 CharUnits BaseOffsetInLayoutClass,
945 const CXXRecordDecl *FirstBaseInPrimaryBaseChain,
946 CharUnits FirstBaseOffsetInLayoutClass) const;
947
948
949
950
952 const CXXRecordDecl *FirstBaseInPrimaryBaseChain,
953 CharUnits FirstBaseOffsetInLayoutClass,
954 PrimaryBasesSetVectorTy &PrimaryBases);
955
956
957
958 void LayoutVTable();
959
960
961
962
963
964
965
966
967
969 bool BaseIsMorallyVirtual,
970 bool BaseIsVirtualInLayoutClass,
972
973
974
975
976
977
978 void LayoutSecondaryVTables(BaseSubobject Base, bool BaseIsMorallyVirtual,
980
981
982
983 void DeterminePrimaryVirtualBases(const CXXRecordDecl *RD,
985 VisitedVirtualBasesSetTy &VBases);
986
987
988
989 void LayoutVTablesForVirtualBases(const CXXRecordDecl *RD,
990 VisitedVirtualBasesSetTy &VBases);
991
992
993
994 bool isBuildingConstructorVTable() const {
995 return MostDerivedClass != LayoutClass;
996 }
997
998public:
999
1000
1002
1005 CharUnits MostDerivedClassOffset,
1006 bool MostDerivedClassIsVirtual,
1008 : VTables(VTables), MostDerivedClass(MostDerivedClass),
1009 MostDerivedClassOffset(MostDerivedClassOffset),
1010 MostDerivedClassIsVirtual(MostDerivedClassIsVirtual),
1011 LayoutClass(LayoutClass), Context(MostDerivedClass->getASTContext()),
1012 Overriders(MostDerivedClass, MostDerivedClassOffset, LayoutClass) {
1014
1015 LayoutVTable();
1016
1017 if (Context.getLangOpts().DumpVTableLayouts)
1018 dumpLayout(llvm::outs());
1019 }
1020
1021 uint64_t getNumThunks() const {
1022 return Thunks.size();
1023 }
1024
1025 ThunksMapTy::const_iterator thunks_begin() const {
1026 return Thunks.begin();
1027 }
1028
1029 ThunksMapTy::const_iterator thunks_end() const {
1030 return Thunks.end();
1031 }
1032
1033 const VBaseOffsetOffsetsMapTy &getVBaseOffsetOffsets() const {
1034 return VBaseOffsetOffsets;
1035 }
1036
1037 const AddressPointsMapTy &getAddressPoints() const {
1038 return AddressPoints;
1039 }
1040
1041 MethodVTableIndicesTy::const_iterator vtable_indices_begin() const {
1042 return MethodVTableIndices.begin();
1043 }
1044
1045 MethodVTableIndicesTy::const_iterator vtable_indices_end() const {
1046 return MethodVTableIndices.end();
1047 }
1048
1050
1051 AddressPointsMapTy::const_iterator address_points_begin() const {
1052 return AddressPoints.begin();
1053 }
1054
1055 AddressPointsMapTy::const_iterator address_points_end() const {
1056 return AddressPoints.end();
1057 }
1058
1059 VTableThunksMapTy::const_iterator vtable_thunks_begin() const {
1060 return VTableThunks.begin();
1061 }
1062
1063 VTableThunksMapTy::const_iterator vtable_thunks_end() const {
1064 return VTableThunks.end();
1065 }
1066
1067
1068 void dumpLayout(raw_ostream&);
1069};
1070
1071void ItaniumVTableBuilder::AddThunk(const CXXMethodDecl *MD,
1073 assert(!isBuildingConstructorVTable() &&
1074 "Can't add thunks for construction vtable");
1075
1077
1078
1079 if (llvm::is_contained(ThunksVector, Thunk))
1080 return;
1081
1082 ThunksVector.push_back(Thunk);
1083}
1084
1086
1087
1088
1089
1090
1091template
1092static void
1093visitAllOverriddenMethods(const CXXMethodDecl *MD, VisitorTy &Visitor) {
1095
1097 if (!Visitor(OverriddenMD))
1098 continue;
1099 visitAllOverriddenMethods(OverriddenMD, Visitor);
1100 }
1101}
1102
1103
1104
1105static void
1106ComputeAllOverriddenMethods(const CXXMethodDecl *MD,
1107 OverriddenMethodsSetTy& OverriddenMethods) {
1108 auto OverriddenMethodsCollector = [&](const CXXMethodDecl *MD) {
1109
1110 return OverriddenMethods.insert(MD).second;
1111 };
1112 visitAllOverriddenMethods(MD, OverriddenMethodsCollector);
1113}
1114
1115void ItaniumVTableBuilder::ComputeThisAdjustments() {
1116
1117
1118 for (const auto &MI : MethodInfoMap) {
1120 const MethodInfo &MethodInfo = MI.second;
1121
1122
1123 uint64_t VTableIndex = MethodInfo.VTableIndex;
1124 if (Components[VTableIndex].getKind() ==
1126 continue;
1127
1128
1129 FinalOverriders::OverriderInfo Overrider =
1130 Overriders.getOverrider(MD, MethodInfo.BaseOffset);
1131
1132
1133 if (MethodInfo.BaseOffsetInLayoutClass == Overrider.Offset) {
1134
1135
1136
1137
1138
1139 if (VTableThunks.lookup(VTableIndex).Return.isEmpty())
1140 continue;
1141 }
1142
1144 ComputeThisAdjustment(MD, MethodInfo.BaseOffsetInLayoutClass, Overrider);
1145
1147 continue;
1148
1149
1150 auto SetThisAdjustmentThunk = [&](uint64_t Idx) {
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172 if (!VTableThunks.count(Idx)) {
1173 const CXXMethodDecl *Method = VTables.findOriginalMethodInMap(MD);
1174 VTableThunks[Idx].Method = Method;
1176 }
1178 };
1179
1180 SetThisAdjustmentThunk(VTableIndex);
1181
1182 if (isa(MD)) {
1183
1184 SetThisAdjustmentThunk(VTableIndex + 1);
1185 }
1186 }
1187
1188
1189 MethodInfoMap.clear();
1190
1191 if (isBuildingConstructorVTable()) {
1192
1193 return;
1194 }
1195
1196 for (const auto &TI : VTableThunks) {
1197 const VTableComponent &Component = Components[TI.first];
1198 const ThunkInfo &Thunk = TI.second;
1200
1201 switch (Component.getKind()) {
1202 default:
1203 llvm_unreachable("Unexpected vtable component kind!");
1206 break;
1209 break;
1211
1212 continue;
1213 }
1214
1215 if (MD->getParent() == MostDerivedClass)
1216 AddThunk(MD, Thunk);
1217 }
1218}
1219
1221ItaniumVTableBuilder::ComputeReturnAdjustment(BaseOffset Offset) {
1223
1224 if (!Offset.isEmpty()) {
1225 if (Offset.VirtualBase) {
1226
1227 if (Offset.DerivedClass == MostDerivedClass) {
1228
1230 VBaseOffsetOffsets.lookup(Offset.VirtualBase).getQuantity();
1231 } else {
1233 VTables.getVirtualBaseOffsetOffset(Offset.DerivedClass,
1234 Offset.VirtualBase).getQuantity();
1235 }
1236 }
1237
1238 Adjustment.NonVirtual = Offset.NonVirtualOffset.getQuantity();
1239 }
1240
1241 return Adjustment;
1242}
1243
1244BaseOffset ItaniumVTableBuilder::ComputeThisAdjustmentBaseOffset(
1248
1249 CXXBasePaths Paths(true,
1250 true, true);
1251
1253 llvm_unreachable("Class must be derived from the passed in base class!");
1254
1255
1256
1258 BaseOffset Offset = ComputeBaseOffset(Context, DerivedRD, Path);
1259
1260 CharUnits OffsetToBaseSubobject = Offset.NonVirtualOffset;
1261
1262 if (Offset.VirtualBase) {
1263
1264
1267
1268
1269
1270 OffsetToBaseSubobject +=
1272 } else {
1273
1274
1275 OffsetToBaseSubobject += Derived.getBaseOffset();
1276 }
1277
1278
1279 if (OffsetToBaseSubobject == Base.getBaseOffset()) {
1280
1281
1282 Offset.NonVirtualOffset = -Offset.NonVirtualOffset;
1283 return Offset;
1284 }
1285 }
1286
1287 return BaseOffset();
1288}
1289
1290ThisAdjustment ItaniumVTableBuilder::ComputeThisAdjustment(
1292 FinalOverriders::OverriderInfo Overrider) {
1293
1294 if (Overrider.Method->isPureVirtual())
1296
1298 BaseOffsetInLayoutClass);
1299
1300 BaseSubobject OverriderBaseSubobject(Overrider.Method->getParent(),
1301 Overrider.Offset);
1302
1303
1304 BaseOffset Offset = ComputeThisAdjustmentBaseOffset(OverriddenBaseSubobject,
1305 OverriderBaseSubobject);
1306 if (Offset.isEmpty())
1308
1310
1311 if (Offset.VirtualBase) {
1312
1313 VCallOffsetMap &VCallOffsets = VCallOffsetsForVBases[Offset.VirtualBase];
1314
1315 if (VCallOffsets.empty()) {
1316
1317
1318 VCallAndVBaseOffsetBuilder Builder(
1319 VTables, MostDerivedClass, MostDerivedClass,
1320 nullptr,
1322 true,
1323
1325
1326 VCallOffsets = Builder.getVCallOffsets();
1327 }
1328
1330 VCallOffsets.getVCallOffsetOffset(MD).getQuantity();
1331 }
1332
1333
1334 Adjustment.NonVirtual = Offset.NonVirtualOffset.getQuantity();
1335
1336 return Adjustment;
1337}
1338
1339void ItaniumVTableBuilder::AddMethod(const CXXMethodDecl *MD,
1341 if (const CXXDestructorDecl *DD = dyn_cast(MD)) {
1343 "Destructor can't have return adjustment!");
1344
1345
1348 } else {
1349
1352
1353
1355 }
1356}
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369static bool OverridesIndirectMethodInBases(
1372 if (Bases.count(MD->getParent()))
1373 return true;
1374
1376
1377 if (OverridesIndirectMethodInBases(OverriddenMD, Bases))
1378 return true;
1379 }
1380
1381 return false;
1382}
1383
1384bool ItaniumVTableBuilder::IsOverriderUsed(
1386 const CXXRecordDecl *FirstBaseInPrimaryBaseChain,
1387 CharUnits FirstBaseOffsetInLayoutClass) const {
1388
1389
1390 if (BaseOffsetInLayoutClass == FirstBaseOffsetInLayoutClass)
1391 return true;
1392
1393
1394
1395
1396
1397
1398
1399 if (Overrider->getParent() == FirstBaseInPrimaryBaseChain)
1400 return true;
1401
1403
1404 const CXXRecordDecl *RD = FirstBaseInPrimaryBaseChain;
1405 PrimaryBases.insert(RD);
1406
1407
1408
1409 while (true) {
1412
1413 if (!PrimaryBase)
1414 break;
1415
1418 "Primary base should always be at offset 0!");
1419
1422
1423
1424
1426 FirstBaseOffsetInLayoutClass) {
1427
1428 break;
1429 }
1430 } else {
1432 "Primary base should always be at offset 0!");
1433 }
1434
1435 if (!PrimaryBases.insert(PrimaryBase))
1436 llvm_unreachable("Found a duplicate primary base!");
1437
1438 RD = PrimaryBase;
1439 }
1440
1441
1442
1443 return OverridesIndirectMethodInBases(Overrider, PrimaryBases);
1444}
1445
1447
1448
1449
1450
1452FindNearestOverriddenMethod(const CXXMethodDecl *MD,
1453 BasesSetVectorTy &Bases) {
1454 OverriddenMethodsSetTy OverriddenMethods;
1455 ComputeAllOverriddenMethods(MD, OverriddenMethods);
1456
1457 for (const CXXRecordDecl *PrimaryBase : llvm::reverse(Bases)) {
1458
1459 for (const CXXMethodDecl *OverriddenMD : OverriddenMethods) {
1460
1461 if (OverriddenMD->getParent() == PrimaryBase)
1462 return OverriddenMD;
1463 }
1464 }
1465
1466 return nullptr;
1467}
1468
1469void ItaniumVTableBuilder::AddMethods(
1471 const CXXRecordDecl *FirstBaseInPrimaryBaseChain,
1472 CharUnits FirstBaseOffsetInLayoutClass,
1473 PrimaryBasesSetVectorTy &PrimaryBases) {
1474
1475
1476
1477
1478
1479
1480
1481
1482
1485
1488 CharUnits PrimaryBaseOffsetInLayoutClass;
1491 "Primary vbase should have a zero offset!");
1492
1495
1496 PrimaryBaseOffset =
1498
1501
1502 PrimaryBaseOffsetInLayoutClass =
1504 } else {
1506 "Primary base should have a zero offset!");
1507
1508 PrimaryBaseOffset = Base.getBaseOffset();
1509 PrimaryBaseOffsetInLayoutClass = BaseOffsetInLayoutClass;
1510 }
1511
1512 AddMethods(BaseSubobject(PrimaryBase, PrimaryBaseOffset),
1513 PrimaryBaseOffsetInLayoutClass, FirstBaseInPrimaryBaseChain,
1514 FirstBaseOffsetInLayoutClass, PrimaryBases);
1515
1516 if (!PrimaryBases.insert(PrimaryBase))
1517 llvm_unreachable("Found a duplicate primary base!");
1518 }
1519
1521 NewVirtualFunctionsTy NewVirtualFunctions;
1522
1524
1525
1526 for (const auto *MD : RD->methods()) {
1527 if (!ItaniumVTableContext::hasVtableSlot(MD))
1528 continue;
1530
1531
1532 FinalOverriders::OverriderInfo Overrider =
1533 Overriders.getOverrider(MD, Base.getBaseOffset());
1534
1535
1536
1537
1539 FindNearestOverriddenMethod(MD, PrimaryBases)) {
1540 if (ComputeReturnAdjustmentBaseOffset(Context, MD,
1541 OverriddenMD).isEmpty()) {
1542 VTables.setOriginalMethod(MD, OverriddenMD);
1543
1544
1545
1546 assert(MethodInfoMap.count(OverriddenMD) &&
1547 "Did not find the overridden method!");
1548 MethodInfo &OverriddenMethodInfo = MethodInfoMap[OverriddenMD];
1549
1550 MethodInfo MethodInfo(Base.getBaseOffset(), BaseOffsetInLayoutClass,
1551 OverriddenMethodInfo.VTableIndex);
1552
1553 assert(!MethodInfoMap.count(MD) &&
1554 "Should not have method info for this method yet!");
1555
1556 MethodInfoMap.insert(std::make_pair(MD, MethodInfo));
1557 MethodInfoMap.erase(OverriddenMD);
1558
1559
1560
1561
1562
1563 if (!isBuildingConstructorVTable() && OverriddenMD != MD) {
1564
1566 ComputeThisAdjustment(OverriddenMD, BaseOffsetInLayoutClass,
1567 Overrider);
1568
1570 Overrider.Method->getParent() == MostDerivedClass) {
1571
1572
1573
1574
1575 BaseOffset ReturnAdjustmentOffset =
1576 ComputeReturnAdjustmentBaseOffset(Context, Overrider.Method, MD);
1578 ComputeReturnAdjustment(ReturnAdjustmentOffset);
1579
1580
1581 AddThunk(Overrider.Method,
1583 OverriddenMD->getThisType().getTypePtr()));
1584 }
1585 }
1586
1587 continue;
1588 }
1589 }
1590
1592 NewImplicitVirtualFunctions.push_back(MD);
1593 else
1594 NewVirtualFunctions.push_back(MD);
1595 }
1596
1597 std::stable_sort(
1598 NewImplicitVirtualFunctions.begin(), NewImplicitVirtualFunctions.end(),
1600 if (A == B)
1601 return false;
1602 if (A->isCopyAssignmentOperator() != B->isCopyAssignmentOperator())
1603 return A->isCopyAssignmentOperator();
1604 if (A->isMoveAssignmentOperator() != B->isMoveAssignmentOperator())
1605 return A->isMoveAssignmentOperator();
1606 if (isa(A) != isa(B))
1607 return isa(A);
1608 assert(A->getOverloadedOperator() == OO_EqualEqual &&
1609 B->getOverloadedOperator() == OO_EqualEqual &&
1610 "unexpected or duplicate implicit virtual function");
1611
1612
1613 return false;
1614 });
1615 NewVirtualFunctions.append(NewImplicitVirtualFunctions.begin(),
1616 NewImplicitVirtualFunctions.end());
1617
1618 for (const CXXMethodDecl *MD : NewVirtualFunctions) {
1619
1620 FinalOverriders::OverriderInfo Overrider =
1621 Overriders.getOverrider(MD, Base.getBaseOffset());
1622
1623
1624 MethodInfo MethodInfo(Base.getBaseOffset(), BaseOffsetInLayoutClass,
1625 Components.size());
1626
1627 assert(!MethodInfoMap.count(MD) &&
1628 "Should not have method info for this method yet!");
1629 MethodInfoMap.insert(std::make_pair(MD, MethodInfo));
1630
1631
1632 const CXXMethodDecl *OverriderMD = Overrider.Method;
1633 if (!IsOverriderUsed(OverriderMD, BaseOffsetInLayoutClass,
1634 FirstBaseInPrimaryBaseChain,
1635 FirstBaseOffsetInLayoutClass)) {
1637 continue;
1638 }
1639
1640
1641
1642 BaseOffset ReturnAdjustmentOffset;
1644 ReturnAdjustmentOffset =
1645 ComputeReturnAdjustmentBaseOffset(Context, OverriderMD, MD);
1646 }
1647
1649 ComputeReturnAdjustment(ReturnAdjustmentOffset);
1650
1651
1652
1653
1654
1656 VTableThunks[Components.size()].Method = MD;
1658 }
1659
1661 }
1662}
1663
1664void ItaniumVTableBuilder::LayoutVTable() {
1665 LayoutPrimaryAndSecondaryVTables(BaseSubobject(MostDerivedClass,
1667 false,
1668 MostDerivedClassIsVirtual,
1669 MostDerivedClassOffset);
1670
1671 VisitedVirtualBasesSetTy VBases;
1672
1673
1674 DeterminePrimaryVirtualBases(MostDerivedClass, MostDerivedClassOffset,
1675 VBases);
1676 VBases.clear();
1677
1678 LayoutVTablesForVirtualBases(MostDerivedClass, VBases);
1679
1680
1681 bool IsAppleKext = Context.getLangOpts().AppleKext;
1682 if (IsAppleKext)
1684}
1685
1686void ItaniumVTableBuilder::LayoutPrimaryAndSecondaryVTables(
1688 bool BaseIsVirtualInLayoutClass, CharUnits OffsetInLayoutClass) {
1689 assert(Base.getBase()->isDynamicClass() && "class does not have a vtable!");
1690
1691 unsigned VTableIndex = Components.size();
1692 VTableIndices.push_back(VTableIndex);
1693
1694
1695 VCallAndVBaseOffsetBuilder Builder(
1696 VTables, MostDerivedClass, LayoutClass, &Overriders, Base,
1697 BaseIsVirtualInLayoutClass, OffsetInLayoutClass);
1698 Components.append(Builder.components_begin(), Builder.components_end());
1699
1700
1701 if (BaseIsVirtualInLayoutClass && !Builder.getVCallOffsets().empty()) {
1702 VCallOffsetMap &VCallOffsets = VCallOffsetsForVBases[Base.getBase()];
1703
1704 if (VCallOffsets.empty())
1705 VCallOffsets = Builder.getVCallOffsets();
1706 }
1707
1708
1709
1710 if (Base.getBase() == MostDerivedClass)
1711 VBaseOffsetOffsets = Builder.getVBaseOffsetOffsets();
1712
1713
1714 CharUnits OffsetToTop = MostDerivedClassOffset - OffsetInLayoutClass;
1716
1717
1718 if (!Context.getLangOpts().OmitVTableRTTI)
1720
1721 uint64_t AddressPoint = Components.size();
1722
1723
1724 PrimaryBasesSetVectorTy PrimaryBases;
1725 AddMethods(Base, OffsetInLayoutClass,
1726 Base.getBase(), OffsetInLayoutClass,
1727 PrimaryBases);
1728
1730 if (RD == MostDerivedClass) {
1731 assert(MethodVTableIndices.empty());
1732 for (const auto &I : MethodInfoMap) {
1734 const MethodInfo &MI = I.second;
1735 if (const CXXDestructorDecl *DD = dyn_cast(MD)) {
1737 = MI.VTableIndex - AddressPoint;
1739 = MI.VTableIndex + 1 - AddressPoint;
1740 } else {
1741 MethodVTableIndices[MD] = MI.VTableIndex - AddressPoint;
1742 }
1743 }
1744 }
1745
1746
1747 ComputeThisAdjustments();
1748
1749
1750 while (true) {
1751 AddressPoints.insert(
1752 std::make_pair(BaseSubobject(RD, OffsetInLayoutClass),
1754 unsigned(VTableIndices.size() - 1),
1755 unsigned(AddressPoint - VTableIndex)}));
1756
1759
1760 if (!PrimaryBase)
1761 break;
1762
1764
1765
1768
1770 OffsetInLayoutClass) {
1771
1772 break;
1773 }
1774 }
1775
1776 RD = PrimaryBase;
1777 }
1778
1779
1780 LayoutSecondaryVTables(Base, BaseIsMorallyVirtual, OffsetInLayoutClass);
1781}
1782
1783void
1785 bool BaseIsMorallyVirtual,
1786 CharUnits OffsetInLayoutClass) {
1787
1788
1789
1790
1791
1795
1796 for (const auto &B : RD->bases()) {
1797
1798 if (B.isVirtual())
1799 continue;
1800
1801 const CXXRecordDecl *BaseDecl = B.getType()->getAsCXXRecordDecl();
1802
1803
1805 continue;
1806
1807 if (isBuildingConstructorVTable()) {
1808
1809
1810
1811
1812
1813 if (!BaseIsMorallyVirtual && !BaseDecl->getNumVBases())
1814 continue;
1815 }
1816
1817
1819 CharUnits BaseOffset = Base.getBaseOffset() + RelativeBaseOffset;
1820
1821 CharUnits BaseOffsetInLayoutClass =
1822 OffsetInLayoutClass + RelativeBaseOffset;
1823
1824
1825
1826 if (BaseDecl == PrimaryBase) {
1827 LayoutSecondaryVTables(BaseSubobject(BaseDecl, BaseOffset),
1828 BaseIsMorallyVirtual, BaseOffsetInLayoutClass);
1829 continue;
1830 }
1831
1832
1833 LayoutPrimaryAndSecondaryVTables(
1835 BaseIsMorallyVirtual,
1836 false,
1837 BaseOffsetInLayoutClass);
1838 }
1839}
1840
1841void ItaniumVTableBuilder::DeterminePrimaryVirtualBases(
1843 VisitedVirtualBasesSetTy &VBases) {
1845
1846
1848
1849
1851 bool IsPrimaryVirtualBase = true;
1852
1853 if (isBuildingConstructorVTable()) {
1854
1855
1858
1859 CharUnits PrimaryBaseOffsetInLayoutClass =
1861
1862
1863
1864 if (PrimaryBaseOffsetInLayoutClass != OffsetInLayoutClass)
1865 IsPrimaryVirtualBase = false;
1866 }
1867
1868 if (IsPrimaryVirtualBase)
1869 PrimaryVirtualBases.insert(PrimaryBase);
1870 }
1871 }
1872
1873
1874 for (const auto &B : RD->bases()) {
1875 const CXXRecordDecl *BaseDecl = B.getType()->getAsCXXRecordDecl();
1876
1877 CharUnits BaseOffsetInLayoutClass;
1878
1879 if (B.isVirtual()) {
1880 if (!VBases.insert(BaseDecl).second)
1881 continue;
1882
1885
1886 BaseOffsetInLayoutClass =
1888 } else {
1889 BaseOffsetInLayoutClass =
1891 }
1892
1893 DeterminePrimaryVirtualBases(BaseDecl, BaseOffsetInLayoutClass, VBases);
1894 }
1895}
1896
1897void ItaniumVTableBuilder::LayoutVTablesForVirtualBases(
1898 const CXXRecordDecl *RD, VisitedVirtualBasesSetTy &VBases) {
1899
1900
1901
1902
1903 for (const auto &B : RD->bases()) {
1904 const CXXRecordDecl *BaseDecl = B.getType()->getAsCXXRecordDecl();
1905
1906
1907
1909 !PrimaryVirtualBases.count(BaseDecl) &&
1910 VBases.insert(BaseDecl).second) {
1915
1918 CharUnits BaseOffsetInLayoutClass =
1920
1921 LayoutPrimaryAndSecondaryVTables(
1923 true,
1924 true,
1925 BaseOffsetInLayoutClass);
1926 }
1927
1928
1929
1931 LayoutVTablesForVirtualBases(BaseDecl, VBases);
1932 }
1933}
1934
1935static void printThunkMethod(const ThunkInfo &Info, raw_ostream &Out) {
1937 return;
1939 PredefinedIdentKind::PrettyFunctionNoVirtual, Info.Method);
1940 Out << " method: " << Str;
1941}
1942
1943
1944void ItaniumVTableBuilder::dumpLayout(raw_ostream &Out) {
1945
1946
1947
1948 Out << "Original map\n";
1949
1950 for (const auto &P : VTables.getOriginalMethodMap()) {
1951 std::string Str0 =
1953 P.first);
1954 std::string Str1 =
1956 P.second);
1957 Out << " " << Str0 << " -> " << Str1 << "\n";
1958 }
1959
1960 if (isBuildingConstructorVTable()) {
1961 Out << "Construction vtable for ('";
1963 Out << "', ";
1964 Out << MostDerivedClassOffset.getQuantity() << ") in '";
1966 } else {
1967 Out << "Vtable for '";
1969 }
1970 Out << "' (" << Components.size() << " entries).\n";
1971
1972
1973
1974
1975
1976 std::multimap<uint64_t, BaseSubobject> AddressPointsByIndex;
1977 for (const auto &AP : AddressPoints) {
1979 uint64_t Index =
1980 VTableIndices[AP.second.VTableIndex] + AP.second.AddressPointIndex;
1981
1982 AddressPointsByIndex.insert(std::make_pair(Index, Base));
1983 }
1984
1985 for (unsigned I = 0, E = Components.size(); I != E; ++I) {
1986 uint64_t Index = I;
1987
1988 Out << llvm::format("%4d | ", I);
1989
1991
1992
1993 switch (Component.getKind()) {
1994
1996 Out << "vcall_offset ("
1998 << ")";
1999 break;
2000
2002 Out << "vbase_offset ("
2004 << ")";
2005 break;
2006
2008 Out << "offset_to_top ("
2010 << ")";
2011 break;
2012
2015 Out << " RTTI";
2016 break;
2017
2020
2022 PredefinedIdentKind::PrettyFunctionNoVirtual, MD);
2023 Out << Str;
2025 Out << " [pure]";
2026
2028 Out << " [deleted]";
2029
2030 ThunkInfo Thunk = VTableThunks.lookup(I);
2032
2034 Out << "\n [return adjustment: ";
2036
2039 Out << " vbase offset offset";
2040 }
2041
2042 Out << ']';
2043 printThunkMethod(Thunk, Out);
2044 }
2045
2046
2048 Out << "\n [this adjustment: ";
2050
2053 Out << " vcall offset offset";
2054 }
2055
2056 Out << ']';
2057 printThunkMethod(Thunk, Out);
2058 }
2059 }
2060
2061 break;
2062 }
2063
2066 bool IsComplete =
2068
2070
2072 if (IsComplete)
2073 Out << "() [complete]";
2074 else
2075 Out << "() [deleting]";
2076
2078 Out << " [pure]";
2079
2080 ThunkInfo Thunk = VTableThunks.lookup(I);
2082
2084 Out << "\n [this adjustment: ";
2086
2089 Out << " vcall offset offset";
2090 }
2091
2092 Out << ']';
2093 }
2094 printThunkMethod(Thunk, Out);
2095 }
2096
2097 break;
2098 }
2099
2102
2104 PredefinedIdentKind::PrettyFunctionNoVirtual, MD);
2105 Out << "[unused] " << Str;
2107 Out << " [pure]";
2108 }
2109
2110 }
2111
2112 Out << '\n';
2113
2114
2115 uint64_t NextIndex = Index + 1;
2116 if (AddressPointsByIndex.count(NextIndex)) {
2117 if (AddressPointsByIndex.count(NextIndex) == 1) {
2119 AddressPointsByIndex.find(NextIndex)->second;
2120
2121 Out << " -- (";
2122 Base.getBase()->printQualifiedName(Out);
2123 Out << ", " << Base.getBaseOffset().getQuantity();
2124 Out << ") vtable address --\n";
2125 } else {
2127 AddressPointsByIndex.lower_bound(NextIndex)->second.getBaseOffset();
2128
2129
2130 std::setstd::string ClassNames;
2131 for (const auto &I :
2132 llvm::make_range(AddressPointsByIndex.equal_range(NextIndex))) {
2133 assert(I.second.getBaseOffset() == BaseOffset &&
2134 "Invalid base offset!");
2137 }
2138
2139 for (const std::string &Name : ClassNames) {
2140 Out << " -- (" << Name;
2141 Out << ", " << BaseOffset.getQuantity() << ") vtable address --\n";
2142 }
2143 }
2144 }
2145 }
2146
2147 Out << '\n';
2148
2149 if (isBuildingConstructorVTable())
2150 return;
2151
2153
2154
2155
2156 std::map<std::string, CharUnits> ClassNamesAndOffsets;
2157 for (const auto &I : VBaseOffsetOffsets) {
2158 std::string ClassName = I.first->getQualifiedNameAsString();
2159 CharUnits OffsetOffset = I.second;
2160 ClassNamesAndOffsets.insert(std::make_pair(ClassName, OffsetOffset));
2161 }
2162
2163 Out << "Virtual base offset offsets for '";
2165 Out << "' (";
2166 Out << ClassNamesAndOffsets.size();
2167 Out << (ClassNamesAndOffsets.size() == 1 ? " entry" : " entries") << ").\n";
2168
2169 for (const auto &I : ClassNamesAndOffsets)
2170 Out << " " << I.first << " | " << I.second.getQuantity() << '\n';
2171
2172 Out << "\n";
2173 }
2174
2175 if (!Thunks.empty()) {
2176
2177 std::map<std::string, const CXXMethodDecl *> MethodNamesAndDecls;
2178
2179 for (const auto &I : Thunks) {
2182 PredefinedIdentKind::PrettyFunctionNoVirtual, MD);
2183
2184 MethodNamesAndDecls.insert(std::make_pair(MethodName, MD));
2185 }
2186
2187 for (const auto &I : MethodNamesAndDecls) {
2188 const std::string &MethodName = I.first;
2190
2191 ThunkInfoVectorTy ThunksVector = Thunks[MD];
2192 llvm::sort(ThunksVector, [](const ThunkInfo &LHS, const ThunkInfo &RHS) {
2194 });
2195
2196 Out << "Thunks for '" << MethodName << "' (" << ThunksVector.size();
2197 Out << (ThunksVector.size() == 1 ? " entry" : " entries") << ").\n";
2198
2199 for (unsigned I = 0, E = ThunksVector.size(); I != E; ++I) {
2200 const ThunkInfo &Thunk = ThunksVector[I];
2201
2202 Out << llvm::format("%4d | ", I);
2203
2204
2207 Out << " non-virtual";
2210 Out << " vbase offset offset";
2211 }
2212
2214 Out << "\n ";
2215 }
2216
2217
2219 Out << "this adjustment: ";
2221
2224 Out << " vcall offset offset";
2225 }
2226 }
2227
2228 Out << '\n';
2229 }
2230
2231 Out << '\n';
2232 }
2233 }
2234
2235
2236
2237 std::map<uint64_t, std::string> IndicesMap;
2238
2239 for (const auto *MD : MostDerivedClass->methods()) {
2240
2241 if (!ItaniumVTableContext::hasVtableSlot(MD))
2242 continue;
2244
2246 PredefinedIdentKind::PrettyFunctionNoVirtual, MD);
2247
2248 if (const CXXDestructorDecl *DD = dyn_cast(MD)) {
2250 assert(MethodVTableIndices.count(GD));
2251 uint64_t VTableIndex = MethodVTableIndices[GD];
2252 IndicesMap[VTableIndex] = MethodName + " [complete]";
2253 IndicesMap[VTableIndex + 1] = MethodName + " [deleting]";
2254 } else {
2255 assert(MethodVTableIndices.count(MD));
2256 IndicesMap[MethodVTableIndices[MD]] = MethodName;
2257 }
2258 }
2259
2260
2261 if (!IndicesMap.empty()) {
2262 Out << "VTable indices for '";
2264 Out << "' (" << IndicesMap.size() << " entries).\n";
2265
2266 for (const auto &I : IndicesMap) {
2267 uint64_t VTableIndex = I.first;
2268 const std::string &MethodName = I.second;
2269
2270 Out << llvm::format("%4" PRIu64 " | ", VTableIndex) << MethodName
2271 << '\n';
2272 }
2273 }
2274
2275 Out << '\n';
2276}
2277}
2278
2281 unsigned numVTables) {
2283
2284 for (auto it = addressPoints.begin(); it != addressPoints.end(); ++it) {
2285 const auto &addressPointLoc = it->second;
2286 unsigned vtableIndex = addressPointLoc.VTableIndex;
2287 unsigned addressPoint = addressPointLoc.AddressPointIndex;
2288 if (indexMap[vtableIndex]) {
2289
2290
2291 assert(indexMap[vtableIndex] == addressPoint &&
2292 "Every vtable index should have a unique address point. Found a "
2293 "vtable that has two different address points.");
2294 } else {
2295 indexMap[vtableIndex] = addressPoint;
2296 }
2297 }
2298
2299
2300
2301
2302
2303 return indexMap;
2304}
2305
2310 : VTableComponents(VTableComponents), VTableThunks(VTableThunks),
2312 AddressPoints, VTableIndices.size())) {
2313 if (VTableIndices.size() <= 1)
2314 assert(VTableIndices.size() == 1 && VTableIndices[0] == 0);
2315 else
2317
2320 assert((LHS.first != RHS.first || LHS.second == RHS.second) &&
2321 "Different thunks should have unique indices!");
2322 return LHS.first < RHS.first;
2323 });
2324}
2325
2327
2330}
2331
2335
2337
2340 MethodVTableIndicesTy::iterator I = MethodVTableIndices.find(GD);
2341 if (I != MethodVTableIndices.end())
2342 return I->second;
2343
2345
2346 computeVTableRelatedInformation(RD);
2347
2348 I = MethodVTableIndices.find(GD);
2349 assert(I != MethodVTableIndices.end() && "Did not find index!");
2350 return I->second;
2351}
2352
2356 ClassPairTy ClassPair(RD, VBase);
2357
2358 VirtualBaseClassOffsetOffsetsMapTy::iterator I =
2359 VirtualBaseClassOffsetOffsets.find(ClassPair);
2360 if (I != VirtualBaseClassOffsetOffsets.end())
2361 return I->second;
2362
2363 VCallAndVBaseOffsetBuilder Builder(*this, RD, RD, nullptr,
2365 false,
2367
2368 for (const auto &I : Builder.getVBaseOffsetOffsets()) {
2369
2370 ClassPairTy ClassPair(RD, I.first);
2371
2372 VirtualBaseClassOffsetOffsets.insert(std::make_pair(ClassPair, I.second));
2373 }
2374
2375 I = VirtualBaseClassOffsetOffsets.find(ClassPair);
2376 assert(I != VirtualBaseClassOffsetOffsets.end() && "Did not find index!");
2377
2378 return I->second;
2379}
2380
2382 const auto *MD = cast(GD.getDecl());
2383 computeVTableRelatedInformation(MD->getParent());
2385
2386 if (const auto *DD = dyn_cast(OriginalMD))
2388 return OriginalMD;
2389}
2390
2393
2394
2395 while (true) {
2396 auto I = OriginalMethodMap.find(MD);
2397
2398
2399
2400 if (I == OriginalMethodMap.end())
2401 break;
2402
2403
2404 MD = I->second;
2405 }
2406
2407 return MD;
2408}
2409
2410static std::unique_ptr
2413 VTableThunks(Builder.vtable_thunks_begin(), Builder.vtable_thunks_end());
2414
2415 return std::make_unique(
2416 Builder.VTableIndices, Builder.vtable_components(), VTableThunks,
2417 Builder.getAddressPoints());
2418}
2419
2420void
2421ItaniumVTableContext::computeVTableRelatedInformation(const CXXRecordDecl *RD) {
2422 std::unique_ptr &Entry = VTableLayouts[RD];
2423
2424
2425 if (Entry)
2426 return;
2427
2428 ItaniumVTableBuilder Builder(*this, RD, CharUnits::Zero(),
2429 false, RD);
2431
2432 MethodVTableIndices.insert(Builder.vtable_indices_begin(),
2433 Builder.vtable_indices_end());
2434
2435
2436 Thunks.insert(Builder.thunks_begin(), Builder.thunks_end());
2437
2438
2439
2440
2442 return;
2443
2446
2447 if (VirtualBaseClassOffsetOffsets.count(std::make_pair(RD, VBase)))
2448 return;
2449
2450 for (const auto &I : Builder.getVBaseOffsetOffsets()) {
2451
2452 ClassPairTy ClassPair(RD, I.first);
2453
2454 VirtualBaseClassOffsetOffsets.insert(std::make_pair(ClassPair, I.second));
2455 }
2456}
2457
2458std::unique_ptr
2461 bool MostDerivedClassIsVirtual, const CXXRecordDecl *LayoutClass) {
2462 ItaniumVTableBuilder Builder(*this, MostDerivedClass, MostDerivedClassOffset,
2463 MostDerivedClassIsVirtual, LayoutClass);
2465}
2466
2467namespace {
2468
2469
2470
2471
2472
2473
2474
2475
2476
2477
2478
2479
2480
2481
2482
2483
2484
2485
2486
2487
2488
2489
2490
2491
2492
2493
2494
2495
2496
2497
2498
2499
2500
2501
2502
2503
2504
2505
2506
2507
2508
2509
2510
2511class VFTableBuilder {
2512public:
2513 typedef llvm::DenseMap<GlobalDecl, MethodVFTableLocation>
2514 MethodVFTableLocationsTy;
2515
2516 typedef llvm::iterator_rangeMethodVFTableLocationsTy::const\_iterator
2517 method_locations_range;
2518
2519private:
2520
2522
2523
2525
2526
2527
2529
2531
2533
2534
2535 const FinalOverriders Overriders;
2536
2537
2539
2540 MethodVFTableLocationsTy MethodVFTableLocations;
2541
2542
2543 bool HasRTTIComponent = false;
2544
2545
2546
2547 struct MethodInfo {
2548
2549
2550 const uint64_t VBTableIndex;
2551
2552
2553 const uint64_t VFTableIndex;
2554
2555
2556
2557
2558 bool Shadowed;
2559
2560
2561
2562 bool UsesExtraSlot;
2563
2564 MethodInfo(uint64_t VBTableIndex, uint64_t VFTableIndex,
2565 bool UsesExtraSlot = false)
2566 : VBTableIndex(VBTableIndex), VFTableIndex(VFTableIndex),
2567 Shadowed(false), UsesExtraSlot(UsesExtraSlot) {}
2568
2569 MethodInfo()
2570 : VBTableIndex(0), VFTableIndex(0), Shadowed(false),
2571 UsesExtraSlot(false) {}
2572 };
2573
2574 typedef llvm::DenseMap<const CXXMethodDecl *, MethodInfo> MethodInfoMapTy;
2575
2576
2577
2578 MethodInfoMapTy MethodInfoMap;
2579
2580 typedef llvm::DenseMap<uint64_t, ThunkInfo> VTableThunksMapTy;
2581
2582
2583
2584 VTableThunksMapTy VTableThunks;
2585
2587 typedef llvm::DenseMap<const CXXMethodDecl *, ThunkInfoVectorTy> ThunksMapTy;
2588
2589
2590
2591 ThunksMapTy Thunks;
2592
2593
2596
2597
2598 if (llvm::is_contained(ThunksVector, Thunk))
2599 return;
2600
2601 ThunksVector.push_back(Thunk);
2602 }
2603
2604
2605
2606 CharUnits ComputeThisOffset(FinalOverriders::OverriderInfo Overrider);
2607
2608 void CalculateVtordispAdjustment(FinalOverriders::OverriderInfo Overrider,
2610
2611
2612
2615 VTableThunks[Components.size()] = TI;
2616 AddThunk(MD, TI);
2617 }
2618 if (const CXXDestructorDecl *DD = dyn_cast(MD)) {
2620 "Destructor can't have return adjustment!");
2622 } else {
2624 }
2625 }
2626
2627
2628
2631 BasesSetVectorTy &VisitedBases);
2632
2633 void LayoutVFTable() {
2634
2635 if (HasRTTIComponent)
2637
2638 BasesSetVectorTy VisitedBases;
2640 VisitedBases);
2641
2642
2643 assert(!Components.empty() && "vftable can't be empty");
2644
2645 assert(MethodVFTableLocations.empty());
2646 for (const auto &I : MethodInfoMap) {
2648 const MethodInfo &MI = I.second;
2650
2651
2652
2653 if (MD->getParent() != MostDerivedClass || MI.Shadowed)
2654 continue;
2657 if (const CXXDestructorDecl *DD = dyn_cast(MD)) {
2659 } else {
2660 MethodVFTableLocations[MD] = Loc;
2661 }
2662 }
2663 }
2664
2665public:
2668 : VTables(VTables),
2669 Context(MostDerivedClass->getASTContext()),
2670 MostDerivedClass(MostDerivedClass),
2671 MostDerivedClassLayout(Context.getASTRecordLayout(MostDerivedClass)),
2672 WhichVFPtr(Which),
2673 Overriders(MostDerivedClass, CharUnits(), MostDerivedClass) {
2674
2675
2676
2677
2678
2680 HasRTTIComponent = true;
2681
2682 LayoutVFTable();
2683
2684 if (Context.getLangOpts().DumpVTableLayouts)
2685 dumpLayout(llvm::outs());
2686 }
2687
2688 uint64_t getNumThunks() const { return Thunks.size(); }
2689
2690 ThunksMapTy::const_iterator thunks_begin() const { return Thunks.begin(); }
2691
2692 ThunksMapTy::const_iterator thunks_end() const { return Thunks.end(); }
2693
2694 method_locations_range vtable_locations() const {
2695 return method_locations_range(MethodVFTableLocations.begin(),
2696 MethodVFTableLocations.end());
2697 }
2698
2700
2701 VTableThunksMapTy::const_iterator vtable_thunks_begin() const {
2702 return VTableThunks.begin();
2703 }
2704
2705 VTableThunksMapTy::const_iterator vtable_thunks_end() const {
2706 return VTableThunks.end();
2707 }
2708
2709 void dumpLayout(raw_ostream &);
2710};
2711
2712}
2713
2714
2715
2716
2717
2718
2719
2720
2721
2722
2723
2724
2725
2726
2727
2728
2729
2730
2731
2732
2733
2734
2735
2736
2737
2738
2739
2740
2741
2742
2743
2744
2745
2746
2747
2748
2749
2750
2751
2752
2753
2754
2755
2756
2757
2758
2759
2760
2761
2762
2763
2764
2765
2766
2767
2769VFTableBuilder::ComputeThisOffset(FinalOverriders::OverriderInfo Overrider) {
2770 BasesSetVectorTy Bases;
2771
2772 {
2773
2774 OverriddenMethodsSetTy VisitedOverriddenMethods;
2775 auto InitialOverriddenDefinitionCollector = [&](
2777 if (OverriddenMD->size_overridden_methods() == 0)
2778 Bases.insert(OverriddenMD->getParent());
2779
2780 return VisitedOverriddenMethods.insert(OverriddenMD).second;
2781 };
2782 visitAllOverriddenMethods(Overrider.Method,
2783 InitialOverriddenDefinitionCollector);
2784 }
2785
2786
2787
2788 if (Bases.size() == 0)
2789 return Overrider.Offset;
2790
2792 Overrider.Method->getParent()->lookupInBases(
2794 return Bases.count(Specifier->getType()->getAsCXXRecordDecl());
2795 },
2796 Paths);
2797
2798
2799
2800
2801
2803 bool First = true;
2804
2808 CharUnits ThisOffset = Overrider.Offset;
2810
2811
2812
2813
2815 QualType CurTy = Element.Base->getType();
2819
2820 if (Element.Base->isVirtual()) {
2821
2822
2823
2824
2825
2826
2827
2828
2829
2830
2831 LastVBaseOffset = ThisOffset =
2833 } else {
2835 }
2836 }
2837
2838 if (isa(Overrider.Method)) {
2839 if (LastVBaseOffset.isZero()) {
2840
2841
2842
2843 ThisOffset = Overrider.Offset;
2844 } else {
2845
2846
2847 ThisOffset = LastVBaseOffset;
2848 }
2849 }
2850
2851 if (Ret > ThisOffset || First) {
2853 Ret = ThisOffset;
2854 }
2855 }
2856
2857 assert( && "Method not found in the given subobject?");
2858 return Ret;
2859}
2860
2861
2862
2863
2864
2865
2866
2867
2868
2869
2870
2871
2872
2873
2874
2875
2876
2877
2878
2879
2880
2881
2882
2883
2884
2885
2886
2887
2888
2889
2890
2891
2892
2893
2894
2895
2896
2897
2898
2899
2900
2901
2902
2903
2904
2905
2906
2907
2908
2909
2910
2911
2912
2913
2914
2915
2916
2917
2918
2919
2920
2921
2922
2923
2924
2925
2926
2927
2928
2929
2930
2931
2932
2933
2934
2935
2936
2937
2938
2939
2940
2941
2942
2943
2944
2945
2946
2947
2948
2949
2950
2951
2952
2953
2954
2955
2956
2957
2958
2959void VFTableBuilder::CalculateVtordispAdjustment(
2960 FinalOverriders::OverriderInfo Overrider, CharUnits ThisOffset,
2964 const ASTRecordLayout::VBaseOffsetsMapTy::const_iterator &VBaseMapEntry =
2966 assert(VBaseMapEntry != VBaseMap.end());
2967
2968
2969
2970 if (!VBaseMapEntry->second.hasVtorDisp() ||
2972 return;
2973
2974
2975
2976 CharUnits OffsetOfVBaseWithVFPtr = VBaseMapEntry->second.VBaseOffset;
2978 (OffsetOfVBaseWithVFPtr - WhichVFPtr.FullOffsetInMDC).getQuantity() - 4;
2979
2980
2981
2982 if (Overrider.Method->getParent() == MostDerivedClass ||
2983 !Overrider.VirtualBase)
2984 return;
2985
2986
2987
2990 MostDerivedClassLayout.getVBPtrOffset()).getQuantity();
2993 VTables.getVBTableIndex(MostDerivedClass, Overrider.VirtualBase);
2994
2995 TA.NonVirtual = (ThisOffset - Overrider.Offset).getQuantity();
2996}
2997
3001
3002
3003
3004
3005
3006
3009 typedef llvm::DenseMap<DeclarationName, unsigned> VisitedGroupIndicesTy;
3010 VisitedGroupIndicesTy VisitedGroupIndices;
3011 for (const auto *D : RD->decls()) {
3012 const auto *ND = dyn_cast(D);
3013 if (!ND)
3014 continue;
3015 VisitedGroupIndicesTy::iterator J;
3016 bool Inserted;
3017 std::tie(J, Inserted) = VisitedGroupIndices.insert(
3018 std::make_pair(ND->getDeclName(), Groups.size()));
3019 if (Inserted)
3020 Groups.push_back(MethodGroup());
3021 if (const auto *MD = dyn_cast(ND))
3024 }
3025
3026 for (const MethodGroup &Group : Groups)
3027 VirtualMethods.append(Group.rbegin(), Group.rend());
3028}
3029
3031 for (const auto &B : RD->bases()) {
3032 if (B.isVirtual() && B.getType()->getAsCXXRecordDecl() == Base)
3033 return true;
3034 }
3035 return false;
3036}
3037
3038void VFTableBuilder::AddMethods(BaseSubobject Base, unsigned BaseDepth,
3040 BasesSetVectorTy &VisitedBases) {
3043 return;
3044
3046
3047
3048
3049
3050 const CXXRecordDecl *NextBase = nullptr, *NextLastVBase = LastVBase;
3055 NextLastVBase = NextBase;
3057 } else {
3058 NextBaseOffset =
3060 }
3063 "No primary virtual bases in this ABI");
3064 NextBase = PrimaryBase;
3065 NextBaseOffset = Base.getBaseOffset();
3066 }
3067
3068 if (NextBase) {
3069 AddMethods(BaseSubobject(NextBase, NextBaseOffset), BaseDepth + 1,
3070 NextLastVBase, VisitedBases);
3071 if (!VisitedBases.insert(NextBase))
3072 llvm_unreachable("Found a duplicate primary base!");
3073 }
3074
3076
3078
3079
3080
3081
3082
3083
3084
3085
3086
3087 for (const CXXMethodDecl *MD : VirtualMethods) {
3088 FinalOverriders::OverriderInfo FinalOverrider =
3089 Overriders.getOverrider(MD, Base.getBaseOffset());
3090 const CXXMethodDecl *FinalOverriderMD = FinalOverrider.Method;
3092 FindNearestOverriddenMethod(MD, VisitedBases);
3093
3095 bool ReturnAdjustingThunk = false, ForceReturnAdjustmentMangling = false;
3096 CharUnits ThisOffset = ComputeThisOffset(FinalOverrider);
3098 (ThisOffset - WhichVFPtr.FullOffsetInMDC).getQuantity();
3099 if ((OverriddenMD || FinalOverriderMD != MD) &&
3101 CalculateVtordispAdjustment(FinalOverrider, ThisOffset,
3102 ThisAdjustmentOffset);
3103
3104 unsigned VBIndex =
3105 LastVBase ? VTables.getVBTableIndex(MostDerivedClass, LastVBase) : 0;
3106
3107 if (OverriddenMD) {
3108
3109
3110 MethodInfoMapTy::iterator OverriddenMDIterator =
3111 MethodInfoMap.find(OverriddenMD);
3112
3113
3114 if (OverriddenMDIterator == MethodInfoMap.end())
3115 continue;
3116
3117 MethodInfo &OverriddenMethodInfo = OverriddenMDIterator->second;
3118
3119 VBIndex = OverriddenMethodInfo.VBTableIndex;
3120
3121
3122
3123
3124
3125
3126 ReturnAdjustingThunk = !ComputeReturnAdjustmentBaseOffset(
3127 Context, MD, OverriddenMD).isEmpty() ||
3128 OverriddenMethodInfo.UsesExtraSlot;
3129
3130 if (!ReturnAdjustingThunk) {
3131
3132
3133 MethodInfo MI(VBIndex, OverriddenMethodInfo.VFTableIndex);
3134 MethodInfoMap.erase(OverriddenMDIterator);
3135
3136 assert(!MethodInfoMap.count(MD) &&
3137 "Should not have method info for this method yet!");
3138 MethodInfoMap.insert(std::make_pair(MD, MI));
3139 continue;
3140 }
3141
3142
3143
3144 OverriddenMethodInfo.Shadowed = true;
3145
3146
3147
3148 ForceReturnAdjustmentMangling =
3149 !(MD == FinalOverriderMD && ThisAdjustmentOffset.isEmpty());
3152
3153
3154
3155 continue;
3156 }
3157
3158
3159
3160 MethodInfo MI(VBIndex,
3161 HasRTTIComponent ? Components.size() - 1 : Components.size(),
3162 ReturnAdjustingThunk);
3163
3164 assert(!MethodInfoMap.count(MD) &&
3165 "Should not have method info for this method yet!");
3166 MethodInfoMap.insert(std::make_pair(MD, MI));
3167
3168
3169
3170 BaseOffset ReturnAdjustmentOffset;
3173 ReturnAdjustmentOffset =
3174 ComputeReturnAdjustmentBaseOffset(Context, FinalOverriderMD, MD);
3175 }
3176 if (!ReturnAdjustmentOffset.isEmpty()) {
3177 ForceReturnAdjustmentMangling = true;
3179 ReturnAdjustmentOffset.NonVirtualOffset.getQuantity();
3180 if (ReturnAdjustmentOffset.VirtualBase) {
3186 VTables.getVBTableIndex(ReturnAdjustmentOffset.DerivedClass,
3187 ReturnAdjustmentOffset.VirtualBase);
3188 }
3189 }
3190 auto ThisType = (OverriddenMD ? OverriddenMD : MD)->getThisType().getTypePtr();
3191 AddMethod(FinalOverriderMD,
3193 ForceReturnAdjustmentMangling ? MD : nullptr));
3194 }
3195}
3196
3199 Out << "'";
3200 Elem->printQualifiedName(Out);
3201 Out << "' in ";
3202 }
3203}
3204
3206 bool ContinueFirstLine) {
3208 bool Multiline = false;
3209 const char *LinePrefix = "\n ";
3211 if (!ContinueFirstLine)
3212 Out << LinePrefix;
3213 Out << "[return adjustment (to type '"
3219 Out << R.NonVirtual << " non-virtual]";
3220 Multiline = true;
3221 }
3222
3224 if (.isEmpty()) {
3225 if (Multiline || !ContinueFirstLine)
3226 Out << LinePrefix;
3227 Out << "[this adjustment: ";
3229 assert(T.Virtual.Microsoft.VtordispOffset < 0);
3230 Out << "vtordisp at " << T.Virtual.Microsoft.VtordispOffset << ", ";
3231 if (T.Virtual.Microsoft.VBPtrOffset) {
3232 Out << "vbptr at " << T.Virtual.Microsoft.VBPtrOffset
3233 << " to the left,";
3234 assert(T.Virtual.Microsoft.VBOffsetOffset > 0);
3235 Out << LinePrefix << " vboffset at "
3236 << T.Virtual.Microsoft.VBOffsetOffset << " in the vbtable, ";
3237 }
3238 }
3239 Out << T.NonVirtual << " non-virtual]";
3240 }
3241}
3242
3243void VFTableBuilder::dumpLayout(raw_ostream &Out) {
3244 Out << "VFTable for ";
3246 Out << "'";
3248 Out << "' (" << Components.size()
3249 << (Components.size() == 1 ? " entry" : " entries") << ").\n";
3250
3251 for (unsigned I = 0, E = Components.size(); I != E; ++I) {
3252 Out << llvm::format("%4d | ", I);
3253
3255
3256
3257 switch (Component.getKind()) {
3260 Out << " RTTI";
3261 break;
3262
3265
3266
3267
3270 Out << Str;
3272 Out << " [pure]";
3273
3275 Out << " [deleted]";
3276
3277 ThunkInfo Thunk = VTableThunks.lookup(I);
3280
3281 break;
3282 }
3283
3286
3288 Out << "() [scalar deleting]";
3289
3291 Out << " [pure]";
3292
3293 ThunkInfo Thunk = VTableThunks.lookup(I);
3296 "No return adjustment needed for destructors!");
3298 }
3299
3300 break;
3301 }
3302
3303 default:
3307 "Unexpected vftable component type %0 for component number %1");
3309 << I << Component.getKind();
3310 }
3311
3312 Out << '\n';
3313 }
3314
3315 Out << '\n';
3316
3317 if (!Thunks.empty()) {
3318
3319 std::map<std::string, const CXXMethodDecl *> MethodNamesAndDecls;
3320
3321 for (const auto &I : Thunks) {
3325
3326 MethodNamesAndDecls.insert(std::make_pair(MethodName, MD));
3327 }
3328
3329 for (const auto &MethodNameAndDecl : MethodNamesAndDecls) {
3330 const std::string &MethodName = MethodNameAndDecl.first;
3331 const CXXMethodDecl *MD = MethodNameAndDecl.second;
3332
3333 ThunkInfoVectorTy ThunksVector = Thunks[MD];
3334 llvm::stable_sort(ThunksVector, [](const ThunkInfo &LHS,
3336
3337
3339 });
3340
3341 Out << "Thunks for '" << MethodName << "' (" << ThunksVector.size();
3342 Out << (ThunksVector.size() == 1 ? " entry" : " entries") << ").\n";
3343
3344 for (unsigned I = 0, E = ThunksVector.size(); I != E; ++I) {
3345 const ThunkInfo &Thunk = ThunksVector[I];
3346
3347 Out << llvm::format("%4d | ", I);
3349 Out << '\n';
3350 }
3351
3352 Out << '\n';
3353 }
3354 }
3355
3356 Out.flush();
3357}
3358
3362 if (A.count(Decl))
3363 return true;
3364 }
3365 return false;
3366}
3367
3369
3370
3371
3372
3373
3374
3375
3376
3377
3378
3379
3380
3381
3382
3383
3384
3385
3386
3387
3388
3389
3390
3391void MicrosoftVTableContext::computeVTablePaths(bool ForVBTables,
3394 assert(Paths.empty());
3396
3397
3399 Paths.push_back(std::make_unique(RD));
3400
3401
3402
3404 for (const auto &B : RD->bases()) {
3406 if (B.isVirtual() && VBasesSeen.count(Base))
3407 continue;
3408
3409 if (->isDynamicClass())
3410 continue;
3411
3414
3415 for (const std::unique_ptr &BaseInfo : BasePaths) {
3416
3417
3418 if (setsIntersect(VBasesSeen, BaseInfo->ContainingVBases))
3419 continue;
3420
3421
3422 auto P = std::make_unique(*BaseInfo);
3423
3424
3425
3426 if (P->MangledPath.empty() || P->MangledPath.back() != Base)
3427 P->NextBaseToMangle = Base;
3428
3429
3430
3431
3432 if (P->ObjectWithVPtr == Base &&
3435 P->ObjectWithVPtr = RD;
3436
3437
3438
3439 if (B.isVirtual())
3440 P->ContainingVBases.push_back(Base);
3441 else if (P->ContainingVBases.empty())
3443
3444
3445 P->FullOffsetInMDC = P->NonVirtualOffset;
3446 if (const CXXRecordDecl *VB = P->getVBaseWithVPtr())
3448
3449 Paths.push_back(std::move(P));
3450 }
3451
3452 if (B.isVirtual())
3453 VBasesSeen.insert(Base);
3454
3455
3456
3457 for (const auto &VB : Base->vbases())
3458 VBasesSeen.insert(VB.getType()->getAsCXXRecordDecl());
3459 }
3460
3461
3462
3464 while (Changed)
3466}
3467
3469 if (P.NextBaseToMangle) {
3470 P.MangledPath.push_back(P.NextBaseToMangle);
3471 P.NextBaseToMangle = nullptr;
3472 return true;
3473 }
3474 return false;
3475}
3476
3478
3479
3480
3481
3482
3483
3485 llvm::make_pointee_range(Paths));
3486 llvm::sort(PathsSorted, [](const VPtrInfo &LHS, const VPtrInfo &RHS) {
3488 });
3489 bool Changed = false;
3490 for (size_t I = 0, E = PathsSorted.size(); I != E;) {
3491
3492 size_t BucketStart = I;
3493 do {
3494 ++I;
3495 } while (I != E &&
3496 PathsSorted[BucketStart].get().MangledPath ==
3497 PathsSorted[I].get().MangledPath);
3498
3499
3500 if (I - BucketStart > 1) {
3501 for (size_t II = BucketStart; II != I; ++II)
3502 Changed |= extendPath(PathsSorted[II]);
3503 assert(Changed && "no paths were extended to fix ambiguity");
3504 }
3505 }
3506 return Changed;
3507}
3508
3510
3511namespace {
3512typedef llvm::SetVector<BaseSubobject, std::vector,
3513 llvm::DenseSet> FullPathTy;
3514}
3515
3516
3517
3522 FullPathTy &FullPath,
3523 std::list &Paths) {
3524 if (BaseSubobject(RD, Offset) == IntroducingObject) {
3525 Paths.push_back(FullPath);
3526 return;
3527 }
3528
3530
3533 CharUnits NewOffset = BS.isVirtual()
3538 IntroducingObject, FullPath, Paths);
3539 FullPath.pop_back();
3540 }
3541}
3542
3543
3545 FullPaths.remove_if([&](const FullPathTy &SpecificPath) {
3546 for (const FullPathTy &OtherPath : FullPaths) {
3547 if (&SpecificPath == &OtherPath)
3548 continue;
3549 if (llvm::all_of(SpecificPath, [&](const BaseSubobject &BSO) {
3550 return OtherPath.contains(BSO);
3551 })) {
3552 return true;
3553 }
3554 }
3555 return false;
3556 });
3557}
3558
3561 const FullPathTy &FullPath) {
3567
3568 if (Base == RD) {
3569 assert(Offset.getQuantity() == -1);
3571 continue;
3572 }
3573 assert(Offset.getQuantity() != -1);
3575
3576
3579 return BS.getType()->getAsCXXRecordDecl() == Base;
3580 });
3584 }
3585 return Offset;
3586}
3587
3588
3589
3590
3594 std::list &FullPaths) {
3595
3596 if (FullPaths.empty())
3597 return nullptr;
3598 if (FullPaths.size() == 1)
3599 return &FullPaths.front();
3600
3601 const FullPathTy *BestPath = nullptr;
3602 typedef std::set<const CXXMethodDecl *> OverriderSetTy;
3603 OverriderSetTy LastOverrides;
3604 for (const FullPathTy &SpecificPath : FullPaths) {
3605 assert(!SpecificPath.empty());
3606 OverriderSetTy CurrentOverrides;
3607 const CXXRecordDecl *TopLevelRD = SpecificPath.begin()->getBase();
3608
3609
3612 FinalOverriders Overriders(TopLevelRD, CharUnits::Zero(), TopLevelRD);
3615 continue;
3616 FinalOverriders::OverriderInfo OI =
3617 Overriders.getOverrider(MD->getCanonicalDecl(), BaseOffset);
3618 const CXXMethodDecl *OverridingMethod = OI.Method;
3619
3620
3621 if (ComputeReturnAdjustmentBaseOffset(Context, OverridingMethod, MD)
3622 .isEmpty())
3623 continue;
3624
3625
3627 if (llvm::none_of(SpecificPath, [&](const BaseSubobject &BSO) {
3628 return BSO.getBase() == OverridingParent;
3629 }))
3630 continue;
3631 CurrentOverrides.insert(OverridingMethod);
3632 }
3633 OverriderSetTy NewOverrides =
3634 llvm::set_difference(CurrentOverrides, LastOverrides);
3635 if (NewOverrides.empty())
3636 continue;
3637 OverriderSetTy MissingOverrides =
3638 llvm::set_difference(LastOverrides, CurrentOverrides);
3639 if (MissingOverrides.empty()) {
3640
3641 BestPath = &SpecificPath;
3642 std::swap(CurrentOverrides, LastOverrides);
3643 } else {
3644
3646 const CXXMethodDecl *CovariantMD = *NewOverrides.begin();
3647 const CXXMethodDecl *ConflictMD = *MissingOverrides.begin();
3648 Diags.Report(RD->getLocation(), diag::err_vftable_ambiguous_component)
3649 << RD;
3650 Diags.Report(CovariantMD->getLocation(), diag::note_covariant_thunk)
3651 << CovariantMD;
3652 Diags.Report(ConflictMD->getLocation(), diag::note_covariant_thunk)
3653 << ConflictMD;
3654 }
3655 }
3656
3657
3658 return BestPath ? BestPath : &FullPaths.front();
3659}
3660
3665 FullPathTy FullPath;
3666 std::list FullPaths;
3667 for (const std::unique_ptr& Info : Paths) {
3670 BaseSubobject(Info->IntroducingObject, Info->FullOffsetInMDC), FullPath,
3671 FullPaths);
3672 FullPath.clear();
3674 Info->PathToIntroducingObject.clear();
3675 if (const FullPathTy *BestPath =
3678 Info->PathToIntroducingObject.push_back(BSO.getBase());
3679 FullPaths.clear();
3680 }
3681}
3682
3692 return L < R;
3693}
3694
3695void MicrosoftVTableContext::computeVTableRelatedInformation(
3698
3699
3700 if (VFPtrLocations.count(RD))
3701 return;
3702
3704
3705 {
3706 auto VFPtrs = std::make_unique();
3707 computeVTablePaths(false, RD, *VFPtrs);
3709 VFPtrLocations[RD] = std::move(VFPtrs);
3710 }
3711
3712 MethodVFTableLocationsTy NewMethodLocations;
3713 for (const std::unique_ptr &VFPtr : *VFPtrLocations[RD]) {
3714 VFTableBuilder Builder(*this, RD, *VFPtr);
3715
3716 VFTableIdTy id(RD, VFPtr->FullOffsetInMDC);
3717 assert(VFTableLayouts.count(id) == 0);
3719 Builder.vtable_thunks_begin(), Builder.vtable_thunks_end());
3720 VFTableLayouts[id] = std::make_unique(
3721 ArrayRef<size_t>{0}, Builder.vtable_components(), VTableThunks,
3722 EmptyAddressPointsMap);
3723 Thunks.insert(Builder.thunks_begin(), Builder.thunks_end());
3724
3726 for (const auto &Loc : Builder.vtable_locations()) {
3727 auto Insert = NewMethodLocations.insert(Loc);
3728 if (.second) {
3732 OldLoc = NewLoc;
3733 }
3734 }
3735 }
3736
3737 MethodVFTableLocations.insert(NewMethodLocations.begin(),
3738 NewMethodLocations.end());
3739 if (Context.getLangOpts().DumpVTableLayouts)
3740 dumpMethodLocations(RD, NewMethodLocations, llvm::outs());
3741}
3742
3743void MicrosoftVTableContext::dumpMethodLocations(
3744 const CXXRecordDecl *RD, const MethodVFTableLocationsTy &NewMethods,
3745 raw_ostream &Out) {
3746
3747
3748 std::map<MethodVFTableLocation, std::string> IndicesMap;
3749 bool HasNonzeroOffset = false;
3750
3751 for (const auto &I : NewMethods) {
3752 const CXXMethodDecl *MD = cast(I.first.getDecl());
3754
3757
3758 if (isa(MD)) {
3759 IndicesMap[I.second] = MethodName + " [scalar deleting]";
3760 } else {
3761 IndicesMap[I.second] = MethodName;
3762 }
3763
3764 if (!I.second.VFPtrOffset.isZero() || I.second.VBTableIndex != 0)
3765 HasNonzeroOffset = true;
3766 }
3767
3768
3769 if (!IndicesMap.empty()) {
3770 Out << "VFTable indices for ";
3771 Out << "'";
3773 Out << "' (" << IndicesMap.size()
3774 << (IndicesMap.size() == 1 ? " entry" : " entries") << ").\n";
3775
3778 for (const auto &I : IndicesMap) {
3779 CharUnits VFPtrOffset = I.first.VFPtrOffset;
3780 uint64_t VBIndex = I.first.VBTableIndex;
3781 if (HasNonzeroOffset &&
3782 (VFPtrOffset != LastVFPtrOffset || VBIndex != LastVBIndex)) {
3783 assert(VBIndex > LastVBIndex || VFPtrOffset > LastVFPtrOffset);
3784 Out << " -- accessible via ";
3785 if (VBIndex)
3786 Out << "vbtable index " << VBIndex << ", ";
3787 Out << "vfptr at offset " << VFPtrOffset.getQuantity() << " --\n";
3788 LastVFPtrOffset = VFPtrOffset;
3789 LastVBIndex = VBIndex;
3790 }
3791
3792 uint64_t VTableIndex = I.first.Index;
3793 const std::string &MethodName = I.second;
3794 Out << llvm::format("%4" PRIu64 " | ", VTableIndex) << MethodName << '\n';
3795 }
3796 Out << '\n';
3797 }
3798
3799 Out.flush();
3800}
3801
3802const VirtualBaseInfo &MicrosoftVTableContext::computeVBTableRelatedInformation(
3805
3806 {
3807
3808
3809 std::unique_ptr &Entry = VBaseInfo[RD];
3810 if (Entry)
3811 return *Entry;
3812 Entry = std::make_unique();
3813 VBI = Entry.get();
3814 }
3815
3816 computeVTablePaths(true, RD, VBI->VBPtrPaths);
3817
3818
3821
3822
3824 computeVBTableRelatedInformation(VBPtrBase);
3827 }
3828
3829
3830
3831 unsigned VBTableIndex = 1 + VBI->VBTableIndices.size();
3832 for (const auto &VB : RD->vbases()) {
3833 const CXXRecordDecl *CurVBase = VB.getType()->getAsCXXRecordDecl();
3834 if (VBI->VBTableIndices.try_emplace(CurVBase, VBTableIndex).second)
3835 ++VBTableIndex;
3836 }
3837
3838 return *VBI;
3839}
3840
3843 const VirtualBaseInfo &VBInfo = computeVBTableRelatedInformation(Derived);
3846}
3847
3850 return computeVBTableRelatedInformation(RD).VBPtrPaths;
3851}
3852
3855 computeVTableRelatedInformation(RD);
3856
3857 assert(VFPtrLocations.count(RD) && "Couldn't find vfptr locations");
3858 return *VFPtrLocations[RD];
3859}
3860
3864 computeVTableRelatedInformation(RD);
3865
3866 VFTableIdTy id(RD, VFPtrOffset);
3867 assert(VFTableLayouts.count(id) && "Couldn't find a VFTable at this offset");
3868 return *VFTableLayouts[id];
3869}
3870
3874 "Only use this method for virtual methods or dtors");
3875 if (isa(GD.getDecl()))
3877
3879
3880 MethodVFTableLocationsTy::iterator I = MethodVFTableLocations.find(GD);
3881 if (I != MethodVFTableLocations.end())
3882 return I->second;
3883
3885
3886 computeVTableRelatedInformation(RD);
3887
3888 I = MethodVFTableLocations.find(GD);
3889 assert(I != MethodVFTableLocations.end() && "Did not find index!");
3890 return I->second;
3891}
Defines the clang::ASTContext interface.
ASTImporterLookupTable & LT
static void dump(llvm::raw_ostream &OS, StringRef FunctionName, ArrayRef< CounterExpression > Expressions, ArrayRef< CounterMappingRegion > Regions)
static Decl::Kind getKind(const Decl *D)
static QualType getPointeeType(const MemRegion *R)
const NestedNameSpecifier * Specifier
static void findPathsToSubobject(ASTContext &Context, const ASTRecordLayout &MostDerivedLayout, const CXXRecordDecl *RD, CharUnits Offset, BaseSubobject IntroducingObject, FullPathTy &FullPath, std::list< FullPathTy > &Paths)
static const FullPathTy * selectBestPath(ASTContext &Context, const CXXRecordDecl *RD, const VPtrInfo &Info, std::list< FullPathTy > &FullPaths)
static CharUnits getOffsetOfFullPath(ASTContext &Context, const CXXRecordDecl *RD, const FullPathTy &FullPath)
static void removeRedundantPaths(std::list< FullPathTy > &FullPaths)
static std::unique_ptr< VTableLayout > CreateVTableLayout(const ItaniumVTableBuilder &Builder)
static bool vfptrIsEarlierInMDC(const ASTRecordLayout &Layout, const MethodVFTableLocation &LHS, const MethodVFTableLocation &RHS)
static bool isDirectVBase(const CXXRecordDecl *Base, const CXXRecordDecl *RD)
static void PrintBasePath(const VPtrInfo::BasePath &Path, raw_ostream &Out)
static VTableLayout::AddressPointsIndexMapTy MakeAddressPointIndices(const VTableLayout::AddressPointsMapTy &addressPoints, unsigned numVTables)
static bool rebucketPaths(VPtrInfoVector &Paths)
static bool extendPath(VPtrInfo &P)
static void dumpMicrosoftThunkAdjustment(const ThunkInfo &TI, raw_ostream &Out, bool ContinueFirstLine)
static void GroupNewVirtualOverloads(const CXXRecordDecl *RD, SmallVector< const CXXMethodDecl *, 10 > &VirtualMethods)
static void computeFullPathsForVFTables(ASTContext &Context, const CXXRecordDecl *RD, VPtrInfoVector &Paths)
static bool setsIntersect(const llvm::SmallPtrSet< const CXXRecordDecl *, 4 > &A, ArrayRef< const CXXRecordDecl * > B)
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
const ASTRecordLayout & getASTRecordLayout(const RecordDecl *D) const
Get or compute information about the layout of the specified record (struct/union/class) D,...
CanQualType getCanonicalType(QualType T) const
Return the canonical (structural) type corresponding to the specified potentially non-canonical type ...
const LangOptions & getLangOpts() const
CharUnits getTypeSizeInChars(QualType T) const
Return the size of the specified (complete) type T, in characters.
DiagnosticsEngine & getDiagnostics() const
const TargetInfo & getTargetInfo() const
CharUnits toCharUnitsFromBits(int64_t BitSize) const
Convert a size in bits to a size in characters.
ASTRecordLayout - This class contains layout information for one RecordDecl, which is a struct/union/...
bool hasOwnVFPtr() const
hasOwnVFPtr - Does this class provide its own virtual-function table pointer, rather than inheriting ...
const CXXRecordDecl * getBaseSharingVBPtr() const
bool hasOwnVBPtr() const
hasOwnVBPtr - Does this class provide its own virtual-base table pointer, rather than inheriting one ...
llvm::DenseMap< const CXXRecordDecl *, VBaseInfo > VBaseOffsetsMapTy
CharUnits getVBPtrOffset() const
getVBPtrOffset - Get the offset for virtual base table pointer.
CharUnits getBaseClassOffset(const CXXRecordDecl *Base) const
getBaseClassOffset - Get the offset, in chars, for the given base class.
CharUnits getVBaseClassOffset(const CXXRecordDecl *VBase) const
getVBaseClassOffset - Get the offset, in chars, for the given base class.
const VBaseOffsetsMapTy & getVBaseOffsetsMap() const
const CXXRecordDecl * getPrimaryBase() const
getPrimaryBase - Get the primary base for this record.
bool isPrimaryBaseVirtual() const
isPrimaryBaseVirtual - Get whether the primary base for this record is virtual or not.
const CXXRecordDecl * getBase() const
getBase - Returns the base class declaration.
CharUnits getBaseOffset() const
getBaseOffset - Returns the base class offset.
Represents a path from a specific derived class (which is not represented as part of the path) to a p...
BasePaths - Represents the set of paths from a derived class to one of its (direct or indirect) bases...
Represents a base class of a C++ class.
bool isVirtual() const
Determines whether the base class is a virtual base class (or not).
QualType getType() const
Retrieves the type of the base class.
Represents a C++ destructor within a class.
A mapping from each virtual member function to its set of final overriders.
Represents a static or instance method of a struct/union/class.
overridden_method_range overridden_methods() const
unsigned size_overridden_methods() const
const CXXRecordDecl * getParent() const
Return the parent of this method declaration, which is the class in which this method is defined.
QualType getThisType() const
Return the type of the this pointer.
CXXMethodDecl * getCanonicalDecl() override
Retrieves the "canonical" declaration of the given declaration.
Represents a C++ struct/union/class.
base_class_iterator bases_end()
method_range methods() const
bool isPolymorphic() const
Whether this class is polymorphic (C++ [class.virtual]), which means that the class contains or inher...
base_class_iterator bases_begin()
base_class_range vbases()
base_class_iterator vbases_begin()
bool isDynamicClass() const
void getFinalOverriders(CXXFinalOverriderMap &FinaOverriders) const
Retrieve the final overriders for each virtual member function in the class hierarchy where this clas...
unsigned getNumVBases() const
Retrieves the number of virtual base classes of this class.
bool isDerivedFrom(const CXXRecordDecl *Base) const
Determine whether this class is derived from the class Base.
CanQual< T > getUnqualifiedType() const
Retrieve the unqualified form of this type.
CanProxy< U > getAs() const
Retrieve a canonical type pointer with a different static type, upcasting or downcasting as needed.
CharUnits - This is an opaque type for sizes expressed in character units.
bool isZero() const
isZero - Test whether the quantity equals zero.
QuantityType getQuantity() const
getQuantity - Get the raw integer representation of this quantity.
static CharUnits fromQuantity(QuantityType Quantity)
fromQuantity - Construct a CharUnits quantity from a raw integer type.
static CharUnits Zero()
Zero - Construct a CharUnits quantity of zero.
DeclContext * getParent()
getParent - Returns the containing DeclContext.
decl_range decls() const
decls_begin/decls_end - Iterate over the declarations stored in this context.
Decl - This represents one declaration (or definition), e.g.
ASTContext & getASTContext() const LLVM_READONLY
bool isImplicit() const
isImplicit - Indicates whether the declaration was implicitly generated by the implementation.
SourceLocation getLocation() const
The name of a declaration.
Concrete class used by the front-end to report problems and issues.
DiagnosticBuilder Report(SourceLocation Loc, unsigned DiagID)
Issue the message to the client.
unsigned getCustomDiagID(Level L, const char(&FormatString)[N])
Return an ID for a diagnostic with the specified format string and level.
bool isImmediateFunction() const
QualType getReturnType() const
bool isDeleted() const
Whether this function has been deleted.
bool isPureVirtual() const
Whether this virtual function is pure, i.e.
Represents a prototype with parameter type info, e.g.
Qualifiers getMethodQuals() const
ArrayRef< QualType > getParamTypes() const
FunctionType - C99 6.7.5.3 - Function Declarators.
QualType getReturnType() const
GlobalDecl - represents a global declaration.
GlobalDecl getCanonicalDecl() const
CXXDtorType getDtorType() const
const Decl * getDecl() const
const CXXMethodDecl * findOriginalMethodInMap(const CXXMethodDecl *MD) const
uint64_t getMethodVTableIndex(GlobalDecl GD)
Locate a virtual function in the vtable.
std::unique_ptr< VTableLayout > createConstructionVTableLayout(const CXXRecordDecl *MostDerivedClass, CharUnits MostDerivedClassOffset, bool MostDerivedClassIsVirtual, const CXXRecordDecl *LayoutClass)
~ItaniumVTableContext() override
CharUnits getVirtualBaseOffsetOffset(const CXXRecordDecl *RD, const CXXRecordDecl *VBase)
Return the offset in chars (relative to the vtable address point) where the offset of the virtual bas...
ItaniumVTableContext(ASTContext &Context, VTableComponentLayout ComponentLayout=Pointer)
GlobalDecl findOriginalMethod(GlobalDecl GD)
Return the method that added the v-table slot that will be used to call the given method.
unsigned getVBTableIndex(const CXXRecordDecl *Derived, const CXXRecordDecl *VBase)
Returns the index of VBase in the vbtable of Derived.
const VPtrInfoVector & enumerateVBTables(const CXXRecordDecl *RD)
MethodVFTableLocation getMethodVFTableLocation(GlobalDecl GD)
const VPtrInfoVector & getVFPtrOffsets(const CXXRecordDecl *RD)
const VTableLayout & getVFTableLayout(const CXXRecordDecl *RD, CharUnits VFPtrOffset)
~MicrosoftVTableContext() override
DeclarationName getDeclName() const
Get the actual, stored name of the declaration, which may be a special name.
std::string getQualifiedNameAsString() const
void printQualifiedName(raw_ostream &OS) const
Returns a human-readable qualified name for this declaration, like A::B::i, for i being member of nam...
The set of methods that override a given virtual method in each subobject where it occurs.
PointerType - C99 6.7.5.1 - Pointer Declarators.
static std::string ComputeName(PredefinedIdentKind IK, const Decl *CurrentDecl, bool ForceElaboratedPrinting=false)
A (possibly-)qualified type.
const Type * getTypePtr() const
Retrieves a pointer to the underlying (unqualified) type.
QualType getCanonicalType() const
Base for LValueReferenceType and RValueReferenceType.
bool isMicrosoft() const
Is this ABI an MSVC-compatible ABI?
uint64_t getPointerWidth(LangAS AddrSpace) const
Return the width of pointers on this target, for the specified address space.
TargetCXXABI getCXXABI() const
Get the C++ ABI currently in use.
CXXRecordDecl * getAsCXXRecordDecl() const
Retrieves the CXXRecordDecl that this type refers to, either because the type is a RecordType or beca...
const T * castAs() const
Member-template castAs.
Represents a single component in a vtable.
static VTableComponent MakeCompleteDtor(const CXXDestructorDecl *DD)
static VTableComponent MakeRTTI(const CXXRecordDecl *RD)
const CXXMethodDecl * getUnusedFunctionDecl() const
static VTableComponent MakeOffsetToTop(CharUnits Offset)
CharUnits getVBaseOffset() const
static VTableComponent MakeUnusedFunction(const CXXMethodDecl *MD)
Kind getKind() const
Get the kind of this vtable component.
static VTableComponent MakeFunction(const CXXMethodDecl *MD)
@ CK_DeletingDtorPointer
A pointer to the deleting destructor.
@ CK_UnusedFunctionPointer
An entry that is never used.
@ CK_CompleteDtorPointer
A pointer to the complete destructor.
static VTableComponent MakeVBaseOffset(CharUnits Offset)
const CXXRecordDecl * getRTTIDecl() const
static VTableComponent MakeDeletingDtor(const CXXDestructorDecl *DD)
CharUnits getOffsetToTop() const
const CXXMethodDecl * getFunctionDecl() const
static VTableComponent MakeVCallOffset(CharUnits Offset)
CharUnits getVCallOffset() const
const CXXDestructorDecl * getDestructorDecl() const
static bool hasVtableSlot(const CXXMethodDecl *MD)
Determine whether this function should be assigned a vtable slot.
ThunksMapTy Thunks
Contains all thunks that a given method decl will need.
VTableLayout(ArrayRef< size_t > VTableIndices, ArrayRef< VTableComponent > VTableComponents, ArrayRef< VTableThunkTy > VTableThunks, const AddressPointsMapTy &AddressPoints)
llvm::DenseMap< BaseSubobject, AddressPointLocation > AddressPointsMapTy
std::pair< uint64_t, ThunkInfo > VTableThunkTy
Defines the clang::TargetInfo interface.
bool Ret(InterpState &S, CodePtr &PC)
The JSON file list parser is used to communicate input to InstallAPI.
@ Dtor_Complete
Complete object dtor.
@ Dtor_Deleting
Deleting dtor.
const FunctionProtoType * T
@ PrettyFunctionNoVirtual
The same as PrettyFunction, except that the 'virtual' keyword is omitted for virtual member functions...
Represents an element in a path from a derived class to a base class.
const CXXRecordDecl * VBase
If nonnull, holds the last vbase which contains the vfptr that the method definition is adjusted to.
CharUnits VFPtrOffset
This is the offset of the vfptr from the start of the last vbase, or the complete type if there are n...
union clang::ReturnAdjustment::VirtualAdjustment Virtual
int64_t NonVirtual
The non-virtual adjustment from the derived object to its nearest virtual base.
A this pointer adjustment.
union clang::ThisAdjustment::VirtualAdjustment Virtual
int64_t NonVirtual
The non-virtual adjustment from the derived object to its nearest virtual base.
The this pointer adjustment as well as an optional return adjustment for a thunk.
ThisAdjustment This
The this pointer adjustment.
const CXXMethodDecl * Method
Holds a pointer to the overridden method this thunk is for, if needed by the ABI to distinguish diffe...
ReturnAdjustment Return
The return adjustment.
Uniquely identifies a virtual method within a class hierarchy by the method itself and a class subobj...
CXXMethodDecl * Method
The overriding virtual method.
unsigned Subobject
The subobject in which the overriding virtual method resides.
const CXXRecordDecl * InVirtualSubobject
The virtual base class subobject of which this overridden virtual method is a part.
Holds information about the inheritance path to a virtual base or function table pointer.
CharUnits NonVirtualOffset
IntroducingObject is at this offset from its containing complete object or virtual base.
CharUnits FullOffsetInMDC
Static offset from the top of the most derived class to this vfptr, including any virtual base offset...
const CXXRecordDecl * getVBaseWithVPtr() const
The vptr is stored inside the non-virtual component of this virtual base.
const CXXRecordDecl * IntroducingObject
This is the class that introduced the vptr by declaring new virtual methods or virtual bases.
BasePath MangledPath
The bases from the inheritance path that got used to mangle the vbtable name.
BasePath PathToIntroducingObject
This holds the base classes path from the complete type to the first base with the given vfptr offset...
All virtual base related information about a given record decl.
VPtrInfoVector VBPtrPaths
Information on all virtual base tables used when this record is the most derived class.
llvm::DenseMap< const CXXRecordDecl *, unsigned > VBTableIndices
A map from virtual base to vbtable index for doing a conversion from the the derived class to the a b...
struct clang::ReturnAdjustment::VirtualAdjustment::@193 Microsoft
uint32_t VBPtrOffset
The offset (in bytes) of the vbptr, relative to the beginning of the derived class.
struct clang::ReturnAdjustment::VirtualAdjustment::@192 Itanium
int64_t VBaseOffsetOffset
The offset (in bytes), relative to the address point of the virtual base class offset.
uint32_t VBIndex
Index of the virtual base in the vbtable.
int32_t VtordispOffset
The offset of the vtordisp (in bytes), relative to the ECX.
int32_t VBOffsetOffset
The offset (in bytes) of the vbase offset in the vbtable.
int64_t VCallOffsetOffset
The offset (in bytes), relative to the address point, of the virtual call offset.
int32_t VBPtrOffset
The offset of the vbptr of the derived class (in bytes), relative to the ECX after vtordisp adjustmen...
struct clang::ThisAdjustment::VirtualAdjustment::@195 Microsoft
struct clang::ThisAdjustment::VirtualAdjustment::@194 Itanium