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 <utility> 24 25 namespace clang { 26 class CXXRecordDecl; 27 28 /// \brief Represents a single component in a vtable. 29 class VTableComponent { 30 public: 31 enum Kind { 32 CK_VCallOffset, 33 CK_VBaseOffset, 34 CK_OffsetToTop, 35 CK_RTTI, 36 CK_FunctionPointer, 37 38 /// \brief A pointer to the complete destructor. 39 CK_CompleteDtorPointer, 40 41 /// \brief A pointer to the deleting destructor. 42 CK_DeletingDtorPointer, 43 44 /// \brief An entry that is never used. 45 /// 46 /// In some cases, a vtable function pointer will end up never being 47 /// called. Such vtable function pointers are represented as a 48 /// CK_UnusedFunctionPointer. 49 CK_UnusedFunctionPointer 50 }; 51 52 VTableComponent() { } 53 54 static VTableComponent MakeVCallOffset(CharUnits Offset) { 55 return VTableComponent(CK_VCallOffset, Offset); 56 } 57 58 static VTableComponent MakeVBaseOffset(CharUnits Offset) { 59 return VTableComponent(CK_VBaseOffset, Offset); 60 } 61 62 static VTableComponent MakeOffsetToTop(CharUnits Offset) { 63 return VTableComponent(CK_OffsetToTop, Offset); 64 } 65 66 static VTableComponent MakeRTTI(const CXXRecordDecl *RD) { 67 return VTableComponent(CK_RTTI, reinterpret_cast<uintptr_t>(RD)); 68 } 69 70 static VTableComponent MakeFunction(const CXXMethodDecl *MD) { 71 assert(!isa<CXXDestructorDecl>(MD) && 72 "Don't use MakeFunction with destructors!"); 73 74 return VTableComponent(CK_FunctionPointer, 75 reinterpret_cast<uintptr_t>(MD)); 76 } 77 78 static VTableComponent MakeCompleteDtor(const CXXDestructorDecl *DD) { 79 return VTableComponent(CK_CompleteDtorPointer, 80 reinterpret_cast<uintptr_t>(DD)); 81 } 82 83 static VTableComponent MakeDeletingDtor(const CXXDestructorDecl *DD) { 84 return VTableComponent(CK_DeletingDtorPointer, 85 reinterpret_cast<uintptr_t>(DD)); 86 } 87 88 static VTableComponent MakeUnusedFunction(const CXXMethodDecl *MD) { 89 assert(!isa<CXXDestructorDecl>(MD) && 90 "Don't use MakeUnusedFunction with destructors!"); 91 return VTableComponent(CK_UnusedFunctionPointer, 92 reinterpret_cast<uintptr_t>(MD)); 93 } 94 95 static VTableComponent getFromOpaqueInteger(uint64_t I) { 96 return VTableComponent(I); 97 } 98 99 /// \brief Get the kind of this vtable component. 100 Kind getKind() const { 101 return (Kind)(Value & 0x7); 102 } 103 104 CharUnits getVCallOffset() const { 105 assert(getKind() == CK_VCallOffset && "Invalid component kind!"); 106 107 return getOffset(); 108 } 109 110 CharUnits getVBaseOffset() const { 111 assert(getKind() == CK_VBaseOffset && "Invalid component kind!"); 112 113 return getOffset(); 114 } 115 116 CharUnits getOffsetToTop() const { 117 assert(getKind() == CK_OffsetToTop && "Invalid component kind!"); 118 119 return getOffset(); 120 } 121 122 const CXXRecordDecl *getRTTIDecl() const { 123 assert(getKind() == CK_RTTI && "Invalid component kind!"); 124 125 return reinterpret_cast<CXXRecordDecl *>(getPointer()); 126 } 127 128 const CXXMethodDecl *getFunctionDecl() const { 129 assert(getKind() == CK_FunctionPointer); 130 131 return reinterpret_cast<CXXMethodDecl *>(getPointer()); 132 } 133 134 const CXXDestructorDecl *getDestructorDecl() const { 135 assert((getKind() == CK_CompleteDtorPointer || 136 getKind() == CK_DeletingDtorPointer) && "Invalid component kind!"); 137 138 return reinterpret_cast<CXXDestructorDecl *>(getPointer()); 139 } 140 141 const CXXMethodDecl *getUnusedFunctionDecl() const { 142 assert(getKind() == CK_UnusedFunctionPointer); 143 144 return reinterpret_cast<CXXMethodDecl *>(getPointer()); 145 } 146 147 private: 148 VTableComponent(Kind ComponentKind, CharUnits Offset) { 149 assert((ComponentKind == CK_VCallOffset || 150 ComponentKind == CK_VBaseOffset || 151 ComponentKind == CK_OffsetToTop) && "Invalid component kind!"); 152 assert(Offset.getQuantity() < (1LL << 56) && "Offset is too big!"); 153 assert(Offset.getQuantity() >= -(1LL << 56) && "Offset is too small!"); 154 155 Value = (uint64_t(Offset.getQuantity()) << 3) | ComponentKind; 156 } 157 158 VTableComponent(Kind ComponentKind, uintptr_t Ptr) { 159 assert((ComponentKind == CK_RTTI || 160 ComponentKind == CK_FunctionPointer || 161 ComponentKind == CK_CompleteDtorPointer || 162 ComponentKind == CK_DeletingDtorPointer || 163 ComponentKind == CK_UnusedFunctionPointer) && 164 "Invalid component kind!"); 165 166 assert((Ptr & 7) == 0 && "Pointer not sufficiently aligned!"); 167 168 Value = Ptr | ComponentKind; 169 } 170 171 CharUnits getOffset() const { 172 assert((getKind() == CK_VCallOffset || getKind() == CK_VBaseOffset || 173 getKind() == CK_OffsetToTop) && "Invalid component kind!"); 174 175 return CharUnits::fromQuantity(Value >> 3); 176 } 177 178 uintptr_t getPointer() const { 179 assert((getKind() == CK_RTTI || 180 getKind() == CK_FunctionPointer || 181 getKind() == CK_CompleteDtorPointer || 182 getKind() == CK_DeletingDtorPointer || 183 getKind() == CK_UnusedFunctionPointer) && 184 "Invalid component kind!"); 185 186 return static_cast<uintptr_t>(Value & ~7ULL); 187 } 188 189 explicit VTableComponent(uint64_t Value) 190 : Value(Value) { } 191 192 /// The kind is stored in the lower 3 bits of the value. For offsets, we 193 /// make use of the facts that classes can't be larger than 2^55 bytes, 194 /// so we store the offset in the lower part of the 61 bits that remain. 195 /// (The reason that we're not simply using a PointerIntPair here is that we 196 /// need the offsets to be 64-bit, even when on a 32-bit machine). 197 int64_t Value; 198 }; 199 200 class VTableLayout { 201 public: 202 typedef std::pair<uint64_t, ThunkInfo> VTableThunkTy; 203 typedef SmallVector<ThunkInfo, 1> ThunkInfoVectorTy; 204 205 typedef const VTableComponent *vtable_component_iterator; 206 typedef const VTableThunkTy *vtable_thunk_iterator; 207 208 typedef llvm::DenseMap<BaseSubobject, uint64_t> AddressPointsMapTy; 209 private: 210 uint64_t NumVTableComponents; 211 llvm::OwningArrayPtr<VTableComponent> VTableComponents; 212 213 /// \brief Contains thunks needed by vtables. 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 222 public: 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 { 244 return NumVTableThunks; 245 } 246 247 vtable_thunk_iterator vtable_thunk_begin() const { 248 return VTableThunks.get(); 249 } 250 251 vtable_thunk_iterator vtable_thunk_end() const { 252 return VTableThunks.get()+NumVTableThunks; 253 } 254 255 uint64_t getAddressPoint(BaseSubobject Base) const { 256 assert(AddressPoints.count(Base) && 257 "Did not find address point!"); 258 259 uint64_t AddressPoint = AddressPoints.lookup(Base); 260 assert(AddressPoint != 0 || IsMicrosoftABI); 261 (void)IsMicrosoftABI; 262 263 return AddressPoint; 264 } 265 266 const AddressPointsMapTy &getAddressPoints() const { 267 return AddressPoints; 268 } 269 }; 270 271 class VTableContextBase { 272 public: 273 typedef SmallVector<ThunkInfo, 1> ThunkInfoVectorTy; 274 275 protected: 276 typedef llvm::DenseMap<const CXXMethodDecl *, ThunkInfoVectorTy> ThunksMapTy; 277 278 /// \brief Contains all thunks that a given method decl will need. 279 ThunksMapTy Thunks; 280 281 /// Compute and store all vtable related information (vtable layout, vbase 282 /// offset offsets, thunks etc) for the given record decl. 283 virtual void computeVTableRelatedInformation(const CXXRecordDecl *RD) = 0; 284 285 virtual ~VTableContextBase() {} 286 287 public: 288 const ThunkInfoVectorTy *getThunkInfo(const CXXMethodDecl *MD) { 289 computeVTableRelatedInformation(MD->getParent()); 290 291 ThunksMapTy::const_iterator I = Thunks.find(MD); 292 if (I == Thunks.end()) { 293 // We did not find a thunk for this method. 294 return 0; 295 } 296 297 return &I->second; 298 } 299 }; 300 301 // FIXME: rename to ItaniumVTableContext. 302 class VTableContext : public VTableContextBase { 303 private: 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 328 public: 329 VTableContext(ASTContext &Context); 330 ~VTableContext(); 331 332 bool isMicrosoftABI() const { 333 // FIXME: Currently, this method is only used in the VTableContext and 334 // VTableBuilder code which is ABI-specific. Probably we can remove it 335 // when we add a layer of abstraction for vtable generation. 336 return IsMicrosoftABI; 337 } 338 339 const VTableLayout &getVTableLayout(const CXXRecordDecl *RD) { 340 computeVTableRelatedInformation(RD); 341 assert(VTableLayouts.count(RD) && "No layout for this record decl!"); 342 343 return *VTableLayouts[RD]; 344 } 345 346 VTableLayout * 347 createConstructionVTableLayout(const CXXRecordDecl *MostDerivedClass, 348 CharUnits MostDerivedClassOffset, 349 bool MostDerivedClassIsVirtual, 350 const CXXRecordDecl *LayoutClass); 351 352 /// \brief Locate a virtual function in the vtable. 353 /// 354 /// Return the index (relative to the vtable address point) where the 355 /// function pointer for the given virtual function is stored. 356 uint64_t getMethodVTableIndex(GlobalDecl GD); 357 358 /// Return the offset in chars (relative to the vtable address point) where 359 /// the offset of the virtual base that contains the given base is stored, 360 /// otherwise, if no virtual base contains the given class, return 0. 361 /// 362 /// Base must be a virtual base class or an unambiguous base. 363 CharUnits getVirtualBaseOffsetOffset(const CXXRecordDecl *RD, 364 const CXXRecordDecl *VBase); 365 }; 366 367 /// \brief Computes the index of VBase in the vbtable of Derived. 368 /// VBase must be a morally virtual base of Derived. The vbtable is 369 /// an array of i32 offsets. The first entry is a self entry, and the rest are 370 /// offsets from the vbptr to virtual bases. The bases are ordered the same way 371 /// our vbases are ordered: as they appear in a left-to-right depth-first search 372 /// of the hierarchy. 373 // FIXME: make this a static method of VBTableBuilder when we move it to AST. 374 unsigned GetVBTableIndex(const CXXRecordDecl *Derived, 375 const CXXRecordDecl *VBase); 376 377 struct VFPtrInfo { 378 typedef SmallVector<const CXXRecordDecl *, 1> BasePath; 379 380 VFPtrInfo(CharUnits VFPtrOffset, const BasePath &PathToBaseWithVFPtr) 381 : VBTableIndex(0), LastVBase(0), VFPtrOffset(VFPtrOffset), 382 PathToBaseWithVFPtr(PathToBaseWithVFPtr), VFPtrFullOffset(VFPtrOffset) { 383 } 384 385 VFPtrInfo(uint64_t VBTableIndex, const CXXRecordDecl *LastVBase, 386 CharUnits VFPtrOffset, const BasePath &PathToBaseWithVFPtr, 387 CharUnits VFPtrFullOffset) 388 : VBTableIndex(VBTableIndex), LastVBase(LastVBase), 389 VFPtrOffset(VFPtrOffset), PathToBaseWithVFPtr(PathToBaseWithVFPtr), 390 VFPtrFullOffset(VFPtrFullOffset) { 391 assert(VBTableIndex && "The full constructor should only be used " 392 "for vfptrs in virtual bases"); 393 assert(LastVBase); 394 } 395 396 /// If nonzero, holds the vbtable index of the virtual base with the vfptr. 397 uint64_t VBTableIndex; 398 399 /// Stores the last vbase on the path from the complete type to the vfptr. 400 const CXXRecordDecl *LastVBase; 401 402 /// This is the offset of the vfptr from the start of the last vbase, 403 /// or the complete type if there are no virtual bases. 404 CharUnits VFPtrOffset; 405 406 /// This holds the base classes path from the complete type to the first base 407 /// with the given vfptr offset. 408 BasePath PathToBaseWithVFPtr; 409 410 /// This is the full offset of the vfptr from the start of the complete type. 411 CharUnits VFPtrFullOffset; 412 }; 413 414 class MicrosoftVFTableContext : public VTableContextBase { 415 public: 416 struct MethodVFTableLocation { 417 /// If nonzero, holds the vbtable index of the virtual base with the vfptr. 418 uint64_t VBTableIndex; 419 420 /// This is the offset of the vfptr from the start of the last vbase, or the 421 /// complete type if there are no virtual bases. 422 CharUnits VFTableOffset; 423 424 /// Method's index in the vftable. 425 uint64_t Index; 426 427 MethodVFTableLocation() 428 : VBTableIndex(0), VFTableOffset(CharUnits::Zero()), Index(0) {} 429 430 MethodVFTableLocation(uint64_t VBTableIndex, CharUnits VFTableOffset, 431 uint64_t Index) 432 : VBTableIndex(VBTableIndex), VFTableOffset(VFTableOffset), 433 Index(Index) {} 434 435 bool operator<(const MethodVFTableLocation &other) const { 436 if (VBTableIndex != other.VBTableIndex) 437 return VBTableIndex < other.VBTableIndex; 438 if (VFTableOffset != other.VFTableOffset) 439 return VFTableOffset < other.VFTableOffset; 440 return Index < other.Index; 441 } 442 }; 443 444 typedef SmallVector<VFPtrInfo, 1> VFPtrListTy; 445 446 private: 447 ASTContext &Context; 448 449 typedef llvm::DenseMap<GlobalDecl, MethodVFTableLocation> 450 MethodVFTableLocationsTy; 451 MethodVFTableLocationsTy MethodVFTableLocations; 452 453 typedef llvm::DenseMap<const CXXRecordDecl *, VFPtrListTy> 454 VFPtrLocationsMapTy; 455 VFPtrLocationsMapTy VFPtrLocations; 456 457 typedef std::pair<const CXXRecordDecl *, CharUnits> VFTableIdTy; 458 typedef llvm::DenseMap<VFTableIdTy, const VTableLayout *> VFTableLayoutMapTy; 459 VFTableLayoutMapTy VFTableLayouts; 460 461 void computeVTableRelatedInformation(const CXXRecordDecl *RD); 462 463 void dumpMethodLocations(const CXXRecordDecl *RD, 464 const MethodVFTableLocationsTy &NewMethods, 465 raw_ostream &); 466 467 public: 468 MicrosoftVFTableContext(ASTContext &Context) : Context(Context) {} 469 470 ~MicrosoftVFTableContext() { llvm::DeleteContainerSeconds(VFTableLayouts); } 471 472 const VFPtrListTy &getVFPtrOffsets(const CXXRecordDecl *RD); 473 474 const VTableLayout &getVFTableLayout(const CXXRecordDecl *RD, 475 CharUnits VFPtrOffset); 476 477 const MethodVFTableLocation &getMethodVFTableLocation(GlobalDecl GD); 478 }; 479 } 480 481 #endif 482