• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
VTableComponent()52   VTableComponent() { }
53 
MakeVCallOffset(CharUnits Offset)54   static VTableComponent MakeVCallOffset(CharUnits Offset) {
55     return VTableComponent(CK_VCallOffset, Offset);
56   }
57 
MakeVBaseOffset(CharUnits Offset)58   static VTableComponent MakeVBaseOffset(CharUnits Offset) {
59     return VTableComponent(CK_VBaseOffset, Offset);
60   }
61 
MakeOffsetToTop(CharUnits Offset)62   static VTableComponent MakeOffsetToTop(CharUnits Offset) {
63     return VTableComponent(CK_OffsetToTop, Offset);
64   }
65 
MakeRTTI(const CXXRecordDecl * RD)66   static VTableComponent MakeRTTI(const CXXRecordDecl *RD) {
67     return VTableComponent(CK_RTTI, reinterpret_cast<uintptr_t>(RD));
68   }
69 
MakeFunction(const CXXMethodDecl * MD)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 
MakeCompleteDtor(const CXXDestructorDecl * DD)78   static VTableComponent MakeCompleteDtor(const CXXDestructorDecl *DD) {
79     return VTableComponent(CK_CompleteDtorPointer,
80                            reinterpret_cast<uintptr_t>(DD));
81   }
82 
MakeDeletingDtor(const CXXDestructorDecl * DD)83   static VTableComponent MakeDeletingDtor(const CXXDestructorDecl *DD) {
84     return VTableComponent(CK_DeletingDtorPointer,
85                            reinterpret_cast<uintptr_t>(DD));
86   }
87 
MakeUnusedFunction(const CXXMethodDecl * MD)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 
getFromOpaqueInteger(uint64_t I)95   static VTableComponent getFromOpaqueInteger(uint64_t I) {
96     return VTableComponent(I);
97   }
98 
99   /// \brief Get the kind of this vtable component.
getKind()100   Kind getKind() const {
101     return (Kind)(Value & 0x7);
102   }
103 
getVCallOffset()104   CharUnits getVCallOffset() const {
105     assert(getKind() == CK_VCallOffset && "Invalid component kind!");
106 
107     return getOffset();
108   }
109 
getVBaseOffset()110   CharUnits getVBaseOffset() const {
111     assert(getKind() == CK_VBaseOffset && "Invalid component kind!");
112 
113     return getOffset();
114   }
115 
getOffsetToTop()116   CharUnits getOffsetToTop() const {
117     assert(getKind() == CK_OffsetToTop && "Invalid component kind!");
118 
119     return getOffset();
120   }
121 
getRTTIDecl()122   const CXXRecordDecl *getRTTIDecl() const {
123     assert(getKind() == CK_RTTI && "Invalid component kind!");
124 
125     return reinterpret_cast<CXXRecordDecl *>(getPointer());
126   }
127 
getFunctionDecl()128   const CXXMethodDecl *getFunctionDecl() const {
129     assert(getKind() == CK_FunctionPointer);
130 
131     return reinterpret_cast<CXXMethodDecl *>(getPointer());
132   }
133 
getDestructorDecl()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 
getUnusedFunctionDecl()141   const CXXMethodDecl *getUnusedFunctionDecl() const {
142     assert(getKind() == CK_UnusedFunctionPointer);
143 
144     return reinterpret_cast<CXXMethodDecl *>(getPointer());
145   }
146 
147 private:
VTableComponent(Kind ComponentKind,CharUnits Offset)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 
VTableComponent(Kind ComponentKind,uintptr_t Ptr)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 
getOffset()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 
getPointer()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 
VTableComponent(uint64_t Value)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 
getNumVTableComponents()231   uint64_t getNumVTableComponents() const {
232     return NumVTableComponents;
233   }
234 
vtable_component_begin()235   vtable_component_iterator vtable_component_begin() const {
236    return VTableComponents.get();
237   }
238 
vtable_component_end()239   vtable_component_iterator vtable_component_end() const {
240    return VTableComponents.get()+NumVTableComponents;
241   }
242 
getNumVTableThunks()243   uint64_t getNumVTableThunks() const {
244     return NumVTableThunks;
245   }
246 
vtable_thunk_begin()247   vtable_thunk_iterator vtable_thunk_begin() const {
248    return VTableThunks.get();
249   }
250 
vtable_thunk_end()251   vtable_thunk_iterator vtable_thunk_end() const {
252    return VTableThunks.get()+NumVTableThunks;
253   }
254 
getAddressPoint(BaseSubobject Base)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 
getAddressPoints()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 
~VTableContextBase()285   virtual ~VTableContextBase() {}
286 
287 public:
getThunkInfo(const CXXMethodDecl * MD)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 
isMicrosoftABI()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 
getVTableLayout(const CXXRecordDecl * RD)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 
VFPtrInfoVFPtrInfo380   VFPtrInfo(CharUnits VFPtrOffset, const BasePath &PathToBaseWithVFPtr)
381       : VBTableIndex(0), LastVBase(0), VFPtrOffset(VFPtrOffset),
382         PathToBaseWithVFPtr(PathToBaseWithVFPtr), VFPtrFullOffset(VFPtrOffset) {
383   }
384 
VFPtrInfoVFPtrInfo385   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 
MethodVFTableLocationMethodVFTableLocation427     MethodVFTableLocation()
428         : VBTableIndex(0), VFTableOffset(CharUnits::Zero()), Index(0) {}
429 
MethodVFTableLocationMethodVFTableLocation430     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:
MicrosoftVFTableContext(ASTContext & Context)468   MicrosoftVFTableContext(ASTContext &Context) : Context(Context) {}
469 
~MicrosoftVFTableContext()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