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
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,
202 Method.Subobject)];
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;
209 Overrider.VirtualBase = Method.InVirtualSubobject;
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
232 NonVirtualStart = I;
235 break;
236 }
237 }
238
239
240 for (unsigned I = NonVirtualStart, E = Path.size(); I != E; ++I) {
242
243
245
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
279 Context.getCanonicalType(DerivedFT->getReturnType());
281 Context.getCanonicalType(BaseFT->getReturnType());
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
293 CanDerivedReturnType =
295 CanBaseReturnType =
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
315 const auto *DerivedRD =
317 ->getDefinitionOrSelf();
318
319 const auto *BaseRD =
321
322 return ComputeBaseOffset(Context, BaseRD, DerivedRD);
323}
324
325void
326FinalOverriders::ComputeBaseOffsets(BaseSubobject Base, bool IsVirtual,
328 SubobjectOffsetMapTy &SubobjectOffsets,
329 SubobjectOffsetMapTy &SubobjectLayoutClassOffsets,
330 SubobjectCountMapTy &SubobjectCounts) {
332
333 unsigned SubobjectNumber = 0;
334 if (!IsVirtual)
335 SubobjectNumber = ++SubobjectCounts[RD];
336
337
338 assert(!SubobjectOffsets.count(std::make_pair(RD, SubobjectNumber))
339 && "Subobject offset already exists!");
340 assert(!SubobjectLayoutClassOffsets.count(std::make_pair(RD, SubobjectNumber))
341 && "Subobject offset already exists!");
342
343 SubobjectOffsets[std::make_pair(RD, SubobjectNumber)] = Base.getBaseOffset();
344 SubobjectLayoutClassOffsets[std::make_pair(RD, SubobjectNumber)] =
345 OffsetInLayoutClass;
346
347
348 for (const auto &B : RD->bases()) {
349 const CXXRecordDecl *BaseDecl = B.getType()->getAsCXXRecordDecl();
350
352 CharUnits BaseOffsetInLayoutClass;
353 if (B.isVirtual()) {
354
355 if (SubobjectOffsets.count(std::make_pair(BaseDecl, 0)))
356 continue;
357
359 Context.getASTRecordLayout(LayoutClass);
360
362 BaseOffsetInLayoutClass =
364 } else {
365 const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
367
368 BaseOffset = Base.getBaseOffset() + Offset;
369 BaseOffsetInLayoutClass = OffsetInLayoutClass + Offset;
370 }
371
372 ComputeBaseOffsets(BaseSubobject(BaseDecl, BaseOffset),
373 B.isVirtual(), BaseOffsetInLayoutClass,
374 SubobjectOffsets, SubobjectLayoutClassOffsets,
375 SubobjectCounts);
376 }
377}
378
380 VisitedVirtualBasesSetTy &VisitedVirtualBases) {
382 const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
383
384 for (const auto &B : RD->bases()) {
385 const CXXRecordDecl *BaseDecl = B.getType()->getAsCXXRecordDecl();
386
387
389 continue;
390
392 if (B.isVirtual()) {
393 if (!VisitedVirtualBases.insert(BaseDecl).second) {
394
395 continue;
396 }
397
399 } else {
401 }
402
403 dump(Out, BaseSubobject(BaseDecl, BaseOffset), VisitedVirtualBases);
404 }
405
406 Out << "Final overriders for (";
408 Out << ", ";
409 Out << Base.getBaseOffset().getQuantity() << ")\n";
410
411
412 for (const auto *MD : RD->methods()) {
414 continue;
415 MD = MD->getCanonicalDecl();
416
417 OverriderInfo Overrider = getOverrider(MD, Base.getBaseOffset());
418
419 Out << " ";
420 MD->printQualifiedName(Out);
421 Out << " - (";
422 Overrider.Method->printQualifiedName(Out);
423 Out << ", " << Overrider.Offset.getQuantity() << ')';
424
425 BaseOffset Offset;
426 if (!Overrider.Method->isPureVirtual())
427 Offset = ComputeReturnAdjustmentBaseOffset(Context, Overrider.Method, MD);
428
429 if (!Offset.isEmpty()) {
430 Out << " [ret-adj: ";
431 if (Offset.VirtualBase) {
432 Offset.VirtualBase->printQualifiedName(Out);
433 Out << " vbase, ";
434 }
435
436 Out << Offset.NonVirtualOffset.getQuantity() << " nv]";
437 }
438
439 Out << "\n";
440 }
441}
442
443
444struct VCallOffsetMap {
445
446 typedef std::pair<const CXXMethodDecl *, CharUnits> MethodAndOffsetPairTy;
447
448
449
451
452
453
454 static bool MethodsCanShareVCallOffset(const CXXMethodDecl *LHS,
456
457public:
458
459
460
462
463
464
466
467
468 bool empty() const { return Offsets.empty(); }
469};
470
471static bool HasSameVirtualSignature(const CXXMethodDecl *LHS,
477
478
479 if (LT == RT) return true;
480
481
482
483
485 return false;
486 return LT->getParamTypes() == RT->getParamTypes();
487}
488
489bool VCallOffsetMap::MethodsCanShareVCallOffset(const CXXMethodDecl *LHS,
493
494
497
498
499
500
503 if (LHSName != RHSName)
504 return false;
505
506
507 return HasSameVirtualSignature(LHS, RHS);
508}
509
510bool VCallOffsetMap::AddVCallOffset(const CXXMethodDecl *MD,
512
513 for (const auto &OffsetPair : Offsets) {
514 if (MethodsCanShareVCallOffset(OffsetPair.first, MD))
515 return false;
516 }
517
518
519 Offsets.push_back(MethodAndOffsetPairTy(MD, OffsetOffset));
520 return true;
521}
522
524
525 for (const auto &OffsetPair : Offsets) {
526 if (MethodsCanShareVCallOffset(OffsetPair.first, MD))
527 return OffsetPair.second;
528 }
529
530 llvm_unreachable("Should always find a vcall offset offset!");
531}
532
533
534class VCallAndVBaseOffsetBuilder {
535public:
536 typedef llvm::DenseMap<const CXXRecordDecl *, CharUnits>
537 VBaseOffsetOffsetsMapTy;
538
539private:
541
542
543
545
546
547
548
550
551
553
554
556 VTableComponentVectorTy Components;
557
558
560
561
562 VCallOffsetMap VCallOffsets;
563
564
565
566
567 VBaseOffsetOffsetsMapTy VBaseOffsetOffsets;
568
569
570
571 const FinalOverriders *Overriders;
572
573
574
575 void AddVCallAndVBaseOffsets(BaseSubobject Base, bool BaseIsVirtual,
577
578
580
581
584
585
586
587 CharUnits getCurrentOffsetOffset() const;
588
589public:
593 const FinalOverriders *Overriders,
596 : VTables(VTables), MostDerivedClass(MostDerivedClass),
597 LayoutClass(LayoutClass), Context(MostDerivedClass->getASTContext()),
598 Overriders(Overriders) {
599
600
601 AddVCallAndVBaseOffsets(Base, BaseIsVirtual, OffsetInLayoutClass);
602 }
603
604
605 typedef VTableComponentVectorTy::const_reverse_iterator const_iterator;
606 const_iterator components_begin() const { return Components.rbegin(); }
607 const_iterator components_end() const { return Components.rend(); }
608
609 const VCallOffsetMap &getVCallOffsets() const { return VCallOffsets; }
610 const VBaseOffsetOffsetsMapTy &getVBaseOffsetOffsets() const {
611 return VBaseOffsetOffsets;
612 }
613};
614
615void
616VCallAndVBaseOffsetBuilder::AddVCallAndVBaseOffsets(BaseSubobject Base,
617 bool BaseIsVirtual,
619 const ASTRecordLayout &Layout = Context.getASTRecordLayout(Base.getBase());
620
621
622
623
624
625
626
627
628
629
632
634
635
636 if (PrimaryBaseIsVirtual) {
638 "Primary vbase should have a zero offset!");
639
641 Context.getASTRecordLayout(MostDerivedClass);
642
643 PrimaryBaseOffset =
645 } else {
647 "Primary base should have a zero offset!");
648
649 PrimaryBaseOffset = Base.getBaseOffset();
650 }
651
652 AddVCallAndVBaseOffsets(
654 PrimaryBaseIsVirtual, RealBaseOffset);
655 }
656
657 AddVBaseOffsets(Base.getBase(), RealBaseOffset);
658
659
660 if (BaseIsVirtual)
661 AddVCallOffsets(Base, RealBaseOffset);
662}
663
664CharUnits VCallAndVBaseOffsetBuilder::getCurrentOffsetOffset() const {
665
666
667
668
669 size_t NumComponentsAboveAddrPoint = 3;
670 if (Context.getLangOpts().OmitVTableRTTI)
671 NumComponentsAboveAddrPoint--;
672 int64_t OffsetIndex =
673 -(int64_t)(NumComponentsAboveAddrPoint + Components.size());
674
675
676
677 CharUnits OffsetWidth = Context.toCharUnitsFromBits(
679 ? 32
680 : Context.getTargetInfo().getPointerWidth(LangAS::Default));
681 CharUnits OffsetOffset = OffsetWidth * OffsetIndex;
682
683 return OffsetOffset;
684}
685
686void VCallAndVBaseOffsetBuilder::AddVCallOffsets(BaseSubobject Base,
689 const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
690
692
693
694
695
697
699 "Primary base should have a zero offset!");
700
701 AddVCallOffsets(BaseSubobject(PrimaryBase, Base.getBaseOffset()),
702 VBaseOffset);
703 }
704
705
706 for (const auto *MD : RD->methods()) {
708 continue;
710
711 CharUnits OffsetOffset = getCurrentOffsetOffset();
712
713
714
715 if (!VCallOffsets.AddVCallOffset(MD, OffsetOffset))
716 continue;
717
719
720 if (Overriders) {
721
722 FinalOverriders::OverriderInfo Overrider =
723 Overriders->getOverrider(MD, Base.getBaseOffset());
724
725
726
727 Offset = Overrider.Offset - VBaseOffset;
728 }
729
730 Components.push_back(
732 }
733
734
735 for (const auto &B : RD->bases()) {
736 if (B.isVirtual())
737 continue;
738
739 const CXXRecordDecl *BaseDecl = B.getType()->getAsCXXRecordDecl();
740 if (BaseDecl == PrimaryBase)
741 continue;
742
743
746
747 AddVCallOffsets(BaseSubobject(BaseDecl, BaseOffset),
748 VBaseOffset);
749 }
750}
751
752void
753VCallAndVBaseOffsetBuilder::AddVBaseOffsets(const CXXRecordDecl *RD,
756 Context.getASTRecordLayout(LayoutClass);
757
758
759 for (const auto &B : RD->bases()) {
760 const CXXRecordDecl *BaseDecl = B.getType()->getAsCXXRecordDecl();
761
762
763 if (B.isVirtual() && VisitedVirtualBases.insert(BaseDecl).second) {
766
767
768 assert(!VBaseOffsetOffsets.count(BaseDecl) &&
769 "vbase offset offset already exists!");
770
771 CharUnits VBaseOffsetOffset = getCurrentOffsetOffset();
772 VBaseOffsetOffsets.insert(
773 std::make_pair(BaseDecl, VBaseOffsetOffset));
774
775 Components.push_back(
777 }
778
779
780 AddVBaseOffsets(BaseDecl, OffsetInLayoutClass);
781 }
782}
783
784
785class ItaniumVTableBuilder {
786public:
787
788
790 PrimaryBasesSetVectorTy;
791
792 typedef llvm::DenseMap<const CXXRecordDecl *, CharUnits>
793 VBaseOffsetOffsetsMapTy;
794
796
797 typedef llvm::DenseMap<GlobalDecl, int64_t> MethodVTableIndicesTy;
798
799private:
800
802
803
804
806
807
808
809 const CharUnits MostDerivedClassOffset;
810
811
812
813 bool MostDerivedClassIsVirtual;
814
815
816
817
819
820
822
823
824 const FinalOverriders Overriders;
825
826
827
828 llvm::DenseMap<const CXXRecordDecl *, VCallOffsetMap> VCallOffsetsForVBases;
829
830
831
832 VBaseOffsetOffsetsMapTy VBaseOffsetOffsets;
833
834
836
837
838 AddressPointsMapTy AddressPoints;
839
840
841
842 struct MethodInfo {
843
845
846
847
848 const CharUnits BaseOffsetInLayoutClass;
849
850
851
852 const uint64_t VTableIndex;
853
855 uint64_t VTableIndex)
856 : BaseOffset(BaseOffset),
857 BaseOffsetInLayoutClass(BaseOffsetInLayoutClass),
858 VTableIndex(VTableIndex) { }
859
860 MethodInfo()
863 VTableIndex(0) { }
864
865 MethodInfo(MethodInfo const&) = default;
866 };
867
868 typedef llvm::DenseMap<const CXXMethodDecl *, MethodInfo> MethodInfoMapTy;
869
870
871
872 MethodInfoMapTy MethodInfoMap;
873
874
875
876 MethodVTableIndicesTy MethodVTableIndices;
877
878 typedef llvm::DenseMap<uint64_t, ThunkInfo> VTableThunksMapTy;
879
880
881
882 VTableThunksMapTy VTableThunks;
883
885 typedef llvm::DenseMap<const CXXMethodDecl *, ThunkInfoVectorTy> ThunksMapTy;
886
887
888
889 ThunksMapTy Thunks;
890
891
893
894
895
896 void ComputeThisAdjustments();
897
899
900
901
902 VisitedVirtualBasesSetTy PrimaryVirtualBases;
903
904
905
907
908
909
912
913
914
915
918 CharUnits BaseOffsetInLayoutClass,
919 FinalOverriders::OverriderInfo Overrider);
920
921
922
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944 bool IsOverriderUsed(const CXXMethodDecl *Overrider,
945 CharUnits BaseOffsetInLayoutClass,
946 const CXXRecordDecl *FirstBaseInPrimaryBaseChain,
947 CharUnits FirstBaseOffsetInLayoutClass) const;
948
949
950
951
953 const CXXRecordDecl *FirstBaseInPrimaryBaseChain,
954 CharUnits FirstBaseOffsetInLayoutClass,
955 PrimaryBasesSetVectorTy &PrimaryBases);
956
957
958
959 void LayoutVTable();
960
961
962
963
964
965
966
967
968
970 bool BaseIsMorallyVirtual,
971 bool BaseIsVirtualInLayoutClass,
973
974
975
976
977
978
979 void LayoutSecondaryVTables(BaseSubobject Base, bool BaseIsMorallyVirtual,
981
982
983
984 void DeterminePrimaryVirtualBases(const CXXRecordDecl *RD,
986 VisitedVirtualBasesSetTy &VBases);
987
988
989
990 void LayoutVTablesForVirtualBases(const CXXRecordDecl *RD,
991 VisitedVirtualBasesSetTy &VBases);
992
993
994
995 bool isBuildingConstructorVTable() const {
996 return MostDerivedClass != LayoutClass;
997 }
998
999public:
1000
1001
1003
1006 CharUnits MostDerivedClassOffset,
1007 bool MostDerivedClassIsVirtual,
1009 : VTables(VTables), MostDerivedClass(MostDerivedClass),
1010 MostDerivedClassOffset(MostDerivedClassOffset),
1011 MostDerivedClassIsVirtual(MostDerivedClassIsVirtual),
1012 LayoutClass(LayoutClass), Context(MostDerivedClass->getASTContext()),
1013 Overriders(MostDerivedClass, MostDerivedClassOffset, LayoutClass) {
1014 assert(!Context.getTargetInfo().getCXXABI().isMicrosoft());
1015
1016 LayoutVTable();
1017
1018 if (Context.getLangOpts().DumpVTableLayouts)
1019 dumpLayout(llvm::outs());
1020 }
1021
1022 uint64_t getNumThunks() const {
1023 return Thunks.size();
1024 }
1025
1026 ThunksMapTy::const_iterator thunks_begin() const {
1027 return Thunks.begin();
1028 }
1029
1030 ThunksMapTy::const_iterator thunks_end() const {
1031 return Thunks.end();
1032 }
1033
1034 const VBaseOffsetOffsetsMapTy &getVBaseOffsetOffsets() const {
1035 return VBaseOffsetOffsets;
1036 }
1037
1038 const AddressPointsMapTy &getAddressPoints() const {
1039 return AddressPoints;
1040 }
1041
1042 MethodVTableIndicesTy::const_iterator vtable_indices_begin() const {
1043 return MethodVTableIndices.begin();
1044 }
1045
1046 MethodVTableIndicesTy::const_iterator vtable_indices_end() const {
1047 return MethodVTableIndices.end();
1048 }
1049
1051
1052 AddressPointsMapTy::const_iterator address_points_begin() const {
1053 return AddressPoints.begin();
1054 }
1055
1056 AddressPointsMapTy::const_iterator address_points_end() const {
1057 return AddressPoints.end();
1058 }
1059
1060 VTableThunksMapTy::const_iterator vtable_thunks_begin() const {
1061 return VTableThunks.begin();
1062 }
1063
1064 VTableThunksMapTy::const_iterator vtable_thunks_end() const {
1065 return VTableThunks.end();
1066 }
1067
1068
1069 void dumpLayout(raw_ostream&);
1070};
1071
1072void ItaniumVTableBuilder::AddThunk(const CXXMethodDecl *MD,
1074 assert(!isBuildingConstructorVTable() &&
1075 "Can't add thunks for construction vtable");
1076
1078
1079
1080 if (llvm::is_contained(ThunksVector, Thunk))
1081 return;
1082
1083 ThunksVector.push_back(Thunk);
1084}
1085
1087
1088
1089
1090
1091
1092template
1093static void
1094visitAllOverriddenMethods(const CXXMethodDecl *MD, VisitorTy &Visitor) {
1096
1098 if (!Visitor(OverriddenMD))
1099 continue;
1100 visitAllOverriddenMethods(OverriddenMD, Visitor);
1101 }
1102}
1103
1104
1105
1106static void
1107ComputeAllOverriddenMethods(const CXXMethodDecl *MD,
1108 OverriddenMethodsSetTy& OverriddenMethods) {
1109 auto OverriddenMethodsCollector = [&](const CXXMethodDecl *MD) {
1110
1111 return OverriddenMethods.insert(MD).second;
1112 };
1113 visitAllOverriddenMethods(MD, OverriddenMethodsCollector);
1114}
1115
1116void ItaniumVTableBuilder::ComputeThisAdjustments() {
1117
1118
1119 for (const auto &MI : MethodInfoMap) {
1121 const MethodInfo &MethodInfo = MI.second;
1122
1123
1124 uint64_t VTableIndex = MethodInfo.VTableIndex;
1125 if (Components[VTableIndex].getKind() ==
1127 continue;
1128
1129
1130 FinalOverriders::OverriderInfo Overrider =
1131 Overriders.getOverrider(MD, MethodInfo.BaseOffset);
1132
1133
1134 if (MethodInfo.BaseOffsetInLayoutClass == Overrider.Offset) {
1135
1136
1137
1138
1139
1140 if (VTableThunks.lookup(VTableIndex).Return.isEmpty())
1141 continue;
1142 }
1143
1145 ComputeThisAdjustment(MD, MethodInfo.BaseOffsetInLayoutClass, Overrider);
1146
1148 continue;
1149
1150
1151 auto SetThisAdjustmentThunk = [&](uint64_t Idx) {
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173 auto [It, Inserted] = VTableThunks.try_emplace(Idx);
1174 if (Inserted) {
1176 It->second.Method = Method;
1178 }
1180 };
1181
1182 SetThisAdjustmentThunk(VTableIndex);
1183
1185
1186 SetThisAdjustmentThunk(VTableIndex + 1);
1187 }
1188 }
1189
1190
1191 MethodInfoMap.clear();
1192
1193 if (isBuildingConstructorVTable()) {
1194
1195 return;
1196 }
1197
1198 for (const auto &TI : VTableThunks) {
1199 const VTableComponent &Component = Components[TI.first];
1200 const ThunkInfo &Thunk = TI.second;
1202
1203 switch (Component.getKind()) {
1204 default:
1205 llvm_unreachable("Unexpected vtable component kind!");
1208 break;
1211 break;
1213
1214 continue;
1215 }
1216
1217 if (MD->getParent() == MostDerivedClass)
1218 AddThunk(MD, Thunk);
1219 }
1220}
1221
1223ItaniumVTableBuilder::ComputeReturnAdjustment(BaseOffset Offset) {
1225
1226 if (!Offset.isEmpty()) {
1227 if (Offset.VirtualBase) {
1228
1229 if (Offset.DerivedClass == MostDerivedClass) {
1230
1232 VBaseOffsetOffsets.lookup(Offset.VirtualBase).getQuantity();
1233 } else {
1237 }
1238 }
1239
1240 Adjustment.NonVirtual = Offset.NonVirtualOffset.getQuantity();
1241 }
1242
1243 return Adjustment;
1244}
1245
1246BaseOffset ItaniumVTableBuilder::ComputeThisAdjustmentBaseOffset(
1250
1251 CXXBasePaths Paths(true,
1252 true, true);
1253
1255 llvm_unreachable("Class must be derived from the passed in base class!");
1256
1257
1258
1260 BaseOffset Offset = ComputeBaseOffset(Context, DerivedRD, Path);
1261
1262 CharUnits OffsetToBaseSubobject = Offset.NonVirtualOffset;
1263
1264 if (Offset.VirtualBase) {
1265
1266
1268 Context.getASTRecordLayout(LayoutClass);
1269
1270
1271
1272 OffsetToBaseSubobject +=
1274 } else {
1275
1276
1277 OffsetToBaseSubobject += Derived.getBaseOffset();
1278 }
1279
1280
1281 if (OffsetToBaseSubobject == Base.getBaseOffset()) {
1282
1283
1284 Offset.NonVirtualOffset = -Offset.NonVirtualOffset;
1285 return Offset;
1286 }
1287 }
1288
1289 return BaseOffset();
1290}
1291
1292ThisAdjustment ItaniumVTableBuilder::ComputeThisAdjustment(
1294 FinalOverriders::OverriderInfo Overrider) {
1295
1298
1300 BaseOffsetInLayoutClass);
1301
1303 Overrider.Offset);
1304
1305
1306 BaseOffset Offset = ComputeThisAdjustmentBaseOffset(OverriddenBaseSubobject,
1307 OverriderBaseSubobject);
1308 if (Offset.isEmpty())
1310
1312
1313 if (Offset.VirtualBase) {
1314
1315 VCallOffsetMap &VCallOffsets = VCallOffsetsForVBases[Offset.VirtualBase];
1316
1317 if (VCallOffsets.empty()) {
1318
1319
1320 VCallAndVBaseOffsetBuilder Builder(
1321 VTables, MostDerivedClass, MostDerivedClass,
1322 nullptr,
1324 true,
1325
1327
1328 VCallOffsets = Builder.getVCallOffsets();
1329 }
1330
1332 VCallOffsets.getVCallOffsetOffset(MD).getQuantity();
1333 }
1334
1335
1336 Adjustment.NonVirtual = Offset.NonVirtualOffset.getQuantity();
1337
1338 return Adjustment;
1339}
1340
1341void ItaniumVTableBuilder::AddMethod(const CXXMethodDecl *MD,
1343 if (const CXXDestructorDecl *DD = dyn_cast(MD)) {
1345 "Destructor can't have return adjustment!");
1346
1347
1350 } else {
1351
1354
1355
1357 }
1358}
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371static bool OverridesIndirectMethodInBases(
1373 ItaniumVTableBuilder::PrimaryBasesSetVectorTy &Bases) {
1374 if (Bases.count(MD->getParent()))
1375 return true;
1376
1378
1379 if (OverridesIndirectMethodInBases(OverriddenMD, Bases))
1380 return true;
1381 }
1382
1383 return false;
1384}
1385
1386bool ItaniumVTableBuilder::IsOverriderUsed(
1388 const CXXRecordDecl *FirstBaseInPrimaryBaseChain,
1389 CharUnits FirstBaseOffsetInLayoutClass) const {
1390
1391
1392 if (BaseOffsetInLayoutClass == FirstBaseOffsetInLayoutClass)
1393 return true;
1394
1395
1396
1397
1398
1399
1400
1401 if (Overrider->getParent() == FirstBaseInPrimaryBaseChain)
1402 return true;
1403
1404 ItaniumVTableBuilder::PrimaryBasesSetVectorTy PrimaryBases;
1405
1406 const CXXRecordDecl *RD = FirstBaseInPrimaryBaseChain;
1407 PrimaryBases.insert(RD);
1408
1409
1410
1411 while (true) {
1412 const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
1414
1415 if (!PrimaryBase)
1416 break;
1417
1420 "Primary base should always be at offset 0!");
1421
1423 Context.getASTRecordLayout(LayoutClass);
1424
1425
1426
1428 FirstBaseOffsetInLayoutClass) {
1429
1430 break;
1431 }
1432 } else {
1434 "Primary base should always be at offset 0!");
1435 }
1436
1437 if (!PrimaryBases.insert(PrimaryBase))
1438 llvm_unreachable("Found a duplicate primary base!");
1439
1440 RD = PrimaryBase;
1441 }
1442
1443
1444
1445 return OverridesIndirectMethodInBases(Overrider, PrimaryBases);
1446}
1447
1449
1450
1451
1452
1454FindNearestOverriddenMethod(const CXXMethodDecl *MD,
1455 BasesSetVectorTy &Bases) {
1456 OverriddenMethodsSetTy OverriddenMethods;
1457 ComputeAllOverriddenMethods(MD, OverriddenMethods);
1458
1459 for (const CXXRecordDecl *PrimaryBase : llvm::reverse(Bases)) {
1460
1461 for (const CXXMethodDecl *OverriddenMD : OverriddenMethods) {
1462
1463 if (OverriddenMD->getParent() == PrimaryBase)
1464 return OverriddenMD;
1465 }
1466 }
1467
1468 return nullptr;
1469}
1470
1471void ItaniumVTableBuilder::AddMethods(
1473 const CXXRecordDecl *FirstBaseInPrimaryBaseChain,
1474 CharUnits FirstBaseOffsetInLayoutClass,
1475 PrimaryBasesSetVectorTy &PrimaryBases) {
1476
1477
1478
1479
1480
1481
1482
1483
1484
1486 const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
1487
1490 CharUnits PrimaryBaseOffsetInLayoutClass;
1493 "Primary vbase should have a zero offset!");
1494
1496 Context.getASTRecordLayout(MostDerivedClass);
1497
1498 PrimaryBaseOffset =
1500
1502 Context.getASTRecordLayout(LayoutClass);
1503
1504 PrimaryBaseOffsetInLayoutClass =
1506 } else {
1508 "Primary base should have a zero offset!");
1509
1510 PrimaryBaseOffset = Base.getBaseOffset();
1511 PrimaryBaseOffsetInLayoutClass = BaseOffsetInLayoutClass;
1512 }
1513
1514 AddMethods(BaseSubobject(PrimaryBase, PrimaryBaseOffset),
1515 PrimaryBaseOffsetInLayoutClass, FirstBaseInPrimaryBaseChain,
1516 FirstBaseOffsetInLayoutClass, PrimaryBases);
1517
1518 if (!PrimaryBases.insert(PrimaryBase))
1519 llvm_unreachable("Found a duplicate primary base!");
1520 }
1521
1523 NewVirtualFunctionsTy NewVirtualFunctions;
1524
1526
1527
1528 for (const auto *MD : RD->methods()) {
1530 continue;
1532
1533
1534 FinalOverriders::OverriderInfo Overrider =
1535 Overriders.getOverrider(MD, Base.getBaseOffset());
1536
1537
1538
1539
1541 FindNearestOverriddenMethod(MD, PrimaryBases)) {
1542 if (ComputeReturnAdjustmentBaseOffset(Context, MD,
1543 OverriddenMD).isEmpty()) {
1545
1546
1547
1548 assert(MethodInfoMap.count(OverriddenMD) &&
1549 "Did not find the overridden method!");
1550 MethodInfo &OverriddenMethodInfo = MethodInfoMap[OverriddenMD];
1551
1552 MethodInfo MethodInfo(Base.getBaseOffset(), BaseOffsetInLayoutClass,
1553 OverriddenMethodInfo.VTableIndex);
1554
1555 assert(!MethodInfoMap.count(MD) &&
1556 "Should not have method info for this method yet!");
1557
1558 MethodInfoMap.insert(std::make_pair(MD, MethodInfo));
1559 MethodInfoMap.erase(OverriddenMD);
1560
1561
1562
1563
1564
1565 if (!isBuildingConstructorVTable() && OverriddenMD != MD) {
1566
1568 ComputeThisAdjustment(OverriddenMD, BaseOffsetInLayoutClass,
1569 Overrider);
1570
1572 Overrider.Method->getParent() == MostDerivedClass) {
1573
1574
1575
1576
1577 BaseOffset ReturnAdjustmentOffset =
1578 ComputeReturnAdjustmentBaseOffset(Context, Overrider.Method, MD);
1580 ComputeReturnAdjustment(ReturnAdjustmentOffset);
1581
1582
1583 AddThunk(Overrider.Method,
1585 OverriddenMD->getThisType().getTypePtr()));
1586 }
1587 }
1588
1589 continue;
1590 }
1591 }
1592
1594 NewImplicitVirtualFunctions.push_back(MD);
1595 else
1596 NewVirtualFunctions.push_back(MD);
1597 }
1598
1599 llvm::stable_sort(
1600 NewImplicitVirtualFunctions,
1602 if (A == B)
1603 return false;
1612 "unexpected or duplicate implicit virtual function");
1613
1614
1615 return false;
1616 });
1617 NewVirtualFunctions.append(NewImplicitVirtualFunctions.begin(),
1618 NewImplicitVirtualFunctions.end());
1619
1620 for (const CXXMethodDecl *MD : NewVirtualFunctions) {
1621
1622 FinalOverriders::OverriderInfo Overrider =
1623 Overriders.getOverrider(MD, Base.getBaseOffset());
1624
1625
1626 MethodInfo MethodInfo(Base.getBaseOffset(), BaseOffsetInLayoutClass,
1627 Components.size());
1628
1629 assert(!MethodInfoMap.count(MD) &&
1630 "Should not have method info for this method yet!");
1631 MethodInfoMap.insert(std::make_pair(MD, MethodInfo));
1632
1633
1634 const CXXMethodDecl *OverriderMD = Overrider.Method;
1635 if (!IsOverriderUsed(OverriderMD, BaseOffsetInLayoutClass,
1636 FirstBaseInPrimaryBaseChain,
1637 FirstBaseOffsetInLayoutClass)) {
1639 continue;
1640 }
1641
1642
1643
1644 BaseOffset ReturnAdjustmentOffset;
1646 ReturnAdjustmentOffset =
1647 ComputeReturnAdjustmentBaseOffset(Context, OverriderMD, MD);
1648 }
1649
1651 ComputeReturnAdjustment(ReturnAdjustmentOffset);
1652
1653
1654
1655
1656
1658 auto &VTT = VTableThunks[Components.size()];
1659 VTT.Method = MD;
1661 }
1662
1664 }
1665}
1666
1667void ItaniumVTableBuilder::LayoutVTable() {
1668 LayoutPrimaryAndSecondaryVTables(BaseSubobject(MostDerivedClass,
1670 false,
1671 MostDerivedClassIsVirtual,
1672 MostDerivedClassOffset);
1673
1674 VisitedVirtualBasesSetTy VBases;
1675
1676
1677 DeterminePrimaryVirtualBases(MostDerivedClass, MostDerivedClassOffset,
1678 VBases);
1679 VBases.clear();
1680
1681 LayoutVTablesForVirtualBases(MostDerivedClass, VBases);
1682
1683
1684 bool IsAppleKext = Context.getLangOpts().AppleKext;
1685 if (IsAppleKext)
1687}
1688
1689void ItaniumVTableBuilder::LayoutPrimaryAndSecondaryVTables(
1691 bool BaseIsVirtualInLayoutClass, CharUnits OffsetInLayoutClass) {
1692 assert(Base.getBase()->isDynamicClass() && "class does not have a vtable!");
1693
1694 unsigned VTableIndex = Components.size();
1695 VTableIndices.push_back(VTableIndex);
1696
1697
1698 VCallAndVBaseOffsetBuilder Builder(
1699 VTables, MostDerivedClass, LayoutClass, &Overriders, Base,
1700 BaseIsVirtualInLayoutClass, OffsetInLayoutClass);
1701 Components.append(Builder.components_begin(), Builder.components_end());
1702
1703
1704 if (BaseIsVirtualInLayoutClass && !Builder.getVCallOffsets().empty()) {
1705 VCallOffsetMap &VCallOffsets = VCallOffsetsForVBases[Base.getBase()];
1706
1707 if (VCallOffsets.empty())
1708 VCallOffsets = Builder.getVCallOffsets();
1709 }
1710
1711
1712
1713 if (Base.getBase() == MostDerivedClass)
1714 VBaseOffsetOffsets = Builder.getVBaseOffsetOffsets();
1715
1716
1717 CharUnits OffsetToTop = MostDerivedClassOffset - OffsetInLayoutClass;
1719
1720
1721 if (!Context.getLangOpts().OmitVTableRTTI)
1723
1724 uint64_t AddressPoint = Components.size();
1725
1726
1727 PrimaryBasesSetVectorTy PrimaryBases;
1728 AddMethods(Base, OffsetInLayoutClass,
1729 Base.getBase(), OffsetInLayoutClass,
1730 PrimaryBases);
1731
1733 if (RD == MostDerivedClass) {
1734 assert(MethodVTableIndices.empty());
1735 for (const auto &I : MethodInfoMap) {
1737 const MethodInfo &MI = I.second;
1738 if (const CXXDestructorDecl *DD = dyn_cast(MD)) {
1740 = MI.VTableIndex - AddressPoint;
1742 = MI.VTableIndex + 1 - AddressPoint;
1743 } else {
1744 MethodVTableIndices[MD] = MI.VTableIndex - AddressPoint;
1745 }
1746 }
1747 }
1748
1749
1750 ComputeThisAdjustments();
1751
1752
1753 while (true) {
1754 AddressPoints.insert(
1755 std::make_pair(BaseSubobject(RD, OffsetInLayoutClass),
1757 unsigned(VTableIndices.size() - 1),
1758 unsigned(AddressPoint - VTableIndex)}));
1759
1760 const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
1762
1763 if (!PrimaryBase)
1764 break;
1765
1767
1768
1770 Context.getASTRecordLayout(LayoutClass);
1771
1773 OffsetInLayoutClass) {
1774
1775 break;
1776 }
1777 }
1778
1779 RD = PrimaryBase;
1780 }
1781
1782
1783 LayoutSecondaryVTables(Base, BaseIsMorallyVirtual, OffsetInLayoutClass);
1784}
1785
1786void
1788 bool BaseIsMorallyVirtual,
1789 CharUnits OffsetInLayoutClass) {
1790
1791
1792
1793
1794
1796 const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
1798
1799 for (const auto &B : RD->bases()) {
1800
1801 if (B.isVirtual())
1802 continue;
1803
1804 const CXXRecordDecl *BaseDecl = B.getType()->getAsCXXRecordDecl();
1805
1806
1808 continue;
1809
1810 if (isBuildingConstructorVTable()) {
1811
1812
1813
1814
1815
1816 if (!BaseIsMorallyVirtual && !BaseDecl->getNumVBases())
1817 continue;
1818 }
1819
1820
1822 CharUnits BaseOffset = Base.getBaseOffset() + RelativeBaseOffset;
1823
1824 CharUnits BaseOffsetInLayoutClass =
1825 OffsetInLayoutClass + RelativeBaseOffset;
1826
1827
1828
1829 if (BaseDecl == PrimaryBase) {
1830 LayoutSecondaryVTables(BaseSubobject(BaseDecl, BaseOffset),
1831 BaseIsMorallyVirtual, BaseOffsetInLayoutClass);
1832 continue;
1833 }
1834
1835
1836 LayoutPrimaryAndSecondaryVTables(
1838 BaseIsMorallyVirtual,
1839 false,
1840 BaseOffsetInLayoutClass);
1841 }
1842}
1843
1844void ItaniumVTableBuilder::DeterminePrimaryVirtualBases(
1846 VisitedVirtualBasesSetTy &VBases) {
1847 const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
1848
1849
1851
1852
1854 bool IsPrimaryVirtualBase = true;
1855
1856 if (isBuildingConstructorVTable()) {
1857
1858
1860 Context.getASTRecordLayout(LayoutClass);
1861
1862 CharUnits PrimaryBaseOffsetInLayoutClass =
1864
1865
1866
1867 if (PrimaryBaseOffsetInLayoutClass != OffsetInLayoutClass)
1868 IsPrimaryVirtualBase = false;
1869 }
1870
1871 if (IsPrimaryVirtualBase)
1872 PrimaryVirtualBases.insert(PrimaryBase);
1873 }
1874 }
1875
1876
1877 for (const auto &B : RD->bases()) {
1878 const CXXRecordDecl *BaseDecl = B.getType()->getAsCXXRecordDecl();
1879
1880 CharUnits BaseOffsetInLayoutClass;
1881
1882 if (B.isVirtual()) {
1883 if (!VBases.insert(BaseDecl).second)
1884 continue;
1885
1887 Context.getASTRecordLayout(LayoutClass);
1888
1889 BaseOffsetInLayoutClass =
1891 } else {
1892 BaseOffsetInLayoutClass =
1894 }
1895
1896 DeterminePrimaryVirtualBases(BaseDecl, BaseOffsetInLayoutClass, VBases);
1897 }
1898}
1899
1900void ItaniumVTableBuilder::LayoutVTablesForVirtualBases(
1901 const CXXRecordDecl *RD, VisitedVirtualBasesSetTy &VBases) {
1902
1903
1904
1905
1906 for (const auto &B : RD->bases()) {
1907 const CXXRecordDecl *BaseDecl = B.getType()->getAsCXXRecordDecl();
1908
1909
1910
1912 !PrimaryVirtualBases.count(BaseDecl) &&
1913 VBases.insert(BaseDecl).second) {
1915 Context.getASTRecordLayout(MostDerivedClass);
1918
1920 Context.getASTRecordLayout(LayoutClass);
1921 CharUnits BaseOffsetInLayoutClass =
1923
1924 LayoutPrimaryAndSecondaryVTables(
1926 true,
1927 true,
1928 BaseOffsetInLayoutClass);
1929 }
1930
1931
1932
1934 LayoutVTablesForVirtualBases(BaseDecl, VBases);
1935 }
1936}
1937
1938static void printThunkMethod(const ThunkInfo &Info, raw_ostream &Out) {
1940 return;
1943 Out << " method: " << Str;
1944}
1945
1946
1947void ItaniumVTableBuilder::dumpLayout(raw_ostream &Out) {
1948
1949
1950
1951 Out << "Original map\n";
1952
1954 std::string Str0 =
1956 P.first);
1957 std::string Str1 =
1959 P.second);
1960 Out << " " << Str0 << " -> " << Str1 << "\n";
1961 }
1962
1963 if (isBuildingConstructorVTable()) {
1964 Out << "Construction vtable for ('";
1966 Out << "', ";
1967 Out << MostDerivedClassOffset.getQuantity() << ") in '";
1969 } else {
1970 Out << "Vtable for '";
1972 }
1973 Out << "' (" << Components.size() << " entries).\n";
1974
1975
1976
1977
1978
1979 std::multimap<uint64_t, BaseSubobject> AddressPointsByIndex;
1980 for (const auto &AP : AddressPoints) {
1982 uint64_t Index =
1983 VTableIndices[AP.second.VTableIndex] + AP.second.AddressPointIndex;
1984
1985 AddressPointsByIndex.insert(std::make_pair(Index, Base));
1986 }
1987
1988 for (unsigned I = 0, E = Components.size(); I != E; ++I) {
1989 uint64_t Index = I;
1990
1991 Out << llvm::format("%4d | ", I);
1992
1994
1995
1996 switch (Component.getKind()) {
1997
1999 Out << "vcall_offset ("
2001 << ")";
2002 break;
2003
2005 Out << "vbase_offset ("
2007 << ")";
2008 break;
2009
2011 Out << "offset_to_top ("
2013 << ")";
2014 break;
2015
2018 Out << " RTTI";
2019 break;
2020
2023
2026 Out << Str;
2028 Out << " [pure]";
2029
2031 Out << " [deleted]";
2032
2033 ThunkInfo Thunk = VTableThunks.lookup(I);
2035
2037 Out << "\n [return adjustment: ";
2039
2042 Out << " vbase offset offset";
2043 }
2044
2045 Out << ']';
2046 printThunkMethod(Thunk, Out);
2047 }
2048
2049
2051 Out << "\n [this adjustment: ";
2053
2056 Out << " vcall offset offset";
2057 }
2058
2059 Out << ']';
2060 printThunkMethod(Thunk, Out);
2061 }
2062 }
2063
2064 break;
2065 }
2066
2069 bool IsComplete =
2071
2073
2075 if (IsComplete)
2076 Out << "() [complete]";
2077 else
2078 Out << "() [deleting]";
2079
2081 Out << " [pure]";
2082
2083 ThunkInfo Thunk = VTableThunks.lookup(I);
2085
2087 Out << "\n [this adjustment: ";
2089
2092 Out << " vcall offset offset";
2093 }
2094
2095 Out << ']';
2096 }
2097 printThunkMethod(Thunk, Out);
2098 }
2099
2100 break;
2101 }
2102
2105
2108 Out << "[unused] " << Str;
2110 Out << " [pure]";
2111 }
2112
2113 }
2114
2115 Out << '\n';
2116
2117
2118 uint64_t NextIndex = Index + 1;
2119 if (unsigned Count = AddressPointsByIndex.count(NextIndex)) {
2120 if (Count == 1) {
2122 AddressPointsByIndex.find(NextIndex)->second;
2123
2124 Out << " -- (";
2125 Base.getBase()->printQualifiedName(Out);
2126 Out << ", " << Base.getBaseOffset().getQuantity();
2127 Out << ") vtable address --\n";
2128 } else {
2130 AddressPointsByIndex.lower_bound(NextIndex)->second.getBaseOffset();
2131
2132
2133 std::setstd::string ClassNames;
2134 for (const auto &I :
2135 llvm::make_range(AddressPointsByIndex.equal_range(NextIndex))) {
2136 assert(I.second.getBaseOffset() == BaseOffset &&
2137 "Invalid base offset!");
2140 }
2141
2142 for (const std::string &Name : ClassNames) {
2143 Out << " -- (" << Name;
2144 Out << ", " << BaseOffset.getQuantity() << ") vtable address --\n";
2145 }
2146 }
2147 }
2148 }
2149
2150 Out << '\n';
2151
2152 if (isBuildingConstructorVTable())
2153 return;
2154
2156
2157
2158
2159 std::map<std::string, CharUnits> ClassNamesAndOffsets;
2160 for (const auto &I : VBaseOffsetOffsets) {
2161 std::string ClassName = I.first->getQualifiedNameAsString();
2162 CharUnits OffsetOffset = I.second;
2163 ClassNamesAndOffsets.insert(std::make_pair(ClassName, OffsetOffset));
2164 }
2165
2166 Out << "Virtual base offset offsets for '";
2168 Out << "' (";
2169 Out << ClassNamesAndOffsets.size();
2170 Out << (ClassNamesAndOffsets.size() == 1 ? " entry" : " entries") << ").\n";
2171
2172 for (const auto &I : ClassNamesAndOffsets)
2173 Out << " " << I.first << " | " << I.second.getQuantity() << '\n';
2174
2175 Out << "\n";
2176 }
2177
2178 if (!Thunks.empty()) {
2179
2180 std::map<std::string, const CXXMethodDecl *> MethodNamesAndDecls;
2181
2182 for (const auto &I : Thunks) {
2186
2187 MethodNamesAndDecls.insert(std::make_pair(MethodName, MD));
2188 }
2189
2190 for (const auto &I : MethodNamesAndDecls) {
2191 const std::string &MethodName = I.first;
2193
2194 ThunkInfoVectorTy ThunksVector = Thunks[MD];
2195 llvm::sort(ThunksVector, [](const ThunkInfo &LHS, const ThunkInfo &RHS) {
2197 });
2198
2199 Out << "Thunks for '" << MethodName << "' (" << ThunksVector.size();
2200 Out << (ThunksVector.size() == 1 ? " entry" : " entries") << ").\n";
2201
2202 for (unsigned I = 0, E = ThunksVector.size(); I != E; ++I) {
2203 const ThunkInfo &Thunk = ThunksVector[I];
2204
2205 Out << llvm::format("%4d | ", I);
2206
2207
2210 Out << " non-virtual";
2213 Out << " vbase offset offset";
2214 }
2215
2217 Out << "\n ";
2218 }
2219
2220
2222 Out << "this adjustment: ";
2224
2227 Out << " vcall offset offset";
2228 }
2229 }
2230
2231 Out << '\n';
2232 }
2233
2234 Out << '\n';
2235 }
2236 }
2237
2238
2239
2240 std::map<uint64_t, std::string> IndicesMap;
2241
2242 for (const auto *MD : MostDerivedClass->methods()) {
2243
2245 continue;
2247
2250
2251 if (const CXXDestructorDecl *DD = dyn_cast(MD)) {
2253 assert(MethodVTableIndices.count(GD));
2254 uint64_t VTableIndex = MethodVTableIndices[GD];
2255 IndicesMap[VTableIndex] = MethodName + " [complete]";
2256 IndicesMap[VTableIndex + 1] = MethodName + " [deleting]";
2257 } else {
2258 assert(MethodVTableIndices.count(MD));
2259 IndicesMap[MethodVTableIndices[MD]] = MethodName;
2260 }
2261 }
2262
2263
2264 if (!IndicesMap.empty()) {
2265 Out << "VTable indices for '";
2267 Out << "' (" << IndicesMap.size() << " entries).\n";
2268
2269 for (const auto &I : IndicesMap) {
2270 uint64_t VTableIndex = I.first;
2271 const std::string &MethodName = I.second;
2272
2273 Out << llvm::format("%4" PRIu64 " | ", VTableIndex) << MethodName
2274 << '\n';
2275 }
2276 }
2277
2278 Out << '\n';
2279}
2280}
2281
2284 unsigned numVTables) {
2286
2287 for (auto it = addressPoints.begin(); it != addressPoints.end(); ++it) {
2288 const auto &addressPointLoc = it->second;
2289 unsigned vtableIndex = addressPointLoc.VTableIndex;
2290 unsigned addressPoint = addressPointLoc.AddressPointIndex;
2291 if (indexMap[vtableIndex]) {
2292
2293
2294 assert(indexMap[vtableIndex] == addressPoint &&
2295 "Every vtable index should have a unique address point. Found a "
2296 "vtable that has two different address points.");
2297 } else {
2298 indexMap[vtableIndex] = addressPoint;
2299 }
2300 }
2301
2302
2303
2304
2305
2306 return indexMap;
2307}
2308
2313 : VTableIndices(std::move(VTableIndices)),
2314 VTableComponents(VTableComponents), VTableThunks(VTableThunks),
2315 AddressPoints(AddressPoints),
2316 AddressPointIndices(
2318 assert(!this->VTableIndices.empty() &&
2319 "VTableLayout requires at least one index.");
2320 assert(this->VTableIndices.front() == 0 &&
2321 "VTableLayout requires the first index is 0.");
2324 assert((LHS.first != RHS.first || LHS.second == RHS.second) &&
2325 "Different thunks should have unique indices!");
2326 return LHS.first < RHS.first;
2327 });
2328}
2329
2331
2335
2339
2341
2344 MethodVTableIndicesTy::iterator I = MethodVTableIndices.find(GD);
2345 if (I != MethodVTableIndices.end())
2346 return I->second;
2347
2349
2350 computeVTableRelatedInformation(RD);
2351
2352 I = MethodVTableIndices.find(GD);
2353 assert(I != MethodVTableIndices.end() && "Did not find index!");
2354 return I->second;
2355}
2356
2360 ClassPairTy ClassPair(RD, VBase);
2361
2362 VirtualBaseClassOffsetOffsetsMapTy::iterator I =
2363 VirtualBaseClassOffsetOffsets.find(ClassPair);
2364 if (I != VirtualBaseClassOffsetOffsets.end())
2365 return I->second;
2366
2367 VCallAndVBaseOffsetBuilder Builder(*this, RD, RD, nullptr,
2369 false,
2371
2372 for (const auto &I : Builder.getVBaseOffsetOffsets()) {
2373
2374 ClassPairTy ClassPair(RD, I.first);
2375
2376 VirtualBaseClassOffsetOffsets.insert(std::make_pair(ClassPair, I.second));
2377 }
2378
2379 I = VirtualBaseClassOffsetOffsets.find(ClassPair);
2380 assert(I != VirtualBaseClassOffsetOffsets.end() && "Did not find index!");
2381
2382 return I->second;
2383}
2384
2387 computeVTableRelatedInformation(MD->getParent());
2389
2390 if (const auto *DD = dyn_cast(OriginalMD))
2392 return OriginalMD;
2393}
2394
2397
2398
2399 while (true) {
2400 auto I = OriginalMethodMap.find(MD);
2401
2402
2403
2404 if (I == OriginalMethodMap.end())
2405 break;
2406
2407
2408 MD = I->second;
2409 }
2410
2411 return MD;
2412}
2413
2414static std::unique_ptr
2417 VTableThunks(Builder.vtable_thunks_begin(), Builder.vtable_thunks_end());
2418
2419 return std::make_unique(
2420 Builder.VTableIndices, Builder.vtable_components(), VTableThunks,
2421 Builder.getAddressPoints());
2422}
2423
2424void
2425ItaniumVTableContext::computeVTableRelatedInformation(const CXXRecordDecl *RD) {
2426 std::unique_ptr &Entry = VTableLayouts[RD];
2427
2428
2429 if (Entry)
2430 return;
2431
2432 ItaniumVTableBuilder Builder(*this, RD, CharUnits::Zero(),
2433 false, RD);
2435
2436 MethodVTableIndices.insert(Builder.vtable_indices_begin(),
2437 Builder.vtable_indices_end());
2438
2439
2440 Thunks.insert(Builder.thunks_begin(), Builder.thunks_end());
2441
2442
2443
2444
2446 return;
2447
2448 const CXXRecordDecl *VBase =
2450
2451 if (VirtualBaseClassOffsetOffsets.count(std::make_pair(RD, VBase)))
2452 return;
2453
2454 for (const auto &I : Builder.getVBaseOffsetOffsets()) {
2455
2456 ClassPairTy ClassPair(RD, I.first);
2457
2458 VirtualBaseClassOffsetOffsets.insert(std::make_pair(ClassPair, I.second));
2459 }
2460}
2461
2462std::unique_ptr
2465 bool MostDerivedClassIsVirtual, const CXXRecordDecl *LayoutClass) {
2466 ItaniumVTableBuilder Builder(*this, MostDerivedClass, MostDerivedClassOffset,
2467 MostDerivedClassIsVirtual, LayoutClass);
2469}
2470
2471namespace {
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
2511
2512
2513
2514
2515class VFTableBuilder {
2516public:
2517 typedef llvm::DenseMap<GlobalDecl, MethodVFTableLocation>
2518 MethodVFTableLocationsTy;
2519
2520 typedef llvm::iterator_rangeMethodVFTableLocationsTy::const\_iterator
2521 method_locations_range;
2522
2523private:
2524
2526
2527
2529
2530
2531
2533
2535
2537
2538
2539 const FinalOverriders Overriders;
2540
2541
2543
2544 MethodVFTableLocationsTy MethodVFTableLocations;
2545
2546
2547 bool HasRTTIComponent = false;
2548
2549
2550
2551 struct MethodInfo {
2552
2553
2554 const uint64_t VBTableIndex;
2555
2556
2557 const uint64_t VFTableIndex;
2558
2559
2560
2561
2562 bool Shadowed;
2563
2564
2565
2566 bool UsesExtraSlot;
2567
2568 MethodInfo(uint64_t VBTableIndex, uint64_t VFTableIndex,
2569 bool UsesExtraSlot = false)
2570 : VBTableIndex(VBTableIndex), VFTableIndex(VFTableIndex),
2571 Shadowed(false), UsesExtraSlot(UsesExtraSlot) {}
2572
2573 MethodInfo()
2574 : VBTableIndex(0), VFTableIndex(0), Shadowed(false),
2575 UsesExtraSlot(false) {}
2576 };
2577
2578 typedef llvm::DenseMap<const CXXMethodDecl *, MethodInfo> MethodInfoMapTy;
2579
2580
2581
2582 MethodInfoMapTy MethodInfoMap;
2583
2584 typedef llvm::DenseMap<uint64_t, ThunkInfo> VTableThunksMapTy;
2585
2586
2587
2588 VTableThunksMapTy VTableThunks;
2589
2590 typedef SmallVector<ThunkInfo, 1> ThunkInfoVectorTy;
2591 typedef llvm::DenseMap<const CXXMethodDecl *, ThunkInfoVectorTy> ThunksMapTy;
2592
2593
2594
2595 ThunksMapTy Thunks;
2596
2597
2598 void AddThunk(const CXXMethodDecl *MD, const ThunkInfo &Thunk) {
2599 SmallVector<ThunkInfo, 1> &ThunksVector = Thunks[MD];
2600
2601
2602 if (llvm::is_contained(ThunksVector, Thunk))
2603 return;
2604
2605 ThunksVector.push_back(Thunk);
2606 }
2607
2608
2609
2610 CharUnits ComputeThisOffset(FinalOverriders::OverriderInfo Overrider);
2611
2612 void CalculateVtordispAdjustment(FinalOverriders::OverriderInfo Overrider,
2613 CharUnits ThisOffset, ThisAdjustment &TA);
2614
2615
2616
2617 void AddMethod(const CXXMethodDecl *MD, ThunkInfo TI) {
2619 VTableThunks[Components.size()] = TI;
2620 AddThunk(MD, TI);
2621 }
2622 if (const CXXDestructorDecl *DD = dyn_cast(MD)) {
2624 "Destructor can't have return adjustment!");
2626 } else {
2628 }
2629 }
2630
2631
2632
2633 void AddMethods(BaseSubobject Base, unsigned BaseDepth,
2634 const CXXRecordDecl *LastVBase,
2635 BasesSetVectorTy &VisitedBases);
2636
2637 void LayoutVFTable() {
2638
2639 if (HasRTTIComponent)
2641
2642 BasesSetVectorTy VisitedBases;
2643 AddMethods(BaseSubobject(MostDerivedClass, CharUnits::Zero()), 0, nullptr,
2644 VisitedBases);
2645
2646
2647 assert(!Components.empty() && "vftable can't be empty");
2648
2649 assert(MethodVFTableLocations.empty());
2650 for (const auto &I : MethodInfoMap) {
2651 const CXXMethodDecl *MD = I.first;
2652 const MethodInfo &MI = I.second;
2654
2655
2656
2657 if (MD->getParent() != MostDerivedClass || MI.Shadowed)
2658 continue;
2659 MethodVFTableLocation Loc(MI.VBTableIndex, WhichVFPtr.getVBaseWithVPtr(),
2661 if (const CXXDestructorDecl *DD = dyn_cast(MD)) {
2662
2667 MethodVFTableLocations[GlobalDecl(DD, DtorTy)] = Loc;
2668 } else {
2669 MethodVFTableLocations[MD] = Loc;
2670 }
2671 }
2672 }
2673
2674public:
2675 VFTableBuilder(MicrosoftVTableContext &VTables,
2676 const CXXRecordDecl *MostDerivedClass, const VPtrInfo &Which)
2677 : VTables(VTables),
2678 Context(MostDerivedClass->getASTContext()),
2679 MostDerivedClass(MostDerivedClass),
2680 MostDerivedClassLayout(Context.getASTRecordLayout(MostDerivedClass)),
2681 WhichVFPtr(Which),
2682 Overriders(MostDerivedClass, CharUnits(), MostDerivedClass) {
2683
2684
2685
2686
2687
2689 HasRTTIComponent = true;
2690
2691 LayoutVFTable();
2692
2693 if (Context.getLangOpts().DumpVTableLayouts)
2694 dumpLayout(llvm::outs());
2695 }
2696
2697 uint64_t getNumThunks() const { return Thunks.size(); }
2698
2699 ThunksMapTy::const_iterator thunks_begin() const { return Thunks.begin(); }
2700
2701 ThunksMapTy::const_iterator thunks_end() const { return Thunks.end(); }
2702
2703 method_locations_range vtable_locations() const {
2704 return method_locations_range(MethodVFTableLocations.begin(),
2705 MethodVFTableLocations.end());
2706 }
2707
2708 ArrayRef vtable_components() const { return Components; }
2709
2710 VTableThunksMapTy::const_iterator vtable_thunks_begin() const {
2711 return VTableThunks.begin();
2712 }
2713
2714 VTableThunksMapTy::const_iterator vtable_thunks_end() const {
2715 return VTableThunks.end();
2716 }
2717
2718 void dumpLayout(raw_ostream &);
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
2768
2769
2770
2771
2772
2773
2774
2775
2776
2778VFTableBuilder::ComputeThisOffset(FinalOverriders::OverriderInfo Overrider) {
2779 BasesSetVectorTy Bases;
2780
2781 {
2782
2783 OverriddenMethodsSetTy VisitedOverriddenMethods;
2784 auto InitialOverriddenDefinitionCollector = [&](
2786 if (OverriddenMD->size_overridden_methods() == 0)
2787 Bases.insert(OverriddenMD->getParent());
2788
2789 return VisitedOverriddenMethods.insert(OverriddenMD).second;
2790 };
2791 visitAllOverriddenMethods(Overrider.Method,
2792 InitialOverriddenDefinitionCollector);
2793 }
2794
2795
2796
2797 if (Bases.size() == 0)
2798 return Overrider.Offset;
2799
2803 return Bases.count(Specifier->getType()->getAsCXXRecordDecl());
2804 },
2805 Paths);
2806
2807
2808
2809
2810
2812 bool First = true;
2813
2817 CharUnits ThisOffset = Overrider.Offset;
2819
2820
2821
2822
2824 QualType CurTy = Element.Base->getType();
2828
2829 if (Element.Base->isVirtual()) {
2830
2831
2832
2833
2834
2835
2836
2837
2838
2839
2840 LastVBaseOffset = ThisOffset =
2842 } else {
2844 }
2845 }
2846
2848 if (LastVBaseOffset.isZero()) {
2849
2850
2851
2852 ThisOffset = Overrider.Offset;
2853 } else {
2854
2855
2856 ThisOffset = LastVBaseOffset;
2857 }
2858 }
2859
2860 if (Ret > ThisOffset || First) {
2862 Ret = ThisOffset;
2863 }
2864 }
2865
2866 assert( && "Method not found in the given subobject?");
2867 return Ret;
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
2959
2960
2961
2962
2963
2964
2965
2966
2967
2968void VFTableBuilder::CalculateVtordispAdjustment(
2969 FinalOverriders::OverriderInfo Overrider, CharUnits ThisOffset,
2973 const ASTRecordLayout::VBaseOffsetsMapTy::const_iterator &VBaseMapEntry =
2975 assert(VBaseMapEntry != VBaseMap.end());
2976
2977
2978
2979 if (!VBaseMapEntry->second.hasVtorDisp() ||
2981 return;
2982
2983
2984
2985 CharUnits OffsetOfVBaseWithVFPtr = VBaseMapEntry->second.VBaseOffset;
2987 (OffsetOfVBaseWithVFPtr - WhichVFPtr.FullOffsetInMDC).getQuantity() - 4;
2988
2989
2990
2991 if (Overrider.Method->getParent() == MostDerivedClass ||
2992 !Overrider.VirtualBase)
2993 return;
2994
2995
2996
2999 MostDerivedClassLayout.getVBPtrOffset()).getQuantity();
3002 VTables.getVBTableIndex(MostDerivedClass, Overrider.VirtualBase);
3003
3004 TA.NonVirtual = (ThisOffset - Overrider.Offset).getQuantity();
3005}
3006
3010
3011
3012
3013
3014
3015
3018 typedef llvm::DenseMap<DeclarationName, unsigned> VisitedGroupIndicesTy;
3019 VisitedGroupIndicesTy VisitedGroupIndices;
3020 for (const auto *D : RD->decls()) {
3021 const auto *ND = dyn_cast(D);
3022 if (!ND)
3023 continue;
3024 VisitedGroupIndicesTy::iterator J;
3025 bool Inserted;
3026 std::tie(J, Inserted) = VisitedGroupIndices.insert(
3027 std::make_pair(ND->getDeclName(), Groups.size()));
3028 if (Inserted)
3029 Groups.push_back(MethodGroup());
3030 if (const auto *MD = dyn_cast(ND))
3033 }
3034
3035 for (const MethodGroup &Group : Groups)
3036 VirtualMethods.append(Group.rbegin(), Group.rend());
3037}
3038
3040 for (const auto &B : RD->bases()) {
3041 if (B.isVirtual() && B.getType()->getAsCXXRecordDecl() == Base)
3042 return true;
3043 }
3044 return false;
3045}
3046
3047void VFTableBuilder::AddMethods(BaseSubobject Base, unsigned BaseDepth,
3049 BasesSetVectorTy &VisitedBases) {
3052 return;
3053
3055
3056
3057
3058
3059 const CXXRecordDecl *NextBase = nullptr, *NextLastVBase = LastVBase;
3064 NextLastVBase = NextBase;
3066 } else {
3067 NextBaseOffset =
3069 }
3072 "No primary virtual bases in this ABI");
3073 NextBase = PrimaryBase;
3074 NextBaseOffset = Base.getBaseOffset();
3075 }
3076
3077 if (NextBase) {
3078 AddMethods(BaseSubobject(NextBase, NextBaseOffset), BaseDepth + 1,
3079 NextLastVBase, VisitedBases);
3080 if (!VisitedBases.insert(NextBase))
3081 llvm_unreachable("Found a duplicate primary base!");
3082 }
3083
3085
3087
3088
3089
3090
3091
3092
3093
3094
3095
3096 for (const CXXMethodDecl *MD : VirtualMethods) {
3097 FinalOverriders::OverriderInfo FinalOverrider =
3098 Overriders.getOverrider(MD, Base.getBaseOffset());
3099 const CXXMethodDecl *FinalOverriderMD = FinalOverrider.Method;
3101 FindNearestOverriddenMethod(MD, VisitedBases);
3102
3104 bool ReturnAdjustingThunk = false, ForceReturnAdjustmentMangling = false;
3105 CharUnits ThisOffset = ComputeThisOffset(FinalOverrider);
3107 (ThisOffset - WhichVFPtr.FullOffsetInMDC).getQuantity();
3108 if ((OverriddenMD || FinalOverriderMD != MD) &&
3110 CalculateVtordispAdjustment(FinalOverrider, ThisOffset,
3111 ThisAdjustmentOffset);
3112
3113 unsigned VBIndex =
3114 LastVBase ? VTables.getVBTableIndex(MostDerivedClass, LastVBase) : 0;
3115
3116 if (OverriddenMD) {
3117
3118
3119 MethodInfoMapTy::iterator OverriddenMDIterator =
3120 MethodInfoMap.find(OverriddenMD);
3121
3122
3123 if (OverriddenMDIterator == MethodInfoMap.end())
3124 continue;
3125
3126 MethodInfo &OverriddenMethodInfo = OverriddenMDIterator->second;
3127
3128 VBIndex = OverriddenMethodInfo.VBTableIndex;
3129
3130
3131
3132
3133
3134
3135 ReturnAdjustingThunk = !ComputeReturnAdjustmentBaseOffset(
3136 Context, MD, OverriddenMD).isEmpty() ||
3137 OverriddenMethodInfo.UsesExtraSlot;
3138
3139 if (!ReturnAdjustingThunk) {
3140
3141
3142 MethodInfo MI(VBIndex, OverriddenMethodInfo.VFTableIndex);
3143 MethodInfoMap.erase(OverriddenMDIterator);
3144
3145 assert(!MethodInfoMap.count(MD) &&
3146 "Should not have method info for this method yet!");
3147 MethodInfoMap.insert(std::make_pair(MD, MI));
3148 continue;
3149 }
3150
3151
3152
3153 OverriddenMethodInfo.Shadowed = true;
3154
3155
3156
3157 ForceReturnAdjustmentMangling =
3158 !(MD == FinalOverriderMD && ThisAdjustmentOffset.isEmpty());
3161
3162
3163
3164 continue;
3165 }
3166
3167
3168
3169 MethodInfo MI(VBIndex,
3170 HasRTTIComponent ? Components.size() - 1 : Components.size(),
3171 ReturnAdjustingThunk);
3172
3173 assert(!MethodInfoMap.count(MD) &&
3174 "Should not have method info for this method yet!");
3175 MethodInfoMap.insert(std::make_pair(MD, MI));
3176
3177
3178
3179 BaseOffset ReturnAdjustmentOffset;
3182 ReturnAdjustmentOffset =
3183 ComputeReturnAdjustmentBaseOffset(Context, FinalOverriderMD, MD);
3184 }
3185 if (!ReturnAdjustmentOffset.isEmpty()) {
3186 ForceReturnAdjustmentMangling = true;
3188 ReturnAdjustmentOffset.NonVirtualOffset.getQuantity();
3189 if (ReturnAdjustmentOffset.VirtualBase) {
3195 VTables.getVBTableIndex(ReturnAdjustmentOffset.DerivedClass,
3196 ReturnAdjustmentOffset.VirtualBase);
3197 }
3198 }
3199 auto ThisType = (OverriddenMD ? OverriddenMD : MD)->getThisType().getTypePtr();
3200 AddMethod(FinalOverriderMD,
3202 ForceReturnAdjustmentMangling ? MD : nullptr));
3203 }
3204}
3205
3207 for (const CXXRecordDecl *Elem : llvm::reverse(Path)) {
3208 Out << "'";
3209 Elem->printQualifiedName(Out);
3210 Out << "' in ";
3211 }
3212}
3213
3215 bool ContinueFirstLine) {
3217 bool Multiline = false;
3218 const char *LinePrefix = "\n ";
3220 if (!ContinueFirstLine)
3221 Out << LinePrefix;
3222 Out << "[return adjustment (to type '"
3228 Out << R.NonVirtual << " non-virtual]";
3229 Multiline = true;
3230 }
3231
3233 if (.isEmpty()) {
3234 if (Multiline || !ContinueFirstLine)
3235 Out << LinePrefix;
3236 Out << "[this adjustment: ";
3238 assert(T.Virtual.Microsoft.VtordispOffset < 0);
3239 Out << "vtordisp at " << T.Virtual.Microsoft.VtordispOffset << ", ";
3240 if (T.Virtual.Microsoft.VBPtrOffset) {
3241 Out << "vbptr at " << T.Virtual.Microsoft.VBPtrOffset
3242 << " to the left,";
3243 assert(T.Virtual.Microsoft.VBOffsetOffset > 0);
3244 Out << LinePrefix << " vboffset at "
3245 << T.Virtual.Microsoft.VBOffsetOffset << " in the vbtable, ";
3246 }
3247 }
3248 Out << T.NonVirtual << " non-virtual]";
3249 }
3250}
3251
3252void VFTableBuilder::dumpLayout(raw_ostream &Out) {
3253 Out << "VFTable for ";
3255 Out << "'";
3257 Out << "' (" << Components.size()
3258 << (Components.size() == 1 ? " entry" : " entries") << ").\n";
3259
3260 for (unsigned I = 0, E = Components.size(); I != E; ++I) {
3261 Out << llvm::format("%4d | ", I);
3262
3264
3265
3266 switch (Component.getKind()) {
3269 Out << " RTTI";
3270 break;
3271
3274
3275
3276
3279 Out << Str;
3281 Out << " [pure]";
3282
3284 Out << " [deleted]";
3285
3286 ThunkInfo Thunk = VTableThunks.lookup(I);
3289
3290 break;
3291 }
3292
3295
3299 Out << "() [vector deleting]";
3300 else
3301 Out << "() [scalar deleting]";
3302
3304 Out << " [pure]";
3305
3306 ThunkInfo Thunk = VTableThunks.lookup(I);
3309 "No return adjustment needed for destructors!");
3311 }
3312
3313 break;
3314 }
3315
3316 default:
3320 "Unexpected vftable component type %0 for component number %1");
3322 << I << Component.getKind();
3323 }
3324
3325 Out << '\n';
3326 }
3327
3328 Out << '\n';
3329
3330 if (!Thunks.empty()) {
3331
3332 std::map<std::string, const CXXMethodDecl *> MethodNamesAndDecls;
3333
3334 for (const auto &I : Thunks) {
3338
3339 MethodNamesAndDecls.insert(std::make_pair(MethodName, MD));
3340 }
3341
3342 for (const auto &MethodNameAndDecl : MethodNamesAndDecls) {
3343 const std::string &MethodName = MethodNameAndDecl.first;
3344 const CXXMethodDecl *MD = MethodNameAndDecl.second;
3345
3346 ThunkInfoVectorTy ThunksVector = Thunks[MD];
3347 llvm::stable_sort(ThunksVector, [](const ThunkInfo &LHS,
3349
3350
3352 });
3353
3354 Out << "Thunks for '" << MethodName << "' (" << ThunksVector.size();
3355 Out << (ThunksVector.size() == 1 ? " entry" : " entries") << ").\n";
3356
3357 for (unsigned I = 0, E = ThunksVector.size(); I != E; ++I) {
3358 const ThunkInfo &Thunk = ThunksVector[I];
3359
3360 Out << llvm::format("%4d | ", I);
3362 Out << '\n';
3363 }
3364
3365 Out << '\n';
3366 }
3367 }
3368
3369 Out.flush();
3370}
3371
3375 if (A.count(Decl))
3376 return true;
3377 }
3378 return false;
3379}
3380
3382
3383
3384
3385
3386
3387
3388
3389
3390
3391
3392
3393
3394
3395
3396
3397
3398
3399
3400
3401
3402
3403
3404void MicrosoftVTableContext::computeVTablePaths(bool ForVBTables,
3407 assert(Paths.empty());
3408 const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
3409
3410
3412 Paths.push_back(std::make_unique(RD));
3413
3414
3415
3416 llvm::SmallPtrSet<const CXXRecordDecl*, 4> VBasesSeen;
3417 for (const auto &B : RD->bases()) {
3418 const CXXRecordDecl *Base = B.getType()->getAsCXXRecordDecl();
3419 if (B.isVirtual() && VBasesSeen.count(Base))
3420 continue;
3421
3422 if (->isDynamicClass())
3423 continue;
3424
3427
3428 for (const std::unique_ptr &BaseInfo : BasePaths) {
3429
3430
3431 if (setsIntersect(VBasesSeen, BaseInfo->ContainingVBases))
3432 continue;
3433
3434
3435 auto P = std::make_unique(*BaseInfo);
3436
3437
3438
3439 if (P->MangledPath.empty() || P->MangledPath.back() != Base)
3440 P->NextBaseToMangle = Base;
3441
3442
3443
3444
3445 if (P->ObjectWithVPtr == Base &&
3448 P->ObjectWithVPtr = RD;
3449
3450
3451
3452 if (B.isVirtual())
3453 P->ContainingVBases.push_back(Base);
3454 else if (P->ContainingVBases.empty())
3456
3457
3458 P->FullOffsetInMDC = P->NonVirtualOffset;
3459 if (const CXXRecordDecl *VB = P->getVBaseWithVPtr())
3461
3462 Paths.push_back(std::move(P));
3463 }
3464
3465 if (B.isVirtual())
3466 VBasesSeen.insert(Base);
3467
3468
3469
3470 for (const auto &VB : Base->vbases())
3471 VBasesSeen.insert(VB.getType()->getAsCXXRecordDecl());
3472 }
3473
3474
3475
3477 while (Changed)
3479}
3480
3484 P.NextBaseToMangle = nullptr;
3485 return true;
3486 }
3487 return false;
3488}
3489
3491
3492
3493
3494
3495
3496
3498 llvm::make_pointee_range(Paths));
3499 llvm::sort(PathsSorted, [](const VPtrInfo &LHS, const VPtrInfo &RHS) {
3501 });
3502 bool Changed = false;
3503 for (size_t I = 0, E = PathsSorted.size(); I != E;) {
3504
3505 size_t BucketStart = I;
3506 do {
3507 ++I;
3508 } while (I != E &&
3509 PathsSorted[BucketStart].get().MangledPath ==
3510 PathsSorted[I].get().MangledPath);
3511
3512
3513 if (I - BucketStart > 1) {
3514 for (size_t II = BucketStart; II != I; ++II)
3515 Changed |= extendPath(PathsSorted[II]);
3516 assert(Changed && "no paths were extended to fix ambiguity");
3517 }
3518 }
3519 return Changed;
3520}
3521
3523
3524namespace {
3525typedef llvm::SetVector<BaseSubobject, std::vector,
3526 llvm::DenseSet> FullPathTy;
3527}
3528
3529
3530
3535 FullPathTy &FullPath,
3536 std::list &Paths) {
3537 if (BaseSubobject(RD, Offset) == IntroducingObject) {
3538 Paths.push_back(FullPath);
3539 return;
3540 }
3541
3542 const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
3543
3546 CharUnits NewOffset = BS.isVirtual()
3551 IntroducingObject, FullPath, Paths);
3552 FullPath.pop_back();
3553 }
3554}
3555
3556
3558 FullPaths.remove_if([&](const FullPathTy &SpecificPath) {
3559 for (const FullPathTy &OtherPath : FullPaths) {
3560 if (&SpecificPath == &OtherPath)
3561 continue;
3562 if (llvm::all_of(SpecificPath, [&](const BaseSubobject &BSO) {
3563 return OtherPath.contains(BSO);
3564 })) {
3565 return true;
3566 }
3567 }
3568 return false;
3569 });
3570}
3571
3574 const FullPathTy &FullPath) {
3576 Context.getASTRecordLayout(RD);
3580
3581 if (Base == RD) {
3582 assert(Offset.getQuantity() == -1);
3584 continue;
3585 }
3586 assert(Offset.getQuantity() != -1);
3587 const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
3588
3589
3592 return BS.getType()->getAsCXXRecordDecl() == Base;
3593 });
3597 }
3598 return Offset;
3599}
3600
3601
3602
3603
3607 std::list &FullPaths) {
3608
3609 if (FullPaths.empty())
3610 return nullptr;
3611 if (FullPaths.size() == 1)
3612 return &FullPaths.front();
3613
3614 const FullPathTy *BestPath = nullptr;
3615 typedef std::set<const CXXMethodDecl *> OverriderSetTy;
3616 OverriderSetTy LastOverrides;
3617 for (const FullPathTy &SpecificPath : FullPaths) {
3618 assert(!SpecificPath.empty());
3619 OverriderSetTy CurrentOverrides;
3620 const CXXRecordDecl *TopLevelRD = SpecificPath.begin()->getBase();
3621
3622
3625 FinalOverriders Overriders(TopLevelRD, CharUnits::Zero(), TopLevelRD);
3628 continue;
3629 FinalOverriders::OverriderInfo OI =
3630 Overriders.getOverrider(MD->getCanonicalDecl(), BaseOffset);
3631 const CXXMethodDecl *OverridingMethod = OI.Method;
3632
3633
3634 if (ComputeReturnAdjustmentBaseOffset(Context, OverridingMethod, MD)
3635 .isEmpty())
3636 continue;
3637
3638
3640 if (llvm::none_of(SpecificPath, [&](const BaseSubobject &BSO) {
3641 return BSO.getBase() == OverridingParent;
3642 }))
3643 continue;
3644 CurrentOverrides.insert(OverridingMethod);
3645 }
3646 OverriderSetTy NewOverrides =
3647 llvm::set_difference(CurrentOverrides, LastOverrides);
3648 if (NewOverrides.empty())
3649 continue;
3650 OverriderSetTy MissingOverrides =
3651 llvm::set_difference(LastOverrides, CurrentOverrides);
3652 if (MissingOverrides.empty()) {
3653
3654 BestPath = &SpecificPath;
3655 std::swap(CurrentOverrides, LastOverrides);
3656 } else {
3657
3659 const CXXMethodDecl *CovariantMD = *NewOverrides.begin();
3660 const CXXMethodDecl *ConflictMD = *MissingOverrides.begin();
3661 Diags.Report(RD->getLocation(), diag::err_vftable_ambiguous_component)
3662 << RD;
3663 Diags.Report(CovariantMD->getLocation(), diag::note_covariant_thunk)
3664 << CovariantMD;
3665 Diags.Report(ConflictMD->getLocation(), diag::note_covariant_thunk)
3666 << ConflictMD;
3667 }
3668 }
3669
3670
3671 return BestPath ? BestPath : &FullPaths.front();
3672}
3673
3677 const ASTRecordLayout &MostDerivedLayout = Context.getASTRecordLayout(RD);
3678 FullPathTy FullPath;
3679 std::list FullPaths;
3680 for (const std::unique_ptr& Info : Paths) {
3683 BaseSubobject(Info->IntroducingObject, Info->FullOffsetInMDC), FullPath,
3684 FullPaths);
3685 FullPath.clear();
3687 Info->PathToIntroducingObject.clear();
3688 if (const FullPathTy *BestPath =
3691 Info->PathToIntroducingObject.push_back(BSO.getBase());
3692 FullPaths.clear();
3693 }
3694}
3695
3707
3708void MicrosoftVTableContext::computeVTableRelatedInformation(
3711
3712
3713 if (VFPtrLocations.count(RD))
3714 return;
3715
3717
3718 {
3719 auto VFPtrs = std::make_unique();
3720 computeVTablePaths(false, RD, *VFPtrs);
3722 VFPtrLocations[RD] = std::move(VFPtrs);
3723 }
3724
3725 MethodVFTableLocationsTy NewMethodLocations;
3726 for (const std::unique_ptr &VFPtr : *VFPtrLocations[RD]) {
3727 VFTableBuilder Builder(*this, RD, *VFPtr);
3728
3729 VFTableIdTy id(RD, VFPtr->FullOffsetInMDC);
3730 assert(VFTableLayouts.count(id) == 0);
3731 SmallVector<VTableLayout::VTableThunkTy, 1> VTableThunks(
3732 Builder.vtable_thunks_begin(), Builder.vtable_thunks_end());
3733 VFTableLayouts[id] = std::make_unique(
3735 VTableThunks, EmptyAddressPointsMap);
3736 Thunks.insert(Builder.thunks_begin(), Builder.thunks_end());
3737
3738 const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
3739 for (const auto &Loc : Builder.vtable_locations()) {
3740 auto Insert = NewMethodLocations.insert(Loc);
3741 if (.second) {
3742 const MethodVFTableLocation &NewLoc = Loc.second;
3743 MethodVFTableLocation &OldLoc = Insert.first->second;
3745 OldLoc = NewLoc;
3746 }
3747 }
3748 }
3749
3750 MethodVFTableLocations.insert_range(NewMethodLocations);
3751 if (Context.getLangOpts().DumpVTableLayouts)
3752 dumpMethodLocations(RD, NewMethodLocations, llvm::outs());
3753}
3754
3755void MicrosoftVTableContext::dumpMethodLocations(
3756 const CXXRecordDecl *RD, const MethodVFTableLocationsTy &NewMethods,
3757 raw_ostream &Out) {
3758
3759
3760 std::map<MethodVFTableLocation, std::string> IndicesMap;
3761 bool HasNonzeroOffset = false;
3762
3763 for (const auto &I : NewMethods) {
3766
3769
3771 IndicesMap[I.second] = MethodName + " [vector deleting]";
3772 } else {
3773 IndicesMap[I.second] = MethodName;
3774 }
3775
3776 if (!I.second.VFPtrOffset.isZero() || I.second.VBTableIndex != 0)
3777 HasNonzeroOffset = true;
3778 }
3779
3780
3781 if (!IndicesMap.empty()) {
3782 Out << "VFTable indices for ";
3783 Out << "'";
3785 Out << "' (" << IndicesMap.size()
3786 << (IndicesMap.size() == 1 ? " entry" : " entries") << ").\n";
3787
3790 for (const auto &I : IndicesMap) {
3791 CharUnits VFPtrOffset = I.first.VFPtrOffset;
3792 uint64_t VBIndex = I.first.VBTableIndex;
3793 if (HasNonzeroOffset &&
3794 (VFPtrOffset != LastVFPtrOffset || VBIndex != LastVBIndex)) {
3795 assert(VBIndex > LastVBIndex || VFPtrOffset > LastVFPtrOffset);
3796 Out << " -- accessible via ";
3797 if (VBIndex)
3798 Out << "vbtable index " << VBIndex << ", ";
3799 Out << "vfptr at offset " << VFPtrOffset.getQuantity() << " --\n";
3800 LastVFPtrOffset = VFPtrOffset;
3801 LastVBIndex = VBIndex;
3802 }
3803
3804 uint64_t VTableIndex = I.first.Index;
3805 const std::string &MethodName = I.second;
3806 Out << llvm::format("%4" PRIu64 " | ", VTableIndex) << MethodName << '\n';
3807 }
3808 Out << '\n';
3809 }
3810
3811 Out.flush();
3812}
3813
3814const VirtualBaseInfo &MicrosoftVTableContext::computeVBTableRelatedInformation(
3816 VirtualBaseInfo *VBI;
3817
3818 {
3819
3820
3821 std::unique_ptr &Entry = VBaseInfo[RD];
3822 if (Entry)
3823 return *Entry;
3824 Entry = std::make_unique();
3825 VBI = Entry.get();
3826 }
3827
3828 computeVTablePaths(true, RD, VBI->VBPtrPaths);
3829
3830
3831 const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
3833
3834
3835 const VirtualBaseInfo &BaseInfo =
3836 computeVBTableRelatedInformation(VBPtrBase);
3838 }
3839
3840
3841
3842 unsigned VBTableIndex = 1 + VBI->VBTableIndices.size();
3843 for (const auto &VB : RD->vbases()) {
3844 const CXXRecordDecl *CurVBase = VB.getType()->getAsCXXRecordDecl();
3845 if (VBI->VBTableIndices.try_emplace(CurVBase, VBTableIndex).second)
3846 ++VBTableIndex;
3847 }
3848
3849 return *VBI;
3850}
3851
3854 const VirtualBaseInfo &VBInfo = computeVBTableRelatedInformation(Derived);
3857}
3858
3861 return computeVBTableRelatedInformation(RD).VBPtrPaths;
3862}
3863
3866 computeVTableRelatedInformation(RD);
3867
3868 assert(VFPtrLocations.count(RD) && "Couldn't find vfptr locations");
3869 return *VFPtrLocations[RD];
3870}
3871
3875 computeVTableRelatedInformation(RD);
3876
3877 VFTableIdTy id(RD, VFPtrOffset);
3878 assert(VFTableLayouts.count(id) && "Couldn't find a VFTable at this offset");
3879 return *VFTableLayouts[id];
3880}
3881
3885 "Only use this method for virtual methods or dtors");
3889
3891
3892 MethodVFTableLocationsTy::iterator I = MethodVFTableLocations.find(GD);
3893 if (I != MethodVFTableLocations.end())
3894 return I->second;
3895
3897
3898 computeVTableRelatedInformation(RD);
3899
3900 I = MethodVFTableLocations.find(GD);
3901 assert(I != MethodVFTableLocations.end() && "Did not find index!");
3902 return I->second;
3903}
Defines the clang::ASTContext interface.
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)
static void findPathsToSubobject(ASTContext &Context, const ASTRecordLayout &MostDerivedLayout, const CXXRecordDecl *RD, CharUnits Offset, BaseSubobject IntroducingObject, FullPathTy &FullPath, std::list< FullPathTy > &Paths)
Definition VTableBuilder.cpp:3531
static const FullPathTy * selectBestPath(ASTContext &Context, const CXXRecordDecl *RD, const VPtrInfo &Info, std::list< FullPathTy > &FullPaths)
Definition VTableBuilder.cpp:3604
static CharUnits getOffsetOfFullPath(ASTContext &Context, const CXXRecordDecl *RD, const FullPathTy &FullPath)
Definition VTableBuilder.cpp:3572
static void removeRedundantPaths(std::list< FullPathTy > &FullPaths)
Definition VTableBuilder.cpp:3557
static std::unique_ptr< VTableLayout > CreateVTableLayout(const ItaniumVTableBuilder &Builder)
Definition VTableBuilder.cpp:2415
static bool vfptrIsEarlierInMDC(const ASTRecordLayout &Layout, const MethodVFTableLocation &LHS, const MethodVFTableLocation &RHS)
Definition VTableBuilder.cpp:3696
static bool isDirectVBase(const CXXRecordDecl *Base, const CXXRecordDecl *RD)
Definition VTableBuilder.cpp:3039
static void PrintBasePath(const VPtrInfo::BasePath &Path, raw_ostream &Out)
Definition VTableBuilder.cpp:3206
static VTableLayout::AddressPointsIndexMapTy MakeAddressPointIndices(const VTableLayout::AddressPointsMapTy &addressPoints, unsigned numVTables)
Definition VTableBuilder.cpp:2283
static bool rebucketPaths(VPtrInfoVector &Paths)
Definition VTableBuilder.cpp:3490
static bool extendPath(VPtrInfo &P)
Definition VTableBuilder.cpp:3481
static void dumpMicrosoftThunkAdjustment(const ThunkInfo &TI, raw_ostream &Out, bool ContinueFirstLine)
Definition VTableBuilder.cpp:3214
static void GroupNewVirtualOverloads(const CXXRecordDecl *RD, SmallVector< const CXXMethodDecl *, 10 > &VirtualMethods)
Definition VTableBuilder.cpp:3007
static void computeFullPathsForVFTables(ASTContext &Context, const CXXRecordDecl *RD, VPtrInfoVector &Paths)
Definition VTableBuilder.cpp:3674
static bool setsIntersect(const llvm::SmallPtrSet< const CXXRecordDecl *, 4 > &A, ArrayRef< const CXXRecordDecl * > B)
Definition VTableBuilder.cpp:3372
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,...
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
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.
bool isMoveAssignmentOperator() const
Determine whether this is a move assignment operator.
bool isCopyAssignmentOperator() const
Determine whether this is a copy-assignment operator, regardless of whether it was declared implicitl...
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...
bool lookupInBases(BaseMatchesCallback BaseMatches, CXXBasePaths &Paths, bool LookupInDependent=false) const
Look for entities within the base classes of this C++ class, transitively searching all base class su...
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.
OverloadedOperatorKind getOverloadedOperator() const
getOverloadedOperator - Which C++ overloaded operator this function represents, if any.
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
Definition VTableBuilder.cpp:2396
const OriginalMethodMapTy & getOriginalMethodMap()
This method is reserved for the implementation and shouldn't be used directly.
uint64_t getMethodVTableIndex(GlobalDecl GD)
Locate a virtual function in the vtable.
Definition VTableBuilder.cpp:2342
bool isRelativeLayout() const
std::unique_ptr< VTableLayout > createConstructionVTableLayout(const CXXRecordDecl *MostDerivedClass, CharUnits MostDerivedClassOffset, bool MostDerivedClassIsVirtual, const CXXRecordDecl *LayoutClass)
Definition VTableBuilder.cpp:2463
~ItaniumVTableContext() override
Definition VTableBuilder.cpp:2340
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...
Definition VTableBuilder.cpp:2358
ItaniumVTableContext(ASTContext &Context, VTableComponentLayout ComponentLayout=Pointer)
Definition VTableBuilder.cpp:2336
GlobalDecl findOriginalMethod(GlobalDecl GD)
Return the method that added the v-table slot that will be used to call the given method.
Definition VTableBuilder.cpp:2385
void setOriginalMethod(const CXXMethodDecl *Key, const CXXMethodDecl *Val)
unsigned getVBTableIndex(const CXXRecordDecl *Derived, const CXXRecordDecl *VBase)
Returns the index of VBase in the vbtable of Derived.
Definition VTableBuilder.cpp:3852
const VPtrInfoVector & enumerateVBTables(const CXXRecordDecl *RD)
Definition VTableBuilder.cpp:3860
MethodVFTableLocation getMethodVFTableLocation(GlobalDecl GD)
Definition VTableBuilder.cpp:3883
const VPtrInfoVector & getVFPtrOffsets(const CXXRecordDecl *RD)
Definition VTableBuilder.cpp:3865
const VTableLayout & getVFTableLayout(const CXXRecordDecl *RD, CharUnits VFPtrOffset)
Definition VTableBuilder.cpp:3873
~MicrosoftVTableContext() override
Definition VTableBuilder.cpp:3522
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.
virtual bool emitVectorDeletingDtors(const LangOptions &) const
Controls whether to emit MSVC vector deleting destructors.
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
VTableContextBase(bool MS)
static bool hasVtableSlot(const CXXMethodDecl *MD)
Determine whether this function should be assigned a vtable slot.
Definition VTableBuilder.cpp:2332
ThunksMapTy Thunks
Contains all thunks that a given method decl will need.
llvm::SmallVector< std::size_t > VTableIndicesTy
VTableLayout(VTableIndicesTy VTableIndices, ArrayRef< VTableComponent > VTableComponents, ArrayRef< VTableThunkTy > VTableThunks, const AddressPointsMapTy &AddressPoints)
Definition VTableBuilder.cpp:2309
~VTableLayout()
Definition VTableBuilder.cpp:2330
llvm::SmallVector< unsigned, 4 > AddressPointsIndexMapTy
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.
CanQual< Type > CanQualType
Represents a canonical, potentially-qualified type.
bool isa(CodeGen::Address addr)
const FunctionProtoType * T
SmallVector< std::unique_ptr< VPtrInfo >, 2 > VPtrInfoVector
CXXDtorType
C++ destructor types.
@ Dtor_VectorDeleting
Vector deleting dtor.
@ Dtor_Complete
Complete object dtor.
@ Dtor_Deleting
Deleting dtor.
for(const auto &A :T->param_types())
U cast(CodeGen::Address addr)
@ 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 * Class
The record decl of the class that the base is a base of.
const CXXBaseSpecifier * Base
The base specifier that states the link from a derived class to a base class, which will be followed ...
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...
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.
SmallVector< const CXXRecordDecl *, 1 > BasePath
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.
const CXXRecordDecl * NextBaseToMangle
The next base to push onto the mangled path if this path is ambiguous in a derived class.
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::@103031170252120233124322035264172076254313213024 Itanium
uint32_t VBPtrOffset
The offset (in bytes) of the vbptr, relative to the beginning of the derived class.
struct clang::ReturnAdjustment::VirtualAdjustment::@167242364125115315334113104006210160165266060257 Microsoft
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.
struct clang::ThisAdjustment::VirtualAdjustment::@106065375072164260365214033034320247050276346205 Itanium
int32_t VtordispOffset
The offset of the vtordisp (in bytes), relative to the ECX.
struct clang::ThisAdjustment::VirtualAdjustment::@312251255113040203233347230177110330127151157305 Microsoft
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...