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

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