clang API Documentation
00001 //===--- VTableBuilder.h - C++ vtable layout builder --------------*- C++ -*-=// 00002 // 00003 // The LLVM Compiler Infrastructure 00004 // 00005 // This file is distributed under the University of Illinois Open Source 00006 // License. See LICENSE.TXT for details. 00007 // 00008 //===----------------------------------------------------------------------===// 00009 // 00010 // This contains code dealing with generation of the layout of virtual tables. 00011 // 00012 //===----------------------------------------------------------------------===// 00013 00014 #ifndef LLVM_CLANG_AST_VTABLEBUILDER_H 00015 #define LLVM_CLANG_AST_VTABLEBUILDER_H 00016 00017 #include "clang/AST/BaseSubobject.h" 00018 #include "clang/AST/CXXInheritance.h" 00019 #include "clang/AST/GlobalDecl.h" 00020 #include "clang/AST/RecordLayout.h" 00021 #include "clang/Basic/ABI.h" 00022 #include "llvm/ADT/SetVector.h" 00023 #include <utility> 00024 00025 namespace clang { 00026 class CXXRecordDecl; 00027 00028 /// VTableComponent - Represents a single component in a vtable. 00029 class VTableComponent { 00030 public: 00031 enum Kind { 00032 CK_VCallOffset, 00033 CK_VBaseOffset, 00034 CK_OffsetToTop, 00035 CK_RTTI, 00036 CK_FunctionPointer, 00037 00038 /// CK_CompleteDtorPointer - A pointer to the complete destructor. 00039 CK_CompleteDtorPointer, 00040 00041 /// CK_DeletingDtorPointer - A pointer to the deleting destructor. 00042 CK_DeletingDtorPointer, 00043 00044 /// CK_UnusedFunctionPointer - In some cases, a vtable function pointer 00045 /// will end up never being called. Such vtable function pointers are 00046 /// represented as a CK_UnusedFunctionPointer. 00047 CK_UnusedFunctionPointer 00048 }; 00049 00050 VTableComponent() { } 00051 00052 static VTableComponent MakeVCallOffset(CharUnits Offset) { 00053 return VTableComponent(CK_VCallOffset, Offset); 00054 } 00055 00056 static VTableComponent MakeVBaseOffset(CharUnits Offset) { 00057 return VTableComponent(CK_VBaseOffset, Offset); 00058 } 00059 00060 static VTableComponent MakeOffsetToTop(CharUnits Offset) { 00061 return VTableComponent(CK_OffsetToTop, Offset); 00062 } 00063 00064 static VTableComponent MakeRTTI(const CXXRecordDecl *RD) { 00065 return VTableComponent(CK_RTTI, reinterpret_cast<uintptr_t>(RD)); 00066 } 00067 00068 static VTableComponent MakeFunction(const CXXMethodDecl *MD) { 00069 assert(!isa<CXXDestructorDecl>(MD) && 00070 "Don't use MakeFunction with destructors!"); 00071 00072 return VTableComponent(CK_FunctionPointer, 00073 reinterpret_cast<uintptr_t>(MD)); 00074 } 00075 00076 static VTableComponent MakeCompleteDtor(const CXXDestructorDecl *DD) { 00077 return VTableComponent(CK_CompleteDtorPointer, 00078 reinterpret_cast<uintptr_t>(DD)); 00079 } 00080 00081 static VTableComponent MakeDeletingDtor(const CXXDestructorDecl *DD) { 00082 return VTableComponent(CK_DeletingDtorPointer, 00083 reinterpret_cast<uintptr_t>(DD)); 00084 } 00085 00086 static VTableComponent MakeUnusedFunction(const CXXMethodDecl *MD) { 00087 assert(!isa<CXXDestructorDecl>(MD) && 00088 "Don't use MakeUnusedFunction with destructors!"); 00089 return VTableComponent(CK_UnusedFunctionPointer, 00090 reinterpret_cast<uintptr_t>(MD)); 00091 } 00092 00093 static VTableComponent getFromOpaqueInteger(uint64_t I) { 00094 return VTableComponent(I); 00095 } 00096 00097 /// getKind - Get the kind of this vtable component. 00098 Kind getKind() const { 00099 return (Kind)(Value & 0x7); 00100 } 00101 00102 CharUnits getVCallOffset() const { 00103 assert(getKind() == CK_VCallOffset && "Invalid component kind!"); 00104 00105 return getOffset(); 00106 } 00107 00108 CharUnits getVBaseOffset() const { 00109 assert(getKind() == CK_VBaseOffset && "Invalid component kind!"); 00110 00111 return getOffset(); 00112 } 00113 00114 CharUnits getOffsetToTop() const { 00115 assert(getKind() == CK_OffsetToTop && "Invalid component kind!"); 00116 00117 return getOffset(); 00118 } 00119 00120 const CXXRecordDecl *getRTTIDecl() const { 00121 assert(getKind() == CK_RTTI && "Invalid component kind!"); 00122 00123 return reinterpret_cast<CXXRecordDecl *>(getPointer()); 00124 } 00125 00126 const CXXMethodDecl *getFunctionDecl() const { 00127 assert(getKind() == CK_FunctionPointer); 00128 00129 return reinterpret_cast<CXXMethodDecl *>(getPointer()); 00130 } 00131 00132 const CXXDestructorDecl *getDestructorDecl() const { 00133 assert((getKind() == CK_CompleteDtorPointer || 00134 getKind() == CK_DeletingDtorPointer) && "Invalid component kind!"); 00135 00136 return reinterpret_cast<CXXDestructorDecl *>(getPointer()); 00137 } 00138 00139 const CXXMethodDecl *getUnusedFunctionDecl() const { 00140 assert(getKind() == CK_UnusedFunctionPointer); 00141 00142 return reinterpret_cast<CXXMethodDecl *>(getPointer()); 00143 } 00144 00145 private: 00146 VTableComponent(Kind ComponentKind, CharUnits Offset) { 00147 assert((ComponentKind == CK_VCallOffset || 00148 ComponentKind == CK_VBaseOffset || 00149 ComponentKind == CK_OffsetToTop) && "Invalid component kind!"); 00150 assert(Offset.getQuantity() <= ((1LL << 56) - 1) && "Offset is too big!"); 00151 00152 Value = ((Offset.getQuantity() << 3) | ComponentKind); 00153 } 00154 00155 VTableComponent(Kind ComponentKind, uintptr_t Ptr) { 00156 assert((ComponentKind == CK_RTTI || 00157 ComponentKind == CK_FunctionPointer || 00158 ComponentKind == CK_CompleteDtorPointer || 00159 ComponentKind == CK_DeletingDtorPointer || 00160 ComponentKind == CK_UnusedFunctionPointer) && 00161 "Invalid component kind!"); 00162 00163 assert((Ptr & 7) == 0 && "Pointer not sufficiently aligned!"); 00164 00165 Value = Ptr | ComponentKind; 00166 } 00167 00168 CharUnits getOffset() const { 00169 assert((getKind() == CK_VCallOffset || getKind() == CK_VBaseOffset || 00170 getKind() == CK_OffsetToTop) && "Invalid component kind!"); 00171 00172 return CharUnits::fromQuantity(Value >> 3); 00173 } 00174 00175 uintptr_t getPointer() const { 00176 assert((getKind() == CK_RTTI || 00177 getKind() == CK_FunctionPointer || 00178 getKind() == CK_CompleteDtorPointer || 00179 getKind() == CK_DeletingDtorPointer || 00180 getKind() == CK_UnusedFunctionPointer) && 00181 "Invalid component kind!"); 00182 00183 return static_cast<uintptr_t>(Value & ~7ULL); 00184 } 00185 00186 explicit VTableComponent(uint64_t Value) 00187 : Value(Value) { } 00188 00189 /// The kind is stored in the lower 3 bits of the value. For offsets, we 00190 /// make use of the facts that classes can't be larger than 2^55 bytes, 00191 /// so we store the offset in the lower part of the 61 bytes that remain. 00192 /// (The reason that we're not simply using a PointerIntPair here is that we 00193 /// need the offsets to be 64-bit, even when on a 32-bit machine). 00194 int64_t Value; 00195 }; 00196 00197 class VTableLayout { 00198 public: 00199 typedef std::pair<uint64_t, ThunkInfo> VTableThunkTy; 00200 typedef SmallVector<ThunkInfo, 1> ThunkInfoVectorTy; 00201 00202 typedef const VTableComponent *vtable_component_iterator; 00203 typedef const VTableThunkTy *vtable_thunk_iterator; 00204 00205 typedef llvm::DenseMap<BaseSubobject, uint64_t> AddressPointsMapTy; 00206 private: 00207 uint64_t NumVTableComponents; 00208 llvm::OwningArrayPtr<VTableComponent> VTableComponents; 00209 00210 /// VTableThunks - Contains thunks needed by vtables. 00211 uint64_t NumVTableThunks; 00212 llvm::OwningArrayPtr<VTableThunkTy> VTableThunks; 00213 00214 /// Address points - Address points for all vtables. 00215 AddressPointsMapTy AddressPoints; 00216 00217 public: 00218 VTableLayout(uint64_t NumVTableComponents, 00219 const VTableComponent *VTableComponents, 00220 uint64_t NumVTableThunks, 00221 const VTableThunkTy *VTableThunks, 00222 const AddressPointsMapTy &AddressPoints); 00223 ~VTableLayout(); 00224 00225 uint64_t getNumVTableComponents() const { 00226 return NumVTableComponents; 00227 } 00228 00229 vtable_component_iterator vtable_component_begin() const { 00230 return VTableComponents.get(); 00231 } 00232 00233 vtable_component_iterator vtable_component_end() const { 00234 return VTableComponents.get()+NumVTableComponents; 00235 } 00236 00237 uint64_t getNumVTableThunks() const { 00238 return NumVTableThunks; 00239 } 00240 00241 vtable_thunk_iterator vtable_thunk_begin() const { 00242 return VTableThunks.get(); 00243 } 00244 00245 vtable_thunk_iterator vtable_thunk_end() const { 00246 return VTableThunks.get()+NumVTableThunks; 00247 } 00248 00249 uint64_t getAddressPoint(BaseSubobject Base) const { 00250 assert(AddressPoints.count(Base) && 00251 "Did not find address point!"); 00252 00253 uint64_t AddressPoint = AddressPoints.lookup(Base); 00254 assert(AddressPoint && "Address point must not be zero!"); 00255 00256 return AddressPoint; 00257 } 00258 00259 const AddressPointsMapTy &getAddressPoints() const { 00260 return AddressPoints; 00261 } 00262 }; 00263 00264 class VTableContext { 00265 ASTContext &Context; 00266 00267 public: 00268 typedef SmallVector<std::pair<uint64_t, ThunkInfo>, 1> 00269 VTableThunksTy; 00270 typedef SmallVector<ThunkInfo, 1> ThunkInfoVectorTy; 00271 00272 private: 00273 /// MethodVTableIndices - Contains the index (relative to the vtable address 00274 /// point) where the function pointer for a virtual function is stored. 00275 typedef llvm::DenseMap<GlobalDecl, int64_t> MethodVTableIndicesTy; 00276 MethodVTableIndicesTy MethodVTableIndices; 00277 00278 typedef llvm::DenseMap<const CXXRecordDecl *, const VTableLayout *> 00279 VTableLayoutMapTy; 00280 VTableLayoutMapTy VTableLayouts; 00281 00282 /// NumVirtualFunctionPointers - Contains the number of virtual function 00283 /// pointers in the vtable for a given record decl. 00284 llvm::DenseMap<const CXXRecordDecl *, uint64_t> NumVirtualFunctionPointers; 00285 00286 typedef std::pair<const CXXRecordDecl *, 00287 const CXXRecordDecl *> ClassPairTy; 00288 00289 /// VirtualBaseClassOffsetOffsets - Contains the vtable offset (relative to 00290 /// the address point) in chars where the offsets for virtual bases of a class 00291 /// are stored. 00292 typedef llvm::DenseMap<ClassPairTy, CharUnits> 00293 VirtualBaseClassOffsetOffsetsMapTy; 00294 VirtualBaseClassOffsetOffsetsMapTy VirtualBaseClassOffsetOffsets; 00295 00296 typedef llvm::DenseMap<const CXXMethodDecl *, ThunkInfoVectorTy> ThunksMapTy; 00297 00298 /// Thunks - Contains all thunks that a given method decl will need. 00299 ThunksMapTy Thunks; 00300 00301 void ComputeMethodVTableIndices(const CXXRecordDecl *RD); 00302 00303 /// ComputeVTableRelatedInformation - Compute and store all vtable related 00304 /// information (vtable layout, vbase offset offsets, thunks etc) for the 00305 /// given record decl. 00306 void ComputeVTableRelatedInformation(const CXXRecordDecl *RD); 00307 00308 public: 00309 VTableContext(ASTContext &Context) : Context(Context) {} 00310 ~VTableContext(); 00311 00312 const VTableLayout &getVTableLayout(const CXXRecordDecl *RD) { 00313 ComputeVTableRelatedInformation(RD); 00314 assert(VTableLayouts.count(RD) && "No layout for this record decl!"); 00315 00316 return *VTableLayouts[RD]; 00317 } 00318 00319 VTableLayout * 00320 createConstructionVTableLayout(const CXXRecordDecl *MostDerivedClass, 00321 CharUnits MostDerivedClassOffset, 00322 bool MostDerivedClassIsVirtual, 00323 const CXXRecordDecl *LayoutClass); 00324 00325 const ThunkInfoVectorTy *getThunkInfo(const CXXMethodDecl *MD) { 00326 ComputeVTableRelatedInformation(MD->getParent()); 00327 00328 ThunksMapTy::const_iterator I = Thunks.find(MD); 00329 if (I == Thunks.end()) { 00330 // We did not find a thunk for this method. 00331 return 0; 00332 } 00333 00334 return &I->second; 00335 } 00336 00337 /// getNumVirtualFunctionPointers - Return the number of virtual function 00338 /// pointers in the vtable for a given record decl. 00339 uint64_t getNumVirtualFunctionPointers(const CXXRecordDecl *RD); 00340 00341 /// getMethodVTableIndex - Return the index (relative to the vtable address 00342 /// point) where the function pointer for the given virtual function is 00343 /// stored. 00344 uint64_t getMethodVTableIndex(GlobalDecl GD); 00345 00346 /// getVirtualBaseOffsetOffset - Return the offset in chars (relative to the 00347 /// vtable address point) where the offset of the virtual base that contains 00348 /// the given base is stored, otherwise, if no virtual base contains the given 00349 /// class, return 0. Base must be a virtual base class or an unambigious 00350 /// base. 00351 CharUnits getVirtualBaseOffsetOffset(const CXXRecordDecl *RD, 00352 const CXXRecordDecl *VBase); 00353 }; 00354 00355 } 00356 00357 #endif