File indexing completed on 2026-05-10 08:36:46
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013 #ifndef LLVM_CLANG_AST_VTABLEBUILDER_H
0014 #define LLVM_CLANG_AST_VTABLEBUILDER_H
0015
0016 #include "clang/AST/BaseSubobject.h"
0017 #include "clang/AST/CXXInheritance.h"
0018 #include "clang/AST/GlobalDecl.h"
0019 #include "clang/AST/RecordLayout.h"
0020 #include "clang/Basic/ABI.h"
0021 #include "clang/Basic/Thunk.h"
0022 #include "llvm/ADT/DenseMap.h"
0023 #include <memory>
0024 #include <utility>
0025
0026 namespace clang {
0027 class CXXRecordDecl;
0028
0029
0030 class VTableComponent {
0031 public:
0032 enum Kind {
0033 CK_VCallOffset,
0034 CK_VBaseOffset,
0035 CK_OffsetToTop,
0036 CK_RTTI,
0037 CK_FunctionPointer,
0038
0039
0040 CK_CompleteDtorPointer,
0041
0042
0043 CK_DeletingDtorPointer,
0044
0045
0046
0047
0048
0049
0050 CK_UnusedFunctionPointer
0051 };
0052
0053 VTableComponent() = default;
0054
0055 static VTableComponent MakeVCallOffset(CharUnits Offset) {
0056 return VTableComponent(CK_VCallOffset, Offset);
0057 }
0058
0059 static VTableComponent MakeVBaseOffset(CharUnits Offset) {
0060 return VTableComponent(CK_VBaseOffset, Offset);
0061 }
0062
0063 static VTableComponent MakeOffsetToTop(CharUnits Offset) {
0064 return VTableComponent(CK_OffsetToTop, Offset);
0065 }
0066
0067 static VTableComponent MakeRTTI(const CXXRecordDecl *RD) {
0068 return VTableComponent(CK_RTTI, reinterpret_cast<uintptr_t>(RD));
0069 }
0070
0071 static VTableComponent MakeFunction(const CXXMethodDecl *MD) {
0072 assert(!isa<CXXDestructorDecl>(MD) &&
0073 "Don't use MakeFunction with destructors!");
0074
0075 return VTableComponent(CK_FunctionPointer,
0076 reinterpret_cast<uintptr_t>(MD));
0077 }
0078
0079 static VTableComponent MakeCompleteDtor(const CXXDestructorDecl *DD) {
0080 return VTableComponent(CK_CompleteDtorPointer,
0081 reinterpret_cast<uintptr_t>(DD));
0082 }
0083
0084 static VTableComponent MakeDeletingDtor(const CXXDestructorDecl *DD) {
0085 return VTableComponent(CK_DeletingDtorPointer,
0086 reinterpret_cast<uintptr_t>(DD));
0087 }
0088
0089 static VTableComponent MakeUnusedFunction(const CXXMethodDecl *MD) {
0090 assert(!isa<CXXDestructorDecl>(MD) &&
0091 "Don't use MakeUnusedFunction with destructors!");
0092 return VTableComponent(CK_UnusedFunctionPointer,
0093 reinterpret_cast<uintptr_t>(MD));
0094 }
0095
0096
0097 Kind getKind() const {
0098 return (Kind)(Value & 0x7);
0099 }
0100
0101 CharUnits getVCallOffset() const {
0102 assert(getKind() == CK_VCallOffset && "Invalid component kind!");
0103
0104 return getOffset();
0105 }
0106
0107 CharUnits getVBaseOffset() const {
0108 assert(getKind() == CK_VBaseOffset && "Invalid component kind!");
0109
0110 return getOffset();
0111 }
0112
0113 CharUnits getOffsetToTop() const {
0114 assert(getKind() == CK_OffsetToTop && "Invalid component kind!");
0115
0116 return getOffset();
0117 }
0118
0119 const CXXRecordDecl *getRTTIDecl() const {
0120 assert(isRTTIKind() && "Invalid component kind!");
0121 return reinterpret_cast<CXXRecordDecl *>(getPointer());
0122 }
0123
0124 const CXXMethodDecl *getFunctionDecl() const {
0125 assert(isFunctionPointerKind() && "Invalid component kind!");
0126 if (isDestructorKind())
0127 return getDestructorDecl();
0128 return reinterpret_cast<CXXMethodDecl *>(getPointer());
0129 }
0130
0131 const CXXDestructorDecl *getDestructorDecl() const {
0132 assert(isDestructorKind() && "Invalid component kind!");
0133 return reinterpret_cast<CXXDestructorDecl *>(getPointer());
0134 }
0135
0136 const CXXMethodDecl *getUnusedFunctionDecl() const {
0137 assert(getKind() == CK_UnusedFunctionPointer && "Invalid component kind!");
0138 return reinterpret_cast<CXXMethodDecl *>(getPointer());
0139 }
0140
0141 bool isDestructorKind() const { return isDestructorKind(getKind()); }
0142
0143 bool isUsedFunctionPointerKind() const {
0144 return isUsedFunctionPointerKind(getKind());
0145 }
0146
0147 bool isFunctionPointerKind() const {
0148 return isFunctionPointerKind(getKind());
0149 }
0150
0151 bool isRTTIKind() const { return isRTTIKind(getKind()); }
0152
0153 GlobalDecl getGlobalDecl() const {
0154 assert(isUsedFunctionPointerKind() &&
0155 "GlobalDecl can be created only from virtual function");
0156
0157 auto *DtorDecl = dyn_cast<CXXDestructorDecl>(getFunctionDecl());
0158 switch (getKind()) {
0159 case CK_FunctionPointer:
0160 return GlobalDecl(getFunctionDecl());
0161 case CK_CompleteDtorPointer:
0162 return GlobalDecl(DtorDecl, CXXDtorType::Dtor_Complete);
0163 case CK_DeletingDtorPointer:
0164 return GlobalDecl(DtorDecl, CXXDtorType::Dtor_Deleting);
0165 case CK_VCallOffset:
0166 case CK_VBaseOffset:
0167 case CK_OffsetToTop:
0168 case CK_RTTI:
0169 case CK_UnusedFunctionPointer:
0170 llvm_unreachable("Only function pointers kinds");
0171 }
0172 llvm_unreachable("Should already return");
0173 }
0174
0175 private:
0176 static bool isFunctionPointerKind(Kind ComponentKind) {
0177 return isUsedFunctionPointerKind(ComponentKind) ||
0178 ComponentKind == CK_UnusedFunctionPointer;
0179 }
0180 static bool isUsedFunctionPointerKind(Kind ComponentKind) {
0181 return ComponentKind == CK_FunctionPointer ||
0182 isDestructorKind(ComponentKind);
0183 }
0184 static bool isDestructorKind(Kind ComponentKind) {
0185 return ComponentKind == CK_CompleteDtorPointer ||
0186 ComponentKind == CK_DeletingDtorPointer;
0187 }
0188 static bool isRTTIKind(Kind ComponentKind) {
0189 return ComponentKind == CK_RTTI;
0190 }
0191
0192 VTableComponent(Kind ComponentKind, CharUnits Offset) {
0193 assert((ComponentKind == CK_VCallOffset ||
0194 ComponentKind == CK_VBaseOffset ||
0195 ComponentKind == CK_OffsetToTop) && "Invalid component kind!");
0196 assert(Offset.getQuantity() < (1LL << 56) && "Offset is too big!");
0197 assert(Offset.getQuantity() >= -(1LL << 56) && "Offset is too small!");
0198
0199 Value = (uint64_t(Offset.getQuantity()) << 3) | ComponentKind;
0200 }
0201
0202 VTableComponent(Kind ComponentKind, uintptr_t Ptr) {
0203 assert((isRTTIKind(ComponentKind) || isFunctionPointerKind(ComponentKind)) &&
0204 "Invalid component kind!");
0205
0206 assert((Ptr & 7) == 0 && "Pointer not sufficiently aligned!");
0207
0208 Value = Ptr | ComponentKind;
0209 }
0210
0211 CharUnits getOffset() const {
0212 assert((getKind() == CK_VCallOffset || getKind() == CK_VBaseOffset ||
0213 getKind() == CK_OffsetToTop) && "Invalid component kind!");
0214
0215 return CharUnits::fromQuantity(Value >> 3);
0216 }
0217
0218 uintptr_t getPointer() const {
0219 assert((getKind() == CK_RTTI || isFunctionPointerKind()) &&
0220 "Invalid component kind!");
0221
0222 return static_cast<uintptr_t>(Value & ~7ULL);
0223 }
0224
0225
0226
0227
0228
0229
0230 int64_t Value;
0231 };
0232
0233 class VTableLayout {
0234 public:
0235 typedef std::pair<uint64_t, ThunkInfo> VTableThunkTy;
0236 struct AddressPointLocation {
0237 unsigned VTableIndex, AddressPointIndex;
0238 };
0239 typedef llvm::DenseMap<BaseSubobject, AddressPointLocation>
0240 AddressPointsMapTy;
0241
0242
0243
0244
0245 typedef llvm::SmallVector<unsigned, 4> AddressPointsIndexMapTy;
0246
0247 private:
0248
0249
0250
0251
0252 OwningArrayRef<size_t> VTableIndices;
0253
0254 OwningArrayRef<VTableComponent> VTableComponents;
0255
0256
0257 OwningArrayRef<VTableThunkTy> VTableThunks;
0258
0259
0260 AddressPointsMapTy AddressPoints;
0261
0262
0263 AddressPointsIndexMapTy AddressPointIndices;
0264
0265 public:
0266 VTableLayout(ArrayRef<size_t> VTableIndices,
0267 ArrayRef<VTableComponent> VTableComponents,
0268 ArrayRef<VTableThunkTy> VTableThunks,
0269 const AddressPointsMapTy &AddressPoints);
0270 ~VTableLayout();
0271
0272 ArrayRef<VTableComponent> vtable_components() const {
0273 return VTableComponents;
0274 }
0275
0276 ArrayRef<VTableThunkTy> vtable_thunks() const {
0277 return VTableThunks;
0278 }
0279
0280 AddressPointLocation getAddressPoint(BaseSubobject Base) const {
0281 assert(AddressPoints.count(Base) && "Did not find address point!");
0282 return AddressPoints.lookup(Base);
0283 }
0284
0285 const AddressPointsMapTy &getAddressPoints() const {
0286 return AddressPoints;
0287 }
0288
0289 const AddressPointsIndexMapTy &getAddressPointIndices() const {
0290 return AddressPointIndices;
0291 }
0292
0293 size_t getNumVTables() const {
0294 if (VTableIndices.empty())
0295 return 1;
0296 return VTableIndices.size();
0297 }
0298
0299 size_t getVTableOffset(size_t i) const {
0300 if (VTableIndices.empty()) {
0301 assert(i == 0);
0302 return 0;
0303 }
0304 return VTableIndices[i];
0305 }
0306
0307 size_t getVTableSize(size_t i) const {
0308 if (VTableIndices.empty()) {
0309 assert(i == 0);
0310 return vtable_components().size();
0311 }
0312
0313 size_t thisIndex = VTableIndices[i];
0314 size_t nextIndex = (i + 1 == VTableIndices.size())
0315 ? vtable_components().size()
0316 : VTableIndices[i + 1];
0317 return nextIndex - thisIndex;
0318 }
0319 };
0320
0321 class VTableContextBase {
0322 public:
0323 typedef SmallVector<ThunkInfo, 1> ThunkInfoVectorTy;
0324
0325 bool isMicrosoft() const { return IsMicrosoftABI; }
0326
0327 virtual ~VTableContextBase() {}
0328
0329 protected:
0330 typedef llvm::DenseMap<const CXXMethodDecl *, ThunkInfoVectorTy> ThunksMapTy;
0331
0332
0333 ThunksMapTy Thunks;
0334
0335
0336
0337 virtual void computeVTableRelatedInformation(const CXXRecordDecl *RD) = 0;
0338
0339 VTableContextBase(bool MS) : IsMicrosoftABI(MS) {}
0340
0341 public:
0342 virtual const ThunkInfoVectorTy *getThunkInfo(GlobalDecl GD) {
0343 const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl()->getCanonicalDecl());
0344 computeVTableRelatedInformation(MD->getParent());
0345
0346
0347
0348 ThunksMapTy::const_iterator I = Thunks.find(MD);
0349 if (I == Thunks.end()) {
0350
0351 return nullptr;
0352 }
0353
0354 return &I->second;
0355 }
0356
0357 bool IsMicrosoftABI;
0358
0359
0360 static bool hasVtableSlot(const CXXMethodDecl *MD);
0361 };
0362
0363 class ItaniumVTableContext : public VTableContextBase {
0364 public:
0365 typedef llvm::DenseMap<const CXXMethodDecl *, const CXXMethodDecl *>
0366 OriginalMethodMapTy;
0367
0368 private:
0369
0370
0371
0372 typedef llvm::DenseMap<GlobalDecl, int64_t> MethodVTableIndicesTy;
0373 MethodVTableIndicesTy MethodVTableIndices;
0374
0375 typedef llvm::DenseMap<const CXXRecordDecl *,
0376 std::unique_ptr<const VTableLayout>>
0377 VTableLayoutMapTy;
0378 VTableLayoutMapTy VTableLayouts;
0379
0380 typedef std::pair<const CXXRecordDecl *,
0381 const CXXRecordDecl *> ClassPairTy;
0382
0383
0384
0385
0386
0387 typedef llvm::DenseMap<ClassPairTy, CharUnits>
0388 VirtualBaseClassOffsetOffsetsMapTy;
0389 VirtualBaseClassOffsetOffsetsMapTy VirtualBaseClassOffsetOffsets;
0390
0391
0392
0393 OriginalMethodMapTy OriginalMethodMap;
0394
0395 void computeVTableRelatedInformation(const CXXRecordDecl *RD) override;
0396
0397 public:
0398 enum VTableComponentLayout {
0399
0400 Pointer,
0401
0402
0403
0404 Relative,
0405 };
0406
0407 ItaniumVTableContext(ASTContext &Context,
0408 VTableComponentLayout ComponentLayout = Pointer);
0409 ~ItaniumVTableContext() override;
0410
0411 const VTableLayout &getVTableLayout(const CXXRecordDecl *RD) {
0412 computeVTableRelatedInformation(RD);
0413 assert(VTableLayouts.count(RD) && "No layout for this record decl!");
0414
0415 return *VTableLayouts[RD];
0416 }
0417
0418 std::unique_ptr<VTableLayout> createConstructionVTableLayout(
0419 const CXXRecordDecl *MostDerivedClass, CharUnits MostDerivedClassOffset,
0420 bool MostDerivedClassIsVirtual, const CXXRecordDecl *LayoutClass);
0421
0422
0423
0424
0425
0426 uint64_t getMethodVTableIndex(GlobalDecl GD);
0427
0428
0429
0430
0431
0432
0433 CharUnits getVirtualBaseOffsetOffset(const CXXRecordDecl *RD,
0434 const CXXRecordDecl *VBase);
0435
0436
0437
0438
0439
0440
0441
0442
0443 GlobalDecl findOriginalMethod(GlobalDecl GD);
0444
0445 const CXXMethodDecl *findOriginalMethodInMap(const CXXMethodDecl *MD) const;
0446
0447 void setOriginalMethod(const CXXMethodDecl *Key, const CXXMethodDecl *Val) {
0448 OriginalMethodMap[Key] = Val;
0449 }
0450
0451
0452
0453 const OriginalMethodMapTy &getOriginalMethodMap() {
0454 return OriginalMethodMap;
0455 }
0456
0457 static bool classof(const VTableContextBase *VT) {
0458 return !VT->isMicrosoft();
0459 }
0460
0461 VTableComponentLayout getVTableComponentLayout() const {
0462 return ComponentLayout;
0463 }
0464
0465 bool isPointerLayout() const { return ComponentLayout == Pointer; }
0466 bool isRelativeLayout() const { return ComponentLayout == Relative; }
0467
0468 private:
0469 VTableComponentLayout ComponentLayout;
0470 };
0471
0472
0473
0474
0475 struct VPtrInfo {
0476 typedef SmallVector<const CXXRecordDecl *, 1> BasePath;
0477
0478 VPtrInfo(const CXXRecordDecl *RD)
0479 : ObjectWithVPtr(RD), IntroducingObject(RD), NextBaseToMangle(RD) {}
0480
0481
0482
0483
0484 const CXXRecordDecl *ObjectWithVPtr;
0485
0486
0487
0488 const CXXRecordDecl *IntroducingObject;
0489
0490
0491
0492 CharUnits NonVirtualOffset;
0493
0494
0495
0496
0497
0498 BasePath MangledPath;
0499
0500
0501
0502 const CXXRecordDecl *NextBaseToMangle;
0503
0504
0505
0506
0507 BasePath ContainingVBases;
0508
0509
0510
0511
0512 BasePath PathToIntroducingObject;
0513
0514
0515
0516 CharUnits FullOffsetInMDC;
0517
0518
0519 const CXXRecordDecl *getVBaseWithVPtr() const {
0520 return ContainingVBases.empty() ? nullptr : ContainingVBases.front();
0521 }
0522 };
0523
0524 typedef SmallVector<std::unique_ptr<VPtrInfo>, 2> VPtrInfoVector;
0525
0526
0527
0528
0529 struct VirtualBaseInfo {
0530
0531
0532 llvm::DenseMap<const CXXRecordDecl *, unsigned> VBTableIndices;
0533
0534
0535
0536 VPtrInfoVector VBPtrPaths;
0537 };
0538
0539 struct MethodVFTableLocation {
0540
0541 uint64_t VBTableIndex;
0542
0543
0544
0545 const CXXRecordDecl *VBase;
0546
0547
0548
0549 CharUnits VFPtrOffset;
0550
0551
0552 uint64_t Index;
0553
0554 MethodVFTableLocation()
0555 : VBTableIndex(0), VBase(nullptr), VFPtrOffset(CharUnits::Zero()),
0556 Index(0) {}
0557
0558 MethodVFTableLocation(uint64_t VBTableIndex, const CXXRecordDecl *VBase,
0559 CharUnits VFPtrOffset, uint64_t Index)
0560 : VBTableIndex(VBTableIndex), VBase(VBase), VFPtrOffset(VFPtrOffset),
0561 Index(Index) {}
0562
0563 bool operator<(const MethodVFTableLocation &other) const {
0564 if (VBTableIndex != other.VBTableIndex) {
0565 assert(VBase != other.VBase);
0566 return VBTableIndex < other.VBTableIndex;
0567 }
0568 return std::tie(VFPtrOffset, Index) <
0569 std::tie(other.VFPtrOffset, other.Index);
0570 }
0571 };
0572
0573 class MicrosoftVTableContext : public VTableContextBase {
0574 public:
0575
0576 private:
0577 ASTContext &Context;
0578
0579 typedef llvm::DenseMap<GlobalDecl, MethodVFTableLocation>
0580 MethodVFTableLocationsTy;
0581 MethodVFTableLocationsTy MethodVFTableLocations;
0582
0583 typedef llvm::DenseMap<const CXXRecordDecl *, std::unique_ptr<VPtrInfoVector>>
0584 VFPtrLocationsMapTy;
0585 VFPtrLocationsMapTy VFPtrLocations;
0586
0587 typedef std::pair<const CXXRecordDecl *, CharUnits> VFTableIdTy;
0588 typedef llvm::DenseMap<VFTableIdTy, std::unique_ptr<const VTableLayout>>
0589 VFTableLayoutMapTy;
0590 VFTableLayoutMapTy VFTableLayouts;
0591
0592 llvm::DenseMap<const CXXRecordDecl *, std::unique_ptr<VirtualBaseInfo>>
0593 VBaseInfo;
0594
0595 void computeVTableRelatedInformation(const CXXRecordDecl *RD) override;
0596
0597 void dumpMethodLocations(const CXXRecordDecl *RD,
0598 const MethodVFTableLocationsTy &NewMethods,
0599 raw_ostream &);
0600
0601 const VirtualBaseInfo &
0602 computeVBTableRelatedInformation(const CXXRecordDecl *RD);
0603
0604 void computeVTablePaths(bool ForVBTables, const CXXRecordDecl *RD,
0605 VPtrInfoVector &Paths);
0606
0607 public:
0608 MicrosoftVTableContext(ASTContext &Context)
0609 : VTableContextBase(true), Context(Context) {}
0610
0611 ~MicrosoftVTableContext() override;
0612
0613 const VPtrInfoVector &getVFPtrOffsets(const CXXRecordDecl *RD);
0614
0615 const VTableLayout &getVFTableLayout(const CXXRecordDecl *RD,
0616 CharUnits VFPtrOffset);
0617
0618 MethodVFTableLocation getMethodVFTableLocation(GlobalDecl GD);
0619
0620 const ThunkInfoVectorTy *getThunkInfo(GlobalDecl GD) override {
0621
0622 if (isa<CXXDestructorDecl>(GD.getDecl()) &&
0623 GD.getDtorType() == Dtor_Complete)
0624 return nullptr;
0625 return VTableContextBase::getThunkInfo(GD);
0626 }
0627
0628
0629
0630
0631
0632 unsigned getVBTableIndex(const CXXRecordDecl *Derived,
0633 const CXXRecordDecl *VBase);
0634
0635 const VPtrInfoVector &enumerateVBTables(const CXXRecordDecl *RD);
0636
0637 static bool classof(const VTableContextBase *VT) { return VT->isMicrosoft(); }
0638 };
0639
0640 }
0641
0642 #endif