1 //===- RecordLayout.h - Layout information for a struct/union ---*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 //  This file defines the RecordLayout interface.
10 //
11 //===----------------------------------------------------------------------===//
12 
13 #ifndef LLVM_CLANG_AST_RECORDLAYOUT_H
14 #define LLVM_CLANG_AST_RECORDLAYOUT_H
15 
16 #include "clang/AST/ASTVector.h"
17 #include "clang/AST/CharUnits.h"
18 #include "clang/AST/DeclCXX.h"
19 #include "clang/Basic/LLVM.h"
20 #include "llvm/ADT/ArrayRef.h"
21 #include "llvm/ADT/DenseMap.h"
22 #include "llvm/ADT/PointerIntPair.h"
23 #include <cassert>
24 #include <cstdint>
25 
26 namespace clang {
27 
28 class ASTContext;
29 class CXXRecordDecl;
30 
31 /// ASTRecordLayout -
32 /// This class contains layout information for one RecordDecl,
33 /// which is a struct/union/class.  The decl represented must be a definition,
34 /// not a forward declaration.
35 /// This class is also used to contain layout information for one
36 /// ObjCInterfaceDecl. FIXME - Find appropriate name.
37 /// These objects are managed by ASTContext.
38 class ASTRecordLayout {
39 public:
40   struct VBaseInfo {
41     /// The offset to this virtual base in the complete-object layout
42     /// of this class.
43     CharUnits VBaseOffset;
44 
45   private:
46     /// Whether this virtual base requires a vtordisp field in the
47     /// Microsoft ABI.  These fields are required for certain operations
48     /// in constructors and destructors.
49     bool HasVtorDisp = false;
50 
51   public:
52     VBaseInfo() = default;
53     VBaseInfo(CharUnits VBaseOffset, bool hasVtorDisp)
54         : VBaseOffset(VBaseOffset), HasVtorDisp(hasVtorDisp) {}
55 
56     bool hasVtorDisp() const { return HasVtorDisp; }
57   };
58 
59   using VBaseOffsetsMapTy = llvm::DenseMap<const CXXRecordDecl *, VBaseInfo>;
60 
61 private:
62   friend class ASTContext;
63 
64   /// Size - Size of record in characters.
65   CharUnits Size;
66 
67   /// DataSize - Size of record in characters without tail padding.
68   CharUnits DataSize;
69 
70   // Alignment - Alignment of record in characters.
71   CharUnits Alignment;
72 
73   // UnadjustedAlignment - Maximum of the alignments of the record members in
74   // characters.
75   CharUnits UnadjustedAlignment;
76 
77   /// RequiredAlignment - The required alignment of the object.  In the MS-ABI
78   /// the __declspec(align()) trumps #pramga pack and must always be obeyed.
79   CharUnits RequiredAlignment;
80 
81   /// FieldOffsets - Array of field offsets in bits.
82   ASTVector<uint64_t> FieldOffsets;
83 
84   /// CXXRecordLayoutInfo - Contains C++ specific layout information.
85   struct CXXRecordLayoutInfo {
86     /// NonVirtualSize - The non-virtual size (in chars) of an object, which is
87     /// the size of the object without virtual bases.
88     CharUnits NonVirtualSize;
89 
90     /// NonVirtualAlignment - The non-virtual alignment (in chars) of an object,
91     /// which is the alignment of the object without virtual bases.
92     CharUnits NonVirtualAlignment;
93 
94     /// SizeOfLargestEmptySubobject - The size of the largest empty subobject
95     /// (either a base or a member). Will be zero if the class doesn't contain
96     /// any empty subobjects.
97     CharUnits SizeOfLargestEmptySubobject;
98 
99     /// VBPtrOffset - Virtual base table offset (Microsoft-only).
100     CharUnits VBPtrOffset;
101 
102     /// HasOwnVFPtr - Does this class provide a virtual function table
103     /// (vtable in Itanium, vftbl in Microsoft) that is independent from
104     /// its base classes?
105     bool HasOwnVFPtr : 1;
106 
107     /// HasVFPtr - Does this class have a vftable that could be extended by
108     /// a derived class.  The class may have inherited this pointer from
109     /// a primary base class.
110     bool HasExtendableVFPtr : 1;
111 
112     /// EndsWithZeroSizedObject - True if this class contains a zero sized
113     /// member or base or a base with a zero sized member or base.
114     /// Only used for MS-ABI.
115     bool EndsWithZeroSizedObject : 1;
116 
117     /// True if this class is zero sized or first base is zero sized or
118     /// has this property.  Only used for MS-ABI.
119     bool LeadsWithZeroSizedBase : 1;
120 
121     /// PrimaryBase - The primary base info for this record.
122     llvm::PointerIntPair<const CXXRecordDecl *, 1, bool> PrimaryBase;
123 
124     /// BaseSharingVBPtr - The base we share vbptr with.
125     const CXXRecordDecl *BaseSharingVBPtr;
126 
127     /// FIXME: This should really use a SmallPtrMap, once we have one in LLVM :)
128     using BaseOffsetsMapTy = llvm::DenseMap<const CXXRecordDecl *, CharUnits>;
129 
130     /// BaseOffsets - Contains a map from base classes to their offset.
131     BaseOffsetsMapTy BaseOffsets;
132 
133     /// VBaseOffsets - Contains a map from vbase classes to their offset.
134     VBaseOffsetsMapTy VBaseOffsets;
135   };
136 
137   /// CXXInfo - If the record layout is for a C++ record, this will have
138   /// C++ specific information about the record.
139   CXXRecordLayoutInfo *CXXInfo = nullptr;
140 
141   ASTRecordLayout(const ASTContext &Ctx, CharUnits size, CharUnits alignment,
142                   CharUnits unadjustedAlignment,
143                   CharUnits requiredAlignment, CharUnits datasize,
144                   ArrayRef<uint64_t> fieldoffsets);
145 
146   using BaseOffsetsMapTy = CXXRecordLayoutInfo::BaseOffsetsMapTy;
147 
148   // Constructor for C++ records.
149   ASTRecordLayout(const ASTContext &Ctx,
150                   CharUnits size, CharUnits alignment,
151                   CharUnits unadjustedAlignment,
152                   CharUnits requiredAlignment,
153                   bool hasOwnVFPtr, bool hasExtendableVFPtr,
154                   CharUnits vbptroffset,
155                   CharUnits datasize,
156                   ArrayRef<uint64_t> fieldoffsets,
157                   CharUnits nonvirtualsize, CharUnits nonvirtualalignment,
158                   CharUnits SizeOfLargestEmptySubobject,
159                   const CXXRecordDecl *PrimaryBase,
160                   bool IsPrimaryBaseVirtual,
161                   const CXXRecordDecl *BaseSharingVBPtr,
162                   bool EndsWithZeroSizedObject,
163                   bool LeadsWithZeroSizedBase,
164                   const BaseOffsetsMapTy& BaseOffsets,
165                   const VBaseOffsetsMapTy& VBaseOffsets);
166 
167   ~ASTRecordLayout() = default;
168 
169   void Destroy(ASTContext &Ctx);
170 
171 public:
172   ASTRecordLayout(const ASTRecordLayout &) = delete;
173   ASTRecordLayout &operator=(const ASTRecordLayout &) = delete;
174 
175   /// getAlignment - Get the record alignment in characters.
176   CharUnits getAlignment() const { return Alignment; }
177 
178   /// getUnadjustedAlignment - Get the record alignment in characters, before
179   /// alignment adjustement.
180   CharUnits getUnadjustedAlignment() const { return UnadjustedAlignment; }
181 
182   /// getSize - Get the record size in characters.
183   CharUnits getSize() const { return Size; }
184 
185   /// getFieldCount - Get the number of fields in the layout.
186   unsigned getFieldCount() const { return FieldOffsets.size(); }
187 
188   /// getFieldOffset - Get the offset of the given field index, in
189   /// bits.
190   uint64_t getFieldOffset(unsigned FieldNo) const {
191     return FieldOffsets[FieldNo];
192   }
193 
194   /// getDataSize() - Get the record data size, which is the record size
195   /// without tail padding, in characters.
196   CharUnits getDataSize() const {
197     return DataSize;
198   }
199 
200   /// getNonVirtualSize - Get the non-virtual size (in chars) of an object,
201   /// which is the size of the object without virtual bases.
202   CharUnits getNonVirtualSize() const {
203     assert(CXXInfo && "Record layout does not have C++ specific info!");
204 
205     return CXXInfo->NonVirtualSize;
206   }
207 
208   /// getNonVirtualSize - Get the non-virtual alignment (in chars) of an object,
209   /// which is the alignment of the object without virtual bases.
210   CharUnits getNonVirtualAlignment() const {
211     assert(CXXInfo && "Record layout does not have C++ specific info!");
212 
213     return CXXInfo->NonVirtualAlignment;
214   }
215 
216   /// getPrimaryBase - Get the primary base for this record.
217   const CXXRecordDecl *getPrimaryBase() const {
218     assert(CXXInfo && "Record layout does not have C++ specific info!");
219 
220     return CXXInfo->PrimaryBase.getPointer();
221   }
222 
223   /// isPrimaryBaseVirtual - Get whether the primary base for this record
224   /// is virtual or not.
225   bool isPrimaryBaseVirtual() const {
226     assert(CXXInfo && "Record layout does not have C++ specific info!");
227 
228     return CXXInfo->PrimaryBase.getInt();
229   }
230 
231   /// getBaseClassOffset - Get the offset, in chars, for the given base class.
232   CharUnits getBaseClassOffset(const CXXRecordDecl *Base) const {
233     assert(CXXInfo && "Record layout does not have C++ specific info!");
234     assert(CXXInfo->BaseOffsets.count(Base) && "Did not find base!");
235 
236     return CXXInfo->BaseOffsets[Base];
237   }
238 
239   /// getVBaseClassOffset - Get the offset, in chars, for the given base class.
240   CharUnits getVBaseClassOffset(const CXXRecordDecl *VBase) const {
241     assert(CXXInfo && "Record layout does not have C++ specific info!");
242     assert(CXXInfo->VBaseOffsets.count(VBase) && "Did not find base!");
243 
244     return CXXInfo->VBaseOffsets[VBase].VBaseOffset;
245   }
246 
247   CharUnits getSizeOfLargestEmptySubobject() const {
248     assert(CXXInfo && "Record layout does not have C++ specific info!");
249     return CXXInfo->SizeOfLargestEmptySubobject;
250   }
251 
252   /// hasOwnVFPtr - Does this class provide its own virtual-function
253   /// table pointer, rather than inheriting one from a primary base
254   /// class?  If so, it is at offset zero.
255   ///
256   /// This implies that the ABI has no primary base class, meaning
257   /// that it has no base classes that are suitable under the conditions
258   /// of the ABI.
259   bool hasOwnVFPtr() const {
260     assert(CXXInfo && "Record layout does not have C++ specific info!");
261     return CXXInfo->HasOwnVFPtr;
262   }
263 
264   /// hasVFPtr - Does this class have a virtual function table pointer
265   /// that can be extended by a derived class?  This is synonymous with
266   /// this class having a VFPtr at offset zero.
267   bool hasExtendableVFPtr() const {
268     assert(CXXInfo && "Record layout does not have C++ specific info!");
269     return CXXInfo->HasExtendableVFPtr;
270   }
271 
272   /// hasOwnVBPtr - Does this class provide its own virtual-base
273   /// table pointer, rather than inheriting one from a primary base
274   /// class?
275   ///
276   /// This implies that the ABI has no primary base class, meaning
277   /// that it has no base classes that are suitable under the conditions
278   /// of the ABI.
279   bool hasOwnVBPtr() const {
280     assert(CXXInfo && "Record layout does not have C++ specific info!");
281     return hasVBPtr() && !CXXInfo->BaseSharingVBPtr;
282   }
283 
284   /// hasVBPtr - Does this class have a virtual function table pointer.
285   bool hasVBPtr() const {
286     assert(CXXInfo && "Record layout does not have C++ specific info!");
287     return !CXXInfo->VBPtrOffset.isNegative();
288   }
289 
290   CharUnits getRequiredAlignment() const {
291     return RequiredAlignment;
292   }
293 
294   bool endsWithZeroSizedObject() const {
295     return CXXInfo && CXXInfo->EndsWithZeroSizedObject;
296   }
297 
298   bool leadsWithZeroSizedBase() const {
299     assert(CXXInfo && "Record layout does not have C++ specific info!");
300     return CXXInfo->LeadsWithZeroSizedBase;
301   }
302 
303   /// getVBPtrOffset - Get the offset for virtual base table pointer.
304   /// This is only meaningful with the Microsoft ABI.
305   CharUnits getVBPtrOffset() const {
306     assert(CXXInfo && "Record layout does not have C++ specific info!");
307     return CXXInfo->VBPtrOffset;
308   }
309 
310   const CXXRecordDecl *getBaseSharingVBPtr() const {
311     assert(CXXInfo && "Record layout does not have C++ specific info!");
312     return CXXInfo->BaseSharingVBPtr;
313   }
314 
315   const VBaseOffsetsMapTy &getVBaseOffsetsMap() const {
316     assert(CXXInfo && "Record layout does not have C++ specific info!");
317     return CXXInfo->VBaseOffsets;
318   }
319 };
320 
321 } // namespace clang
322 
323 #endif // LLVM_CLANG_AST_RECORDLAYOUT_H
324