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() && VirtualBase; }

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(First && "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 (T.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 (Base->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 (Insert.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