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 | // PreferredAlignment - Preferred alignment of record in characters. This |
74 | // can be different than Alignment in cases where it is beneficial for |
75 | // performance or backwards compatibility preserving (e.g. AIX-ABI). |
76 | CharUnits PreferredAlignment; |
77 | |
78 | // UnadjustedAlignment - Maximum of the alignments of the record members in |
79 | // characters. |
80 | CharUnits UnadjustedAlignment; |
81 | |
82 | /// RequiredAlignment - The required alignment of the object. In the MS-ABI |
83 | /// the __declspec(align()) trumps #pramga pack and must always be obeyed. |
84 | CharUnits RequiredAlignment; |
85 | |
86 | /// FieldOffsets - Array of field offsets in bits. |
87 | ASTVector<uint64_t> FieldOffsets; |
88 | |
89 | /// CXXRecordLayoutInfo - Contains C++ specific layout information. |
90 | struct CXXRecordLayoutInfo { |
91 | /// NonVirtualSize - The non-virtual size (in chars) of an object, which is |
92 | /// the size of the object without virtual bases. |
93 | CharUnits NonVirtualSize; |
94 | |
95 | /// NonVirtualAlignment - The non-virtual alignment (in chars) of an object, |
96 | /// which is the alignment of the object without virtual bases. |
97 | CharUnits NonVirtualAlignment; |
98 | |
99 | /// PreferredNVAlignment - The preferred non-virtual alignment (in chars) of |
100 | /// an object, which is the preferred alignment of the object without |
101 | /// virtual bases. |
102 | CharUnits PreferredNVAlignment; |
103 | |
104 | /// SizeOfLargestEmptySubobject - The size of the largest empty subobject |
105 | /// (either a base or a member). Will be zero if the class doesn't contain |
106 | /// any empty subobjects. |
107 | CharUnits SizeOfLargestEmptySubobject; |
108 | |
109 | /// VBPtrOffset - Virtual base table offset (Microsoft-only). |
110 | CharUnits VBPtrOffset; |
111 | |
112 | /// HasOwnVFPtr - Does this class provide a virtual function table |
113 | /// (vtable in Itanium, vftbl in Microsoft) that is independent from |
114 | /// its base classes? |
115 | bool HasOwnVFPtr : 1; |
116 | |
117 | /// HasVFPtr - Does this class have a vftable that could be extended by |
118 | /// a derived class. The class may have inherited this pointer from |
119 | /// a primary base class. |
120 | bool HasExtendableVFPtr : 1; |
121 | |
122 | /// EndsWithZeroSizedObject - True if this class contains a zero sized |
123 | /// member or base or a base with a zero sized member or base. |
124 | /// Only used for MS-ABI. |
125 | bool EndsWithZeroSizedObject : 1; |
126 | |
127 | /// True if this class is zero sized or first base is zero sized or |
128 | /// has this property. Only used for MS-ABI. |
129 | bool LeadsWithZeroSizedBase : 1; |
130 | |
131 | /// PrimaryBase - The primary base info for this record. |
132 | llvm::PointerIntPair<const CXXRecordDecl *, 1, bool> PrimaryBase; |
133 | |
134 | /// BaseSharingVBPtr - The base we share vbptr with. |
135 | const CXXRecordDecl *BaseSharingVBPtr; |
136 | |
137 | /// FIXME: This should really use a SmallPtrMap, once we have one in LLVM :) |
138 | using BaseOffsetsMapTy = llvm::DenseMap<const CXXRecordDecl *, CharUnits>; |
139 | |
140 | /// BaseOffsets - Contains a map from base classes to their offset. |
141 | BaseOffsetsMapTy BaseOffsets; |
142 | |
143 | /// VBaseOffsets - Contains a map from vbase classes to their offset. |
144 | VBaseOffsetsMapTy VBaseOffsets; |
145 | }; |
146 | |
147 | /// CXXInfo - If the record layout is for a C++ record, this will have |
148 | /// C++ specific information about the record. |
149 | CXXRecordLayoutInfo *CXXInfo = nullptr; |
150 | |
151 | ASTRecordLayout(const ASTContext &Ctx, CharUnits size, CharUnits alignment, |
152 | CharUnits preferredAlignment, CharUnits unadjustedAlignment, |
153 | CharUnits requiredAlignment, CharUnits datasize, |
154 | ArrayRef<uint64_t> fieldoffsets); |
155 | |
156 | using BaseOffsetsMapTy = CXXRecordLayoutInfo::BaseOffsetsMapTy; |
157 | |
158 | // Constructor for C++ records. |
159 | ASTRecordLayout(const ASTContext &Ctx, CharUnits size, CharUnits alignment, |
160 | CharUnits preferredAlignment, CharUnits unadjustedAlignment, |
161 | CharUnits requiredAlignment, bool hasOwnVFPtr, |
162 | bool hasExtendableVFPtr, CharUnits vbptroffset, |
163 | CharUnits datasize, ArrayRef<uint64_t> fieldoffsets, |
164 | CharUnits nonvirtualsize, CharUnits nonvirtualalignment, |
165 | CharUnits preferrednvalignment, |
166 | CharUnits SizeOfLargestEmptySubobject, |
167 | const CXXRecordDecl *PrimaryBase, bool IsPrimaryBaseVirtual, |
168 | const CXXRecordDecl *BaseSharingVBPtr, |
169 | bool EndsWithZeroSizedObject, bool LeadsWithZeroSizedBase, |
170 | const BaseOffsetsMapTy &BaseOffsets, |
171 | const VBaseOffsetsMapTy &VBaseOffsets); |
172 | |
173 | ~ASTRecordLayout() = default; |
174 | |
175 | void Destroy(ASTContext &Ctx); |
176 | |
177 | public: |
178 | ASTRecordLayout(const ASTRecordLayout &) = delete; |
179 | ASTRecordLayout &operator=(const ASTRecordLayout &) = delete; |
180 | |
181 | /// getAlignment - Get the record alignment in characters. |
182 | CharUnits getAlignment() const { return Alignment; } |
183 | |
184 | /// getPreferredFieldAlignment - Get the record preferred alignment in |
185 | /// characters. |
186 | CharUnits getPreferredAlignment() const { return PreferredAlignment; } |
187 | |
188 | /// getUnadjustedAlignment - Get the record alignment in characters, before |
189 | /// alignment adjustement. |
190 | CharUnits getUnadjustedAlignment() const { return UnadjustedAlignment; } |
191 | |
192 | /// getSize - Get the record size in characters. |
193 | CharUnits getSize() const { return Size; } |
194 | |
195 | /// getFieldCount - Get the number of fields in the layout. |
196 | unsigned getFieldCount() const { return FieldOffsets.size(); } |
197 | |
198 | /// getFieldOffset - Get the offset of the given field index, in |
199 | /// bits. |
200 | uint64_t getFieldOffset(unsigned FieldNo) const { |
201 | return FieldOffsets[FieldNo]; |
202 | } |
203 | |
204 | /// getDataSize() - Get the record data size, which is the record size |
205 | /// without tail padding, in characters. |
206 | CharUnits getDataSize() const { return DataSize; } |
207 | |
208 | /// getNonVirtualSize - Get the non-virtual size (in chars) of an object, |
209 | /// which is the size of the object without virtual bases. |
210 | CharUnits getNonVirtualSize() const { |
211 | assert(CXXInfo && "Record layout does not have C++ specific info!" ); |
212 | |
213 | return CXXInfo->NonVirtualSize; |
214 | } |
215 | |
216 | /// getNonVirtualAlignment - Get the non-virtual alignment (in chars) of an |
217 | /// object, which is the alignment of the object without virtual bases. |
218 | CharUnits getNonVirtualAlignment() const { |
219 | assert(CXXInfo && "Record layout does not have C++ specific info!" ); |
220 | |
221 | return CXXInfo->NonVirtualAlignment; |
222 | } |
223 | |
224 | /// getPreferredNVAlignment - Get the preferred non-virtual alignment (in |
225 | /// chars) of an object, which is the preferred alignment of the object |
226 | /// without virtual bases. |
227 | CharUnits getPreferredNVAlignment() const { |
228 | assert(CXXInfo && "Record layout does not have C++ specific info!" ); |
229 | |
230 | return CXXInfo->PreferredNVAlignment; |
231 | } |
232 | |
233 | /// getPrimaryBase - Get the primary base for this record. |
234 | const CXXRecordDecl *getPrimaryBase() const { |
235 | assert(CXXInfo && "Record layout does not have C++ specific info!" ); |
236 | |
237 | return CXXInfo->PrimaryBase.getPointer(); |
238 | } |
239 | |
240 | /// isPrimaryBaseVirtual - Get whether the primary base for this record |
241 | /// is virtual or not. |
242 | bool isPrimaryBaseVirtual() const { |
243 | assert(CXXInfo && "Record layout does not have C++ specific info!" ); |
244 | |
245 | return CXXInfo->PrimaryBase.getInt(); |
246 | } |
247 | |
248 | /// getBaseClassOffset - Get the offset, in chars, for the given base class. |
249 | CharUnits getBaseClassOffset(const CXXRecordDecl *Base) const { |
250 | assert(CXXInfo && "Record layout does not have C++ specific info!" ); |
251 | |
252 | Base = Base->getDefinition(); |
253 | assert(CXXInfo->BaseOffsets.count(Base) && "Did not find base!" ); |
254 | |
255 | return CXXInfo->BaseOffsets[Base]; |
256 | } |
257 | |
258 | /// getVBaseClassOffset - Get the offset, in chars, for the given base class. |
259 | CharUnits getVBaseClassOffset(const CXXRecordDecl *VBase) const { |
260 | assert(CXXInfo && "Record layout does not have C++ specific info!" ); |
261 | |
262 | VBase = VBase->getDefinition(); |
263 | assert(CXXInfo->VBaseOffsets.count(VBase) && "Did not find base!" ); |
264 | |
265 | return CXXInfo->VBaseOffsets[VBase].VBaseOffset; |
266 | } |
267 | |
268 | CharUnits getSizeOfLargestEmptySubobject() const { |
269 | assert(CXXInfo && "Record layout does not have C++ specific info!" ); |
270 | return CXXInfo->SizeOfLargestEmptySubobject; |
271 | } |
272 | |
273 | /// hasOwnVFPtr - Does this class provide its own virtual-function |
274 | /// table pointer, rather than inheriting one from a primary base |
275 | /// class? If so, it is at offset zero. |
276 | /// |
277 | /// This implies that the ABI has no primary base class, meaning |
278 | /// that it has no base classes that are suitable under the conditions |
279 | /// of the ABI. |
280 | bool hasOwnVFPtr() const { |
281 | assert(CXXInfo && "Record layout does not have C++ specific info!" ); |
282 | return CXXInfo->HasOwnVFPtr; |
283 | } |
284 | |
285 | /// hasVFPtr - Does this class have a virtual function table pointer |
286 | /// that can be extended by a derived class? This is synonymous with |
287 | /// this class having a VFPtr at offset zero. |
288 | bool hasExtendableVFPtr() const { |
289 | assert(CXXInfo && "Record layout does not have C++ specific info!" ); |
290 | return CXXInfo->HasExtendableVFPtr; |
291 | } |
292 | |
293 | /// hasOwnVBPtr - Does this class provide its own virtual-base |
294 | /// table pointer, rather than inheriting one from a primary base |
295 | /// class? |
296 | /// |
297 | /// This implies that the ABI has no primary base class, meaning |
298 | /// that it has no base classes that are suitable under the conditions |
299 | /// of the ABI. |
300 | bool hasOwnVBPtr() const { |
301 | assert(CXXInfo && "Record layout does not have C++ specific info!" ); |
302 | return hasVBPtr() && !CXXInfo->BaseSharingVBPtr; |
303 | } |
304 | |
305 | /// hasVBPtr - Does this class have a virtual function table pointer. |
306 | bool hasVBPtr() const { |
307 | assert(CXXInfo && "Record layout does not have C++ specific info!" ); |
308 | return !CXXInfo->VBPtrOffset.isNegative(); |
309 | } |
310 | |
311 | CharUnits getRequiredAlignment() const { return RequiredAlignment; } |
312 | |
313 | bool endsWithZeroSizedObject() const { |
314 | return CXXInfo && CXXInfo->EndsWithZeroSizedObject; |
315 | } |
316 | |
317 | bool leadsWithZeroSizedBase() const { |
318 | assert(CXXInfo && "Record layout does not have C++ specific info!" ); |
319 | return CXXInfo->LeadsWithZeroSizedBase; |
320 | } |
321 | |
322 | /// getVBPtrOffset - Get the offset for virtual base table pointer. |
323 | /// This is only meaningful with the Microsoft ABI. |
324 | CharUnits getVBPtrOffset() const { |
325 | assert(CXXInfo && "Record layout does not have C++ specific info!" ); |
326 | return CXXInfo->VBPtrOffset; |
327 | } |
328 | |
329 | const CXXRecordDecl *getBaseSharingVBPtr() const { |
330 | assert(CXXInfo && "Record layout does not have C++ specific info!" ); |
331 | return CXXInfo->BaseSharingVBPtr; |
332 | } |
333 | |
334 | const VBaseOffsetsMapTy &getVBaseOffsetsMap() const { |
335 | assert(CXXInfo && "Record layout does not have C++ specific info!" ); |
336 | return CXXInfo->VBaseOffsets; |
337 | } |
338 | }; |
339 | |
340 | } // namespace clang |
341 | |
342 | #endif // LLVM_CLANG_AST_RECORDLAYOUT_H |
343 | |