1226586Sdim//===--- VTableBuilder.h - C++ vtable layout builder --------------*- C++ -*-=// 2226586Sdim// 3353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4353358Sdim// See https://llvm.org/LICENSE.txt for license information. 5353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6226586Sdim// 7226586Sdim//===----------------------------------------------------------------------===// 8226586Sdim// 9226586Sdim// This contains code dealing with generation of the layout of virtual tables. 10226586Sdim// 11226586Sdim//===----------------------------------------------------------------------===// 12226586Sdim 13226586Sdim#ifndef LLVM_CLANG_AST_VTABLEBUILDER_H 14226586Sdim#define LLVM_CLANG_AST_VTABLEBUILDER_H 15226586Sdim 16226586Sdim#include "clang/AST/BaseSubobject.h" 17226586Sdim#include "clang/AST/CXXInheritance.h" 18226586Sdim#include "clang/AST/GlobalDecl.h" 19226586Sdim#include "clang/AST/RecordLayout.h" 20226586Sdim#include "clang/Basic/ABI.h" 21276479Sdim#include "llvm/ADT/DenseMap.h" 22276479Sdim#include <memory> 23226586Sdim#include <utility> 24226586Sdim 25226586Sdimnamespace clang { 26226586Sdim class CXXRecordDecl; 27226586Sdim 28341825Sdim/// Represents a single component in a vtable. 29226586Sdimclass VTableComponent { 30226586Sdimpublic: 31226586Sdim enum Kind { 32226586Sdim CK_VCallOffset, 33226586Sdim CK_VBaseOffset, 34226586Sdim CK_OffsetToTop, 35226586Sdim CK_RTTI, 36226586Sdim CK_FunctionPointer, 37234353Sdim 38341825Sdim /// A pointer to the complete destructor. 39226586Sdim CK_CompleteDtorPointer, 40234353Sdim 41341825Sdim /// A pointer to the deleting destructor. 42226586Sdim CK_DeletingDtorPointer, 43234353Sdim 44341825Sdim /// An entry that is never used. 45261991Sdim /// 46261991Sdim /// In some cases, a vtable function pointer will end up never being 47261991Sdim /// called. Such vtable function pointers are represented as a 48261991Sdim /// CK_UnusedFunctionPointer. 49226586Sdim CK_UnusedFunctionPointer 50226586Sdim }; 51226586Sdim 52296417Sdim VTableComponent() = default; 53226586Sdim 54226586Sdim static VTableComponent MakeVCallOffset(CharUnits Offset) { 55226586Sdim return VTableComponent(CK_VCallOffset, Offset); 56226586Sdim } 57226586Sdim 58226586Sdim static VTableComponent MakeVBaseOffset(CharUnits Offset) { 59226586Sdim return VTableComponent(CK_VBaseOffset, Offset); 60226586Sdim } 61226586Sdim 62226586Sdim static VTableComponent MakeOffsetToTop(CharUnits Offset) { 63226586Sdim return VTableComponent(CK_OffsetToTop, Offset); 64226586Sdim } 65234353Sdim 66226586Sdim static VTableComponent MakeRTTI(const CXXRecordDecl *RD) { 67226586Sdim return VTableComponent(CK_RTTI, reinterpret_cast<uintptr_t>(RD)); 68226586Sdim } 69226586Sdim 70226586Sdim static VTableComponent MakeFunction(const CXXMethodDecl *MD) { 71234353Sdim assert(!isa<CXXDestructorDecl>(MD) && 72226586Sdim "Don't use MakeFunction with destructors!"); 73226586Sdim 74234353Sdim return VTableComponent(CK_FunctionPointer, 75226586Sdim reinterpret_cast<uintptr_t>(MD)); 76226586Sdim } 77234353Sdim 78226586Sdim static VTableComponent MakeCompleteDtor(const CXXDestructorDecl *DD) { 79226586Sdim return VTableComponent(CK_CompleteDtorPointer, 80226586Sdim reinterpret_cast<uintptr_t>(DD)); 81226586Sdim } 82226586Sdim 83226586Sdim static VTableComponent MakeDeletingDtor(const CXXDestructorDecl *DD) { 84234353Sdim return VTableComponent(CK_DeletingDtorPointer, 85226586Sdim reinterpret_cast<uintptr_t>(DD)); 86226586Sdim } 87226586Sdim 88226586Sdim static VTableComponent MakeUnusedFunction(const CXXMethodDecl *MD) { 89234353Sdim assert(!isa<CXXDestructorDecl>(MD) && 90226586Sdim "Don't use MakeUnusedFunction with destructors!"); 91226586Sdim return VTableComponent(CK_UnusedFunctionPointer, 92234353Sdim reinterpret_cast<uintptr_t>(MD)); 93226586Sdim } 94226586Sdim 95341825Sdim /// Get the kind of this vtable component. 96226586Sdim Kind getKind() const { 97226586Sdim return (Kind)(Value & 0x7); 98226586Sdim } 99226586Sdim 100226586Sdim CharUnits getVCallOffset() const { 101226586Sdim assert(getKind() == CK_VCallOffset && "Invalid component kind!"); 102234353Sdim 103226586Sdim return getOffset(); 104226586Sdim } 105226586Sdim 106226586Sdim CharUnits getVBaseOffset() const { 107226586Sdim assert(getKind() == CK_VBaseOffset && "Invalid component kind!"); 108234353Sdim 109226586Sdim return getOffset(); 110226586Sdim } 111226586Sdim 112226586Sdim CharUnits getOffsetToTop() const { 113226586Sdim assert(getKind() == CK_OffsetToTop && "Invalid component kind!"); 114234353Sdim 115226586Sdim return getOffset(); 116226586Sdim } 117234353Sdim 118226586Sdim const CXXRecordDecl *getRTTIDecl() const { 119296417Sdim assert(isRTTIKind() && "Invalid component kind!"); 120226586Sdim return reinterpret_cast<CXXRecordDecl *>(getPointer()); 121226586Sdim } 122234353Sdim 123226586Sdim const CXXMethodDecl *getFunctionDecl() const { 124296417Sdim assert(isFunctionPointerKind() && "Invalid component kind!"); 125296417Sdim if (isDestructorKind()) 126296417Sdim return getDestructorDecl(); 127226586Sdim return reinterpret_cast<CXXMethodDecl *>(getPointer()); 128226586Sdim } 129226586Sdim 130226586Sdim const CXXDestructorDecl *getDestructorDecl() const { 131296417Sdim assert(isDestructorKind() && "Invalid component kind!"); 132226586Sdim return reinterpret_cast<CXXDestructorDecl *>(getPointer()); 133226586Sdim } 134226586Sdim 135226586Sdim const CXXMethodDecl *getUnusedFunctionDecl() const { 136296417Sdim assert(getKind() == CK_UnusedFunctionPointer && "Invalid component kind!"); 137226586Sdim return reinterpret_cast<CXXMethodDecl *>(getPointer()); 138226586Sdim } 139234353Sdim 140296417Sdim bool isDestructorKind() const { return isDestructorKind(getKind()); } 141296417Sdim 142296417Sdim bool isUsedFunctionPointerKind() const { 143296417Sdim return isUsedFunctionPointerKind(getKind()); 144296417Sdim } 145296417Sdim 146296417Sdim bool isFunctionPointerKind() const { 147296417Sdim return isFunctionPointerKind(getKind()); 148296417Sdim } 149296417Sdim 150296417Sdim bool isRTTIKind() const { return isRTTIKind(getKind()); } 151296417Sdim 152321369Sdim GlobalDecl getGlobalDecl() const { 153321369Sdim assert(isUsedFunctionPointerKind() && 154321369Sdim "GlobalDecl can be created only from virtual function"); 155321369Sdim 156321369Sdim auto *DtorDecl = dyn_cast<CXXDestructorDecl>(getFunctionDecl()); 157321369Sdim switch (getKind()) { 158321369Sdim case CK_FunctionPointer: 159321369Sdim return GlobalDecl(getFunctionDecl()); 160321369Sdim case CK_CompleteDtorPointer: 161321369Sdim return GlobalDecl(DtorDecl, CXXDtorType::Dtor_Complete); 162321369Sdim case CK_DeletingDtorPointer: 163321369Sdim return GlobalDecl(DtorDecl, CXXDtorType::Dtor_Deleting); 164321369Sdim case CK_VCallOffset: 165321369Sdim case CK_VBaseOffset: 166321369Sdim case CK_OffsetToTop: 167321369Sdim case CK_RTTI: 168321369Sdim case CK_UnusedFunctionPointer: 169321369Sdim llvm_unreachable("Only function pointers kinds"); 170321369Sdim } 171321369Sdim llvm_unreachable("Should already return"); 172321369Sdim } 173321369Sdim 174226586Sdimprivate: 175296417Sdim static bool isFunctionPointerKind(Kind ComponentKind) { 176296417Sdim return isUsedFunctionPointerKind(ComponentKind) || 177296417Sdim ComponentKind == CK_UnusedFunctionPointer; 178296417Sdim } 179296417Sdim static bool isUsedFunctionPointerKind(Kind ComponentKind) { 180296417Sdim return ComponentKind == CK_FunctionPointer || 181296417Sdim isDestructorKind(ComponentKind); 182296417Sdim } 183296417Sdim static bool isDestructorKind(Kind ComponentKind) { 184296417Sdim return ComponentKind == CK_CompleteDtorPointer || 185296417Sdim ComponentKind == CK_DeletingDtorPointer; 186296417Sdim } 187296417Sdim static bool isRTTIKind(Kind ComponentKind) { 188296417Sdim return ComponentKind == CK_RTTI; 189296417Sdim } 190296417Sdim 191226586Sdim VTableComponent(Kind ComponentKind, CharUnits Offset) { 192234353Sdim assert((ComponentKind == CK_VCallOffset || 193226586Sdim ComponentKind == CK_VBaseOffset || 194226586Sdim ComponentKind == CK_OffsetToTop) && "Invalid component kind!"); 195243830Sdim assert(Offset.getQuantity() < (1LL << 56) && "Offset is too big!"); 196243830Sdim assert(Offset.getQuantity() >= -(1LL << 56) && "Offset is too small!"); 197234353Sdim 198243830Sdim Value = (uint64_t(Offset.getQuantity()) << 3) | ComponentKind; 199226586Sdim } 200226586Sdim 201226586Sdim VTableComponent(Kind ComponentKind, uintptr_t Ptr) { 202296417Sdim assert((isRTTIKind(ComponentKind) || isFunctionPointerKind(ComponentKind)) && 203296417Sdim "Invalid component kind!"); 204234353Sdim 205226586Sdim assert((Ptr & 7) == 0 && "Pointer not sufficiently aligned!"); 206234353Sdim 207226586Sdim Value = Ptr | ComponentKind; 208226586Sdim } 209234353Sdim 210226586Sdim CharUnits getOffset() const { 211226586Sdim assert((getKind() == CK_VCallOffset || getKind() == CK_VBaseOffset || 212226586Sdim getKind() == CK_OffsetToTop) && "Invalid component kind!"); 213234353Sdim 214226586Sdim return CharUnits::fromQuantity(Value >> 3); 215226586Sdim } 216226586Sdim 217226586Sdim uintptr_t getPointer() const { 218296417Sdim assert((getKind() == CK_RTTI || isFunctionPointerKind()) && 219226586Sdim "Invalid component kind!"); 220234353Sdim 221226586Sdim return static_cast<uintptr_t>(Value & ~7ULL); 222226586Sdim } 223234353Sdim 224226586Sdim /// The kind is stored in the lower 3 bits of the value. For offsets, we 225226586Sdim /// make use of the facts that classes can't be larger than 2^55 bytes, 226261991Sdim /// so we store the offset in the lower part of the 61 bits that remain. 227226586Sdim /// (The reason that we're not simply using a PointerIntPair here is that we 228226586Sdim /// need the offsets to be 64-bit, even when on a 32-bit machine). 229226586Sdim int64_t Value; 230226586Sdim}; 231226586Sdim 232226586Sdimclass VTableLayout { 233226586Sdimpublic: 234226586Sdim typedef std::pair<uint64_t, ThunkInfo> VTableThunkTy; 235314564Sdim struct AddressPointLocation { 236314564Sdim unsigned VTableIndex, AddressPointIndex; 237314564Sdim }; 238314564Sdim typedef llvm::DenseMap<BaseSubobject, AddressPointLocation> 239314564Sdim AddressPointsMapTy; 240226586Sdim 241314564Sdimprivate: 242314564Sdim // Stores the component indices of the first component of each virtual table in 243314564Sdim // the virtual table group. To save a little memory in the common case where 244314564Sdim // the vtable group contains a single vtable, an empty vector here represents 245314564Sdim // the vector {0}. 246314564Sdim OwningArrayRef<size_t> VTableIndices; 247226586Sdim 248314564Sdim OwningArrayRef<VTableComponent> VTableComponents; 249296417Sdim 250341825Sdim /// Contains thunks needed by vtables, sorted by indices. 251314564Sdim OwningArrayRef<VTableThunkTy> VTableThunks; 252234353Sdim 253341825Sdim /// Address points for all vtables. 254226586Sdim AddressPointsMapTy AddressPoints; 255226586Sdim 256226586Sdimpublic: 257314564Sdim VTableLayout(ArrayRef<size_t> VTableIndices, 258314564Sdim ArrayRef<VTableComponent> VTableComponents, 259314564Sdim ArrayRef<VTableThunkTy> VTableThunks, 260314564Sdim const AddressPointsMapTy &AddressPoints); 261226586Sdim ~VTableLayout(); 262226586Sdim 263314564Sdim ArrayRef<VTableComponent> vtable_components() const { 264314564Sdim return VTableComponents; 265226586Sdim } 266226586Sdim 267314564Sdim ArrayRef<VTableThunkTy> vtable_thunks() const { 268314564Sdim return VTableThunks; 269296417Sdim } 270296417Sdim 271314564Sdim AddressPointLocation getAddressPoint(BaseSubobject Base) const { 272314564Sdim assert(AddressPoints.count(Base) && "Did not find address point!"); 273314564Sdim return AddressPoints.find(Base)->second; 274226586Sdim } 275226586Sdim 276314564Sdim const AddressPointsMapTy &getAddressPoints() const { 277314564Sdim return AddressPoints; 278226586Sdim } 279226586Sdim 280314564Sdim size_t getNumVTables() const { 281314564Sdim if (VTableIndices.empty()) 282314564Sdim return 1; 283314564Sdim return VTableIndices.size(); 284226586Sdim } 285226586Sdim 286314564Sdim size_t getVTableOffset(size_t i) const { 287314564Sdim if (VTableIndices.empty()) { 288314564Sdim assert(i == 0); 289314564Sdim return 0; 290314564Sdim } 291314564Sdim return VTableIndices[i]; 292226586Sdim } 293226586Sdim 294314564Sdim size_t getVTableSize(size_t i) const { 295314564Sdim if (VTableIndices.empty()) { 296314564Sdim assert(i == 0); 297314564Sdim return vtable_components().size(); 298314564Sdim } 299226586Sdim 300314564Sdim size_t thisIndex = VTableIndices[i]; 301314564Sdim size_t nextIndex = (i + 1 == VTableIndices.size()) 302314564Sdim ? vtable_components().size() 303314564Sdim : VTableIndices[i + 1]; 304314564Sdim return nextIndex - thisIndex; 305226586Sdim } 306226586Sdim}; 307226586Sdim 308261991Sdimclass VTableContextBase { 309226586Sdimpublic: 310226586Sdim typedef SmallVector<ThunkInfo, 1> ThunkInfoVectorTy; 311234353Sdim 312276479Sdim bool isMicrosoft() const { return IsMicrosoftABI; } 313276479Sdim 314276479Sdim virtual ~VTableContextBase() {} 315276479Sdim 316261991Sdimprotected: 317261991Sdim typedef llvm::DenseMap<const CXXMethodDecl *, ThunkInfoVectorTy> ThunksMapTy; 318261991Sdim 319341825Sdim /// Contains all thunks that a given method decl will need. 320261991Sdim ThunksMapTy Thunks; 321261991Sdim 322261991Sdim /// Compute and store all vtable related information (vtable layout, vbase 323261991Sdim /// offset offsets, thunks etc) for the given record decl. 324261991Sdim virtual void computeVTableRelatedInformation(const CXXRecordDecl *RD) = 0; 325261991Sdim 326276479Sdim VTableContextBase(bool MS) : IsMicrosoftABI(MS) {} 327261991Sdim 328261991Sdimpublic: 329261991Sdim virtual const ThunkInfoVectorTy *getThunkInfo(GlobalDecl GD) { 330261991Sdim const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl()->getCanonicalDecl()); 331261991Sdim computeVTableRelatedInformation(MD->getParent()); 332261991Sdim 333261991Sdim // This assumes that all the destructors present in the vtable 334261991Sdim // use exactly the same set of thunks. 335261991Sdim ThunksMapTy::const_iterator I = Thunks.find(MD); 336261991Sdim if (I == Thunks.end()) { 337261991Sdim // We did not find a thunk for this method. 338276479Sdim return nullptr; 339261991Sdim } 340261991Sdim 341261991Sdim return &I->second; 342261991Sdim } 343276479Sdim 344276479Sdim bool IsMicrosoftABI; 345261991Sdim}; 346261991Sdim 347261991Sdimclass ItaniumVTableContext : public VTableContextBase { 348226586Sdimprivate: 349249423Sdim 350341825Sdim /// Contains the index (relative to the vtable address point) 351261991Sdim /// where the function pointer for a virtual function is stored. 352226586Sdim typedef llvm::DenseMap<GlobalDecl, int64_t> MethodVTableIndicesTy; 353226586Sdim MethodVTableIndicesTy MethodVTableIndices; 354226586Sdim 355314564Sdim typedef llvm::DenseMap<const CXXRecordDecl *, 356314564Sdim std::unique_ptr<const VTableLayout>> 357314564Sdim VTableLayoutMapTy; 358226586Sdim VTableLayoutMapTy VTableLayouts; 359226586Sdim 360226586Sdim typedef std::pair<const CXXRecordDecl *, 361226586Sdim const CXXRecordDecl *> ClassPairTy; 362226586Sdim 363341825Sdim /// vtable offsets for offsets of virtual bases of a class. 364261991Sdim /// 365261991Sdim /// Contains the vtable offset (relative to the address point) in chars 366261991Sdim /// where the offsets for virtual bases of a class are stored. 367234353Sdim typedef llvm::DenseMap<ClassPairTy, CharUnits> 368226586Sdim VirtualBaseClassOffsetOffsetsMapTy; 369226586Sdim VirtualBaseClassOffsetOffsetsMapTy VirtualBaseClassOffsetOffsets; 370226586Sdim 371276479Sdim void computeVTableRelatedInformation(const CXXRecordDecl *RD) override; 372234353Sdim 373226586Sdimpublic: 374261991Sdim ItaniumVTableContext(ASTContext &Context); 375288943Sdim ~ItaniumVTableContext() override; 376226586Sdim 377226586Sdim const VTableLayout &getVTableLayout(const CXXRecordDecl *RD) { 378261991Sdim computeVTableRelatedInformation(RD); 379226586Sdim assert(VTableLayouts.count(RD) && "No layout for this record decl!"); 380234353Sdim 381226586Sdim return *VTableLayouts[RD]; 382226586Sdim } 383226586Sdim 384314564Sdim std::unique_ptr<VTableLayout> createConstructionVTableLayout( 385314564Sdim const CXXRecordDecl *MostDerivedClass, CharUnits MostDerivedClassOffset, 386314564Sdim bool MostDerivedClassIsVirtual, const CXXRecordDecl *LayoutClass); 387226586Sdim 388341825Sdim /// Locate a virtual function in the vtable. 389261991Sdim /// 390261991Sdim /// Return the index (relative to the vtable address point) where the 391261991Sdim /// function pointer for the given virtual function is stored. 392261991Sdim uint64_t getMethodVTableIndex(GlobalDecl GD); 393226586Sdim 394261991Sdim /// Return the offset in chars (relative to the vtable address point) where 395261991Sdim /// the offset of the virtual base that contains the given base is stored, 396341825Sdim /// otherwise, if no virtual base contains the given class, return 0. 397261991Sdim /// 398261991Sdim /// Base must be a virtual base class or an unambiguous base. 399261991Sdim CharUnits getVirtualBaseOffsetOffset(const CXXRecordDecl *RD, 400261991Sdim const CXXRecordDecl *VBase); 401276479Sdim 402276479Sdim static bool classof(const VTableContextBase *VT) { 403276479Sdim return !VT->isMicrosoft(); 404276479Sdim } 405261991Sdim}; 406226586Sdim 407276479Sdim/// Holds information about the inheritance path to a virtual base or function 408276479Sdim/// table pointer. A record may contain as many vfptrs or vbptrs as there are 409276479Sdim/// base subobjects. 410276479Sdimstruct VPtrInfo { 411261991Sdim typedef SmallVector<const CXXRecordDecl *, 1> BasePath; 412261991Sdim 413276479Sdim VPtrInfo(const CXXRecordDecl *RD) 414314564Sdim : ObjectWithVPtr(RD), IntroducingObject(RD), NextBaseToMangle(RD) {} 415226586Sdim 416314564Sdim /// This is the most derived class that has this vptr at offset zero. When 417314564Sdim /// single inheritance is used, this is always the most derived class. If 418314564Sdim /// multiple inheritance is used, it may be any direct or indirect base. 419314564Sdim const CXXRecordDecl *ObjectWithVPtr; 420226586Sdim 421314564Sdim /// This is the class that introduced the vptr by declaring new virtual 422314564Sdim /// methods or virtual bases. 423314564Sdim const CXXRecordDecl *IntroducingObject; 424314564Sdim 425314564Sdim /// IntroducingObject is at this offset from its containing complete object or 426276479Sdim /// virtual base. 427276479Sdim CharUnits NonVirtualOffset; 428261991Sdim 429276479Sdim /// The bases from the inheritance path that got used to mangle the vbtable 430276479Sdim /// name. This is not really a full path like a CXXBasePath. It holds the 431276479Sdim /// subset of records that need to be mangled into the vbtable symbol name in 432276479Sdim /// order to get a unique name. 433276479Sdim BasePath MangledPath; 434276479Sdim 435276479Sdim /// The next base to push onto the mangled path if this path is ambiguous in a 436276479Sdim /// derived class. If it's null, then it's already been pushed onto the path. 437276479Sdim const CXXRecordDecl *NextBaseToMangle; 438276479Sdim 439276479Sdim /// The set of possibly indirect vbases that contain this vbtable. When a 440276479Sdim /// derived class indirectly inherits from the same vbase twice, we only keep 441276479Sdim /// vtables and their paths from the first instance. 442276479Sdim BasePath ContainingVBases; 443276479Sdim 444261991Sdim /// This holds the base classes path from the complete type to the first base 445276479Sdim /// with the given vfptr offset, in the base-to-derived order. Only used for 446276479Sdim /// vftables. 447314564Sdim BasePath PathToIntroducingObject; 448261991Sdim 449276479Sdim /// Static offset from the top of the most derived class to this vfptr, 450276479Sdim /// including any virtual base offset. Only used for vftables. 451276479Sdim CharUnits FullOffsetInMDC; 452261991Sdim 453276479Sdim /// The vptr is stored inside the non-virtual component of this virtual base. 454276479Sdim const CXXRecordDecl *getVBaseWithVPtr() const { 455276479Sdim return ContainingVBases.empty() ? nullptr : ContainingVBases.front(); 456276479Sdim } 457226586Sdim}; 458226586Sdim 459314564Sdimtypedef SmallVector<std::unique_ptr<VPtrInfo>, 2> VPtrInfoVector; 460276479Sdim 461276479Sdim/// All virtual base related information about a given record decl. Includes 462276479Sdim/// information on all virtual base tables and the path components that are used 463276479Sdim/// to mangle them. 464276479Sdimstruct VirtualBaseInfo { 465276479Sdim /// A map from virtual base to vbtable index for doing a conversion from the 466276479Sdim /// the derived class to the a base. 467276479Sdim llvm::DenseMap<const CXXRecordDecl *, unsigned> VBTableIndices; 468276479Sdim 469276479Sdim /// Information on all virtual base tables used when this record is the most 470276479Sdim /// derived class. 471276479Sdim VPtrInfoVector VBPtrPaths; 472276479Sdim}; 473276479Sdim 474341825Sdimstruct MethodVFTableLocation { 475341825Sdim /// If nonzero, holds the vbtable index of the virtual base with the vfptr. 476341825Sdim uint64_t VBTableIndex; 477261991Sdim 478341825Sdim /// If nonnull, holds the last vbase which contains the vfptr that the 479341825Sdim /// method definition is adjusted to. 480341825Sdim const CXXRecordDecl *VBase; 481261991Sdim 482341825Sdim /// This is the offset of the vfptr from the start of the last vbase, or the 483341825Sdim /// complete type if there are no virtual bases. 484341825Sdim CharUnits VFPtrOffset; 485261991Sdim 486341825Sdim /// Method's index in the vftable. 487341825Sdim uint64_t Index; 488261991Sdim 489341825Sdim MethodVFTableLocation() 490341825Sdim : VBTableIndex(0), VBase(nullptr), VFPtrOffset(CharUnits::Zero()), 491341825Sdim Index(0) {} 492261991Sdim 493341825Sdim MethodVFTableLocation(uint64_t VBTableIndex, const CXXRecordDecl *VBase, 494341825Sdim CharUnits VFPtrOffset, uint64_t Index) 495341825Sdim : VBTableIndex(VBTableIndex), VBase(VBase), VFPtrOffset(VFPtrOffset), 496341825Sdim Index(Index) {} 497261991Sdim 498341825Sdim bool operator<(const MethodVFTableLocation &other) const { 499341825Sdim if (VBTableIndex != other.VBTableIndex) { 500341825Sdim assert(VBase != other.VBase); 501341825Sdim return VBTableIndex < other.VBTableIndex; 502261991Sdim } 503341825Sdim return std::tie(VFPtrOffset, Index) < 504341825Sdim std::tie(other.VFPtrOffset, other.Index); 505341825Sdim } 506341825Sdim}; 507261991Sdim 508341825Sdimclass MicrosoftVTableContext : public VTableContextBase { 509341825Sdimpublic: 510341825Sdim 511261991Sdimprivate: 512261991Sdim ASTContext &Context; 513261991Sdim 514261991Sdim typedef llvm::DenseMap<GlobalDecl, MethodVFTableLocation> 515261991Sdim MethodVFTableLocationsTy; 516261991Sdim MethodVFTableLocationsTy MethodVFTableLocations; 517261991Sdim 518341825Sdim typedef llvm::DenseMap<const CXXRecordDecl *, std::unique_ptr<VPtrInfoVector>> 519314564Sdim VFPtrLocationsMapTy; 520261991Sdim VFPtrLocationsMapTy VFPtrLocations; 521261991Sdim 522261991Sdim typedef std::pair<const CXXRecordDecl *, CharUnits> VFTableIdTy; 523314564Sdim typedef llvm::DenseMap<VFTableIdTy, std::unique_ptr<const VTableLayout>> 524314564Sdim VFTableLayoutMapTy; 525261991Sdim VFTableLayoutMapTy VFTableLayouts; 526261991Sdim 527314564Sdim llvm::DenseMap<const CXXRecordDecl *, std::unique_ptr<VirtualBaseInfo>> 528314564Sdim VBaseInfo; 529261991Sdim 530276479Sdim void enumerateVFPtrs(const CXXRecordDecl *ForClass, VPtrInfoVector &Result); 531261991Sdim 532276479Sdim void computeVTableRelatedInformation(const CXXRecordDecl *RD) override; 533261991Sdim 534261991Sdim void dumpMethodLocations(const CXXRecordDecl *RD, 535261991Sdim const MethodVFTableLocationsTy &NewMethods, 536261991Sdim raw_ostream &); 537261991Sdim 538314564Sdim const VirtualBaseInfo & 539276479Sdim computeVBTableRelatedInformation(const CXXRecordDecl *RD); 540261991Sdim 541276479Sdim void computeVTablePaths(bool ForVBTables, const CXXRecordDecl *RD, 542276479Sdim VPtrInfoVector &Paths); 543261991Sdim 544261991Sdimpublic: 545276479Sdim MicrosoftVTableContext(ASTContext &Context) 546276479Sdim : VTableContextBase(/*MS=*/true), Context(Context) {} 547261991Sdim 548288943Sdim ~MicrosoftVTableContext() override; 549261991Sdim 550276479Sdim const VPtrInfoVector &getVFPtrOffsets(const CXXRecordDecl *RD); 551261991Sdim 552261991Sdim const VTableLayout &getVFTableLayout(const CXXRecordDecl *RD, 553261991Sdim CharUnits VFPtrOffset); 554261991Sdim 555341825Sdim MethodVFTableLocation getMethodVFTableLocation(GlobalDecl GD); 556261991Sdim 557276479Sdim const ThunkInfoVectorTy *getThunkInfo(GlobalDecl GD) override { 558261991Sdim // Complete destructors don't have a slot in a vftable, so no thunks needed. 559261991Sdim if (isa<CXXDestructorDecl>(GD.getDecl()) && 560261991Sdim GD.getDtorType() == Dtor_Complete) 561276479Sdim return nullptr; 562261991Sdim return VTableContextBase::getThunkInfo(GD); 563261991Sdim } 564261991Sdim 565341825Sdim /// Returns the index of VBase in the vbtable of Derived. 566261991Sdim /// VBase must be a morally virtual base of Derived. 567261991Sdim /// The vbtable is an array of i32 offsets. The first entry is a self entry, 568261991Sdim /// and the rest are offsets from the vbptr to virtual bases. 569261991Sdim unsigned getVBTableIndex(const CXXRecordDecl *Derived, 570276479Sdim const CXXRecordDecl *VBase); 571276479Sdim 572276479Sdim const VPtrInfoVector &enumerateVBTables(const CXXRecordDecl *RD); 573276479Sdim 574276479Sdim static bool classof(const VTableContextBase *VT) { return VT->isMicrosoft(); } 575261991Sdim}; 576226586Sdim 577276479Sdim} // namespace clang 578276479Sdim 579226586Sdim#endif 580