VTableBuilder.h revision 263508
1//===--- VTableBuilder.h - C++ vtable layout builder --------------*- C++ -*-=// 2// 3// The LLVM Compiler Infrastructure 4// 5// This file is distributed under the University of Illinois Open Source 6// License. See LICENSE.TXT for details. 7// 8//===----------------------------------------------------------------------===// 9// 10// This contains code dealing with generation of the layout of virtual tables. 11// 12//===----------------------------------------------------------------------===// 13 14#ifndef LLVM_CLANG_AST_VTABLEBUILDER_H 15#define LLVM_CLANG_AST_VTABLEBUILDER_H 16 17#include "clang/AST/BaseSubobject.h" 18#include "clang/AST/CXXInheritance.h" 19#include "clang/AST/GlobalDecl.h" 20#include "clang/AST/RecordLayout.h" 21#include "clang/Basic/ABI.h" 22#include "llvm/ADT/SetVector.h" 23#include "llvm/ADT/DenseSet.h" 24#include <utility> 25 26namespace clang { 27 class CXXRecordDecl; 28 29/// \brief Represents a single component in a vtable. 30class VTableComponent { 31public: 32 enum Kind { 33 CK_VCallOffset, 34 CK_VBaseOffset, 35 CK_OffsetToTop, 36 CK_RTTI, 37 CK_FunctionPointer, 38 39 /// \brief A pointer to the complete destructor. 40 CK_CompleteDtorPointer, 41 42 /// \brief A pointer to the deleting destructor. 43 CK_DeletingDtorPointer, 44 45 /// \brief An entry that is never used. 46 /// 47 /// In some cases, a vtable function pointer will end up never being 48 /// called. Such vtable function pointers are represented as a 49 /// CK_UnusedFunctionPointer. 50 CK_UnusedFunctionPointer 51 }; 52 53 VTableComponent() { } 54 55 static VTableComponent MakeVCallOffset(CharUnits Offset) { 56 return VTableComponent(CK_VCallOffset, Offset); 57 } 58 59 static VTableComponent MakeVBaseOffset(CharUnits Offset) { 60 return VTableComponent(CK_VBaseOffset, Offset); 61 } 62 63 static VTableComponent MakeOffsetToTop(CharUnits Offset) { 64 return VTableComponent(CK_OffsetToTop, Offset); 65 } 66 67 static VTableComponent MakeRTTI(const CXXRecordDecl *RD) { 68 return VTableComponent(CK_RTTI, reinterpret_cast<uintptr_t>(RD)); 69 } 70 71 static VTableComponent MakeFunction(const CXXMethodDecl *MD) { 72 assert(!isa<CXXDestructorDecl>(MD) && 73 "Don't use MakeFunction with destructors!"); 74 75 return VTableComponent(CK_FunctionPointer, 76 reinterpret_cast<uintptr_t>(MD)); 77 } 78 79 static VTableComponent MakeCompleteDtor(const CXXDestructorDecl *DD) { 80 return VTableComponent(CK_CompleteDtorPointer, 81 reinterpret_cast<uintptr_t>(DD)); 82 } 83 84 static VTableComponent MakeDeletingDtor(const CXXDestructorDecl *DD) { 85 return VTableComponent(CK_DeletingDtorPointer, 86 reinterpret_cast<uintptr_t>(DD)); 87 } 88 89 static VTableComponent MakeUnusedFunction(const CXXMethodDecl *MD) { 90 assert(!isa<CXXDestructorDecl>(MD) && 91 "Don't use MakeUnusedFunction with destructors!"); 92 return VTableComponent(CK_UnusedFunctionPointer, 93 reinterpret_cast<uintptr_t>(MD)); 94 } 95 96 static VTableComponent getFromOpaqueInteger(uint64_t I) { 97 return VTableComponent(I); 98 } 99 100 /// \brief Get the kind of this vtable component. 101 Kind getKind() const { 102 return (Kind)(Value & 0x7); 103 } 104 105 CharUnits getVCallOffset() const { 106 assert(getKind() == CK_VCallOffset && "Invalid component kind!"); 107 108 return getOffset(); 109 } 110 111 CharUnits getVBaseOffset() const { 112 assert(getKind() == CK_VBaseOffset && "Invalid component kind!"); 113 114 return getOffset(); 115 } 116 117 CharUnits getOffsetToTop() const { 118 assert(getKind() == CK_OffsetToTop && "Invalid component kind!"); 119 120 return getOffset(); 121 } 122 123 const CXXRecordDecl *getRTTIDecl() const { 124 assert(getKind() == CK_RTTI && "Invalid component kind!"); 125 126 return reinterpret_cast<CXXRecordDecl *>(getPointer()); 127 } 128 129 const CXXMethodDecl *getFunctionDecl() const { 130 assert(getKind() == CK_FunctionPointer); 131 132 return reinterpret_cast<CXXMethodDecl *>(getPointer()); 133 } 134 135 const CXXDestructorDecl *getDestructorDecl() const { 136 assert((getKind() == CK_CompleteDtorPointer || 137 getKind() == CK_DeletingDtorPointer) && "Invalid component kind!"); 138 139 return reinterpret_cast<CXXDestructorDecl *>(getPointer()); 140 } 141 142 const CXXMethodDecl *getUnusedFunctionDecl() const { 143 assert(getKind() == CK_UnusedFunctionPointer); 144 145 return reinterpret_cast<CXXMethodDecl *>(getPointer()); 146 } 147 148private: 149 VTableComponent(Kind ComponentKind, CharUnits Offset) { 150 assert((ComponentKind == CK_VCallOffset || 151 ComponentKind == CK_VBaseOffset || 152 ComponentKind == CK_OffsetToTop) && "Invalid component kind!"); 153 assert(Offset.getQuantity() < (1LL << 56) && "Offset is too big!"); 154 assert(Offset.getQuantity() >= -(1LL << 56) && "Offset is too small!"); 155 156 Value = (uint64_t(Offset.getQuantity()) << 3) | ComponentKind; 157 } 158 159 VTableComponent(Kind ComponentKind, uintptr_t Ptr) { 160 assert((ComponentKind == CK_RTTI || 161 ComponentKind == CK_FunctionPointer || 162 ComponentKind == CK_CompleteDtorPointer || 163 ComponentKind == CK_DeletingDtorPointer || 164 ComponentKind == CK_UnusedFunctionPointer) && 165 "Invalid component kind!"); 166 167 assert((Ptr & 7) == 0 && "Pointer not sufficiently aligned!"); 168 169 Value = Ptr | ComponentKind; 170 } 171 172 CharUnits getOffset() const { 173 assert((getKind() == CK_VCallOffset || getKind() == CK_VBaseOffset || 174 getKind() == CK_OffsetToTop) && "Invalid component kind!"); 175 176 return CharUnits::fromQuantity(Value >> 3); 177 } 178 179 uintptr_t getPointer() const { 180 assert((getKind() == CK_RTTI || 181 getKind() == CK_FunctionPointer || 182 getKind() == CK_CompleteDtorPointer || 183 getKind() == CK_DeletingDtorPointer || 184 getKind() == CK_UnusedFunctionPointer) && 185 "Invalid component kind!"); 186 187 return static_cast<uintptr_t>(Value & ~7ULL); 188 } 189 190 explicit VTableComponent(uint64_t Value) 191 : Value(Value) { } 192 193 /// The kind is stored in the lower 3 bits of the value. For offsets, we 194 /// make use of the facts that classes can't be larger than 2^55 bytes, 195 /// so we store the offset in the lower part of the 61 bits that remain. 196 /// (The reason that we're not simply using a PointerIntPair here is that we 197 /// need the offsets to be 64-bit, even when on a 32-bit machine). 198 int64_t Value; 199}; 200 201class VTableLayout { 202public: 203 typedef std::pair<uint64_t, ThunkInfo> VTableThunkTy; 204 205 typedef const VTableComponent *vtable_component_iterator; 206 typedef const VTableThunkTy *vtable_thunk_iterator; 207 208 typedef llvm::DenseMap<BaseSubobject, uint64_t> AddressPointsMapTy; 209private: 210 uint64_t NumVTableComponents; 211 llvm::OwningArrayPtr<VTableComponent> VTableComponents; 212 213 /// \brief Contains thunks needed by vtables, sorted by indices. 214 uint64_t NumVTableThunks; 215 llvm::OwningArrayPtr<VTableThunkTy> VTableThunks; 216 217 /// \brief Address points for all vtables. 218 AddressPointsMapTy AddressPoints; 219 220 bool IsMicrosoftABI; 221 222public: 223 VTableLayout(uint64_t NumVTableComponents, 224 const VTableComponent *VTableComponents, 225 uint64_t NumVTableThunks, 226 const VTableThunkTy *VTableThunks, 227 const AddressPointsMapTy &AddressPoints, 228 bool IsMicrosoftABI); 229 ~VTableLayout(); 230 231 uint64_t getNumVTableComponents() const { 232 return NumVTableComponents; 233 } 234 235 vtable_component_iterator vtable_component_begin() const { 236 return VTableComponents.get(); 237 } 238 239 vtable_component_iterator vtable_component_end() const { 240 return VTableComponents.get() + NumVTableComponents; 241 } 242 243 uint64_t getNumVTableThunks() const { return NumVTableThunks; } 244 245 vtable_thunk_iterator vtable_thunk_begin() const { 246 return VTableThunks.get(); 247 } 248 249 vtable_thunk_iterator vtable_thunk_end() const { 250 return VTableThunks.get() + NumVTableThunks; 251 } 252 253 uint64_t getAddressPoint(BaseSubobject Base) const { 254 assert(AddressPoints.count(Base) && 255 "Did not find address point!"); 256 257 uint64_t AddressPoint = AddressPoints.lookup(Base); 258 assert(AddressPoint != 0 || IsMicrosoftABI); 259 (void)IsMicrosoftABI; 260 261 return AddressPoint; 262 } 263 264 const AddressPointsMapTy &getAddressPoints() const { 265 return AddressPoints; 266 } 267}; 268 269class VTableContextBase { 270public: 271 typedef SmallVector<ThunkInfo, 1> ThunkInfoVectorTy; 272 273protected: 274 typedef llvm::DenseMap<const CXXMethodDecl *, ThunkInfoVectorTy> ThunksMapTy; 275 276 /// \brief Contains all thunks that a given method decl will need. 277 ThunksMapTy Thunks; 278 279 /// Compute and store all vtable related information (vtable layout, vbase 280 /// offset offsets, thunks etc) for the given record decl. 281 virtual void computeVTableRelatedInformation(const CXXRecordDecl *RD) = 0; 282 283 virtual ~VTableContextBase() {} 284 285public: 286 virtual const ThunkInfoVectorTy *getThunkInfo(GlobalDecl GD) { 287 const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl()->getCanonicalDecl()); 288 computeVTableRelatedInformation(MD->getParent()); 289 290 // This assumes that all the destructors present in the vtable 291 // use exactly the same set of thunks. 292 ThunksMapTy::const_iterator I = Thunks.find(MD); 293 if (I == Thunks.end()) { 294 // We did not find a thunk for this method. 295 return 0; 296 } 297 298 return &I->second; 299 } 300}; 301 302class ItaniumVTableContext : public VTableContextBase { 303private: 304 bool IsMicrosoftABI; 305 306 /// \brief Contains the index (relative to the vtable address point) 307 /// where the function pointer for a virtual function is stored. 308 typedef llvm::DenseMap<GlobalDecl, int64_t> MethodVTableIndicesTy; 309 MethodVTableIndicesTy MethodVTableIndices; 310 311 typedef llvm::DenseMap<const CXXRecordDecl *, const VTableLayout *> 312 VTableLayoutMapTy; 313 VTableLayoutMapTy VTableLayouts; 314 315 typedef std::pair<const CXXRecordDecl *, 316 const CXXRecordDecl *> ClassPairTy; 317 318 /// \brief vtable offsets for offsets of virtual bases of a class. 319 /// 320 /// Contains the vtable offset (relative to the address point) in chars 321 /// where the offsets for virtual bases of a class are stored. 322 typedef llvm::DenseMap<ClassPairTy, CharUnits> 323 VirtualBaseClassOffsetOffsetsMapTy; 324 VirtualBaseClassOffsetOffsetsMapTy VirtualBaseClassOffsetOffsets; 325 326 void computeVTableRelatedInformation(const CXXRecordDecl *RD); 327 328public: 329 ItaniumVTableContext(ASTContext &Context); 330 ~ItaniumVTableContext(); 331 332 const VTableLayout &getVTableLayout(const CXXRecordDecl *RD) { 333 computeVTableRelatedInformation(RD); 334 assert(VTableLayouts.count(RD) && "No layout for this record decl!"); 335 336 return *VTableLayouts[RD]; 337 } 338 339 VTableLayout * 340 createConstructionVTableLayout(const CXXRecordDecl *MostDerivedClass, 341 CharUnits MostDerivedClassOffset, 342 bool MostDerivedClassIsVirtual, 343 const CXXRecordDecl *LayoutClass); 344 345 /// \brief Locate a virtual function in the vtable. 346 /// 347 /// Return the index (relative to the vtable address point) where the 348 /// function pointer for the given virtual function is stored. 349 uint64_t getMethodVTableIndex(GlobalDecl GD); 350 351 /// Return the offset in chars (relative to the vtable address point) where 352 /// the offset of the virtual base that contains the given base is stored, 353 /// otherwise, if no virtual base contains the given class, return 0. 354 /// 355 /// Base must be a virtual base class or an unambiguous base. 356 CharUnits getVirtualBaseOffsetOffset(const CXXRecordDecl *RD, 357 const CXXRecordDecl *VBase); 358}; 359 360struct VFPtrInfo { 361 typedef SmallVector<const CXXRecordDecl *, 1> BasePath; 362 363 // Don't pass the PathToMangle as it should be calculated later. 364 VFPtrInfo(CharUnits VFPtrOffset, const BasePath &PathToBaseWithVFPtr) 365 : VBTableIndex(0), LastVBase(0), VFPtrOffset(VFPtrOffset), 366 PathToBaseWithVFPtr(PathToBaseWithVFPtr), VFPtrFullOffset(VFPtrOffset) { 367 } 368 369 // Don't pass the PathToMangle as it should be calculated later. 370 VFPtrInfo(uint64_t VBTableIndex, const CXXRecordDecl *LastVBase, 371 CharUnits VFPtrOffset, const BasePath &PathToBaseWithVFPtr, 372 CharUnits VFPtrFullOffset) 373 : VBTableIndex(VBTableIndex), LastVBase(LastVBase), 374 VFPtrOffset(VFPtrOffset), PathToBaseWithVFPtr(PathToBaseWithVFPtr), 375 VFPtrFullOffset(VFPtrFullOffset) { 376 assert(VBTableIndex && "The full constructor should only be used " 377 "for vfptrs in virtual bases"); 378 assert(LastVBase); 379 } 380 381 /// If nonzero, holds the vbtable index of the virtual base with the vfptr. 382 uint64_t VBTableIndex; 383 384 /// Stores the last vbase on the path from the complete type to the vfptr. 385 const CXXRecordDecl *LastVBase; 386 387 /// This is the offset of the vfptr from the start of the last vbase, 388 /// or the complete type if there are no virtual bases. 389 CharUnits VFPtrOffset; 390 391 /// This holds the base classes path from the complete type to the first base 392 /// with the given vfptr offset, in the base-to-derived order. 393 BasePath PathToBaseWithVFPtr; 394 395 /// This holds the subset of records that need to be mangled into the vftable 396 /// symbol name in order to get a unique name, in the derived-to-base order. 397 BasePath PathToMangle; 398 399 /// This is the full offset of the vfptr from the start of the complete type. 400 CharUnits VFPtrFullOffset; 401}; 402 403class MicrosoftVTableContext : public VTableContextBase { 404public: 405 struct MethodVFTableLocation { 406 /// If nonzero, holds the vbtable index of the virtual base with the vfptr. 407 uint64_t VBTableIndex; 408 409 /// If nonnull, holds the last vbase which contains the vfptr that the 410 /// method definition is adjusted to. 411 const CXXRecordDecl *VBase; 412 413 /// This is the offset of the vfptr from the start of the last vbase, or the 414 /// complete type if there are no virtual bases. 415 CharUnits VFPtrOffset; 416 417 /// Method's index in the vftable. 418 uint64_t Index; 419 420 MethodVFTableLocation() 421 : VBTableIndex(0), VBase(0), VFPtrOffset(CharUnits::Zero()), 422 Index(0) {} 423 424 MethodVFTableLocation(uint64_t VBTableIndex, const CXXRecordDecl *VBase, 425 CharUnits VFPtrOffset, uint64_t Index) 426 : VBTableIndex(VBTableIndex), VBase(VBase), 427 VFPtrOffset(VFPtrOffset), Index(Index) {} 428 429 bool operator<(const MethodVFTableLocation &other) const { 430 if (VBTableIndex != other.VBTableIndex) { 431 assert(VBase != other.VBase); 432 return VBTableIndex < other.VBTableIndex; 433 } 434 if (VFPtrOffset != other.VFPtrOffset) 435 return VFPtrOffset < other.VFPtrOffset; 436 if (Index != other.Index) 437 return Index < other.Index; 438 return false; 439 } 440 }; 441 442 typedef SmallVector<VFPtrInfo, 1> VFPtrListTy; 443 444private: 445 ASTContext &Context; 446 447 typedef llvm::DenseMap<GlobalDecl, MethodVFTableLocation> 448 MethodVFTableLocationsTy; 449 MethodVFTableLocationsTy MethodVFTableLocations; 450 451 typedef llvm::DenseMap<const CXXRecordDecl *, VFPtrListTy> 452 VFPtrLocationsMapTy; 453 VFPtrLocationsMapTy VFPtrLocations; 454 455 typedef std::pair<const CXXRecordDecl *, CharUnits> VFTableIdTy; 456 typedef llvm::DenseMap<VFTableIdTy, const VTableLayout *> VFTableLayoutMapTy; 457 VFTableLayoutMapTy VFTableLayouts; 458 459 typedef llvm::SmallSetVector<const CXXRecordDecl *, 8> BasesSetVectorTy; 460 void enumerateVFPtrs(const CXXRecordDecl *MostDerivedClass, 461 const ASTRecordLayout &MostDerivedClassLayout, 462 BaseSubobject Base, const CXXRecordDecl *LastVBase, 463 const VFPtrInfo::BasePath &PathFromCompleteClass, 464 BasesSetVectorTy &VisitedVBases, 465 MicrosoftVTableContext::VFPtrListTy &Result); 466 467 void enumerateVFPtrs(const CXXRecordDecl *ForClass, 468 MicrosoftVTableContext::VFPtrListTy &Result); 469 470 void computeVTableRelatedInformation(const CXXRecordDecl *RD); 471 472 void dumpMethodLocations(const CXXRecordDecl *RD, 473 const MethodVFTableLocationsTy &NewMethods, 474 raw_ostream &); 475 476 typedef std::pair<const CXXRecordDecl *, const CXXRecordDecl *> ClassPairTy; 477 typedef llvm::DenseMap<ClassPairTy, unsigned> VBTableIndicesTy; 478 VBTableIndicesTy VBTableIndices; 479 llvm::DenseSet<const CXXRecordDecl *> ComputedVBTableIndices; 480 481 void computeVBTableRelatedInformation(const CXXRecordDecl *RD); 482 483public: 484 MicrosoftVTableContext(ASTContext &Context) : Context(Context) {} 485 486 ~MicrosoftVTableContext() { llvm::DeleteContainerSeconds(VFTableLayouts); } 487 488 const VFPtrListTy &getVFPtrOffsets(const CXXRecordDecl *RD); 489 490 const VTableLayout &getVFTableLayout(const CXXRecordDecl *RD, 491 CharUnits VFPtrOffset); 492 493 const MethodVFTableLocation &getMethodVFTableLocation(GlobalDecl GD); 494 495 const ThunkInfoVectorTy *getThunkInfo(GlobalDecl GD) { 496 // Complete destructors don't have a slot in a vftable, so no thunks needed. 497 if (isa<CXXDestructorDecl>(GD.getDecl()) && 498 GD.getDtorType() == Dtor_Complete) 499 return 0; 500 return VTableContextBase::getThunkInfo(GD); 501 } 502 503 /// \brief Returns the index of VBase in the vbtable of Derived. 504 /// VBase must be a morally virtual base of Derived. 505 /// The vbtable is an array of i32 offsets. The first entry is a self entry, 506 /// and the rest are offsets from the vbptr to virtual bases. 507 unsigned getVBTableIndex(const CXXRecordDecl *Derived, 508 const CXXRecordDecl *VBase) { 509 computeVBTableRelatedInformation(Derived); 510 ClassPairTy Pair(Derived, VBase); 511 assert(VBTableIndices.count(Pair) == 1 && 512 "VBase must be a vbase of Derived"); 513 return VBTableIndices[Pair]; 514 } 515}; 516} 517 518#endif 519