clang API Documentation

VTableBuilder.h
Go to the documentation of this file.
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