Details | Last modification | View Log | RSS feed
| Rev | Author | Line No. | Line |
|---|---|---|---|
| 14 | pmbaty | 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 |