| //===--- RecordLayout.h - Layout information for a struct/union -*- C++ -*-===// |
| // |
| // The LLVM Compiler Infrastructure |
| // |
| // This file is distributed under the University of Illinois Open Source |
| // License. See LICENSE.TXT for details. |
| // |
| //===----------------------------------------------------------------------===// |
| // |
| // This file defines the RecordLayout interface. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #ifndef LLVM_CLANG_AST_LAYOUTINFO_H |
| #define LLVM_CLANG_AST_LAYOUTINFO_H |
| |
| #include "llvm/System/DataTypes.h" |
| #include "llvm/ADT/DenseMap.h" |
| #include "clang/AST/DeclCXX.h" |
| |
| namespace clang { |
| class ASTContext; |
| class FieldDecl; |
| class RecordDecl; |
| class CXXRecordDecl; |
| |
| /// ASTRecordLayout - |
| /// This class contains layout information for one RecordDecl, |
| /// which is a struct/union/class. The decl represented must be a definition, |
| /// not a forward declaration. |
| /// This class is also used to contain layout information for one |
| /// ObjCInterfaceDecl. FIXME - Find appropriate name. |
| /// These objects are managed by ASTContext. |
| class ASTRecordLayout { |
| /// Size - Size of record in bits. |
| uint64_t Size; |
| |
| /// DataSize - Size of record in bits without tail padding. |
| uint64_t DataSize; |
| |
| /// FieldOffsets - Array of field offsets in bits. |
| uint64_t *FieldOffsets; |
| |
| // Alignment - Alignment of record in bits. |
| unsigned Alignment; |
| |
| // FieldCount - Number of fields. |
| unsigned FieldCount; |
| |
| public: |
| /// PrimaryBaseInfo - Contains info about a primary base. |
| struct PrimaryBaseInfo { |
| PrimaryBaseInfo() {} |
| |
| PrimaryBaseInfo(const CXXRecordDecl *Base, bool IsVirtual) |
| : Value(Base, Base && IsVirtual) {} |
| |
| /// Value - Points to the primary base. The single-bit value |
| /// will be non-zero when the primary base is virtual. |
| llvm::PointerIntPair<const CXXRecordDecl *, 1, bool> Value; |
| |
| /// getBase - Returns the primary base. |
| const CXXRecordDecl *getBase() const { return Value.getPointer(); } |
| |
| /// isVirtual - Returns whether the primary base is virtual or not. |
| bool isVirtual() const { return Value.getInt(); } |
| |
| friend bool operator==(const PrimaryBaseInfo &X, const PrimaryBaseInfo &Y) { |
| return X.Value == Y.Value; |
| } |
| }; |
| |
| /// primary_base_info_iterator - An iterator for iterating the primary base |
| /// class chain. |
| class primary_base_info_iterator { |
| /// Current - The current base class info. |
| PrimaryBaseInfo Current; |
| |
| public: |
| primary_base_info_iterator() {} |
| primary_base_info_iterator(PrimaryBaseInfo Info) : Current(Info) {} |
| |
| const PrimaryBaseInfo &operator*() const { return Current; } |
| |
| primary_base_info_iterator& operator++() { |
| const CXXRecordDecl *RD = Current.getBase(); |
| Current = RD->getASTContext().getASTRecordLayout(RD).getPrimaryBaseInfo(); |
| return *this; |
| } |
| |
| friend bool operator==(const primary_base_info_iterator &X, |
| const primary_base_info_iterator &Y) { |
| return X.Current == Y.Current; |
| } |
| friend bool operator!=(const primary_base_info_iterator &X, |
| const primary_base_info_iterator &Y) { |
| return !(X == Y); |
| } |
| }; |
| |
| private: |
| /// CXXRecordLayoutInfo - Contains C++ specific layout information. |
| struct CXXRecordLayoutInfo { |
| /// NonVirtualSize - The non-virtual size (in bits) of an object, which is |
| /// the size of the object without virtual bases. |
| uint64_t NonVirtualSize; |
| |
| /// NonVirtualAlign - The non-virtual alignment (in bits) of an object, |
| /// which is the alignment of the object without virtual bases. |
| uint64_t NonVirtualAlign; |
| |
| /// PrimaryBase - The primary base info for this record. |
| PrimaryBaseInfo PrimaryBase; |
| |
| /// BaseOffsets - Contains a map from base classes to their offset. |
| /// FIXME: This should really use a SmallPtrMap, once we have one in LLVM :) |
| llvm::DenseMap<const CXXRecordDecl *, uint64_t> BaseOffsets; |
| |
| /// VBaseOffsets - Contains a map from vbase classes to their offset. |
| /// FIXME: This should really use a SmallPtrMap, once we have one in LLVM :) |
| llvm::DenseMap<const CXXRecordDecl *, uint64_t> VBaseOffsets; |
| }; |
| |
| /// CXXInfo - If the record layout is for a C++ record, this will have |
| /// C++ specific information about the record. |
| CXXRecordLayoutInfo *CXXInfo; |
| |
| friend class ASTContext; |
| friend class ASTRecordLayoutBuilder; |
| |
| ASTRecordLayout(uint64_t size, unsigned alignment, unsigned datasize, |
| const uint64_t *fieldoffsets, unsigned fieldcount) |
| : Size(size), DataSize(datasize), FieldOffsets(0), Alignment(alignment), |
| FieldCount(fieldcount), CXXInfo(0) { |
| if (FieldCount > 0) { |
| FieldOffsets = new uint64_t[FieldCount]; |
| for (unsigned i = 0; i < FieldCount; ++i) |
| FieldOffsets[i] = fieldoffsets[i]; |
| } |
| } |
| |
| // Constructor for C++ records. |
| ASTRecordLayout(uint64_t size, unsigned alignment, uint64_t datasize, |
| const uint64_t *fieldoffsets, unsigned fieldcount, |
| uint64_t nonvirtualsize, unsigned nonvirtualalign, |
| const PrimaryBaseInfo &PrimaryBase, |
| const std::pair<const CXXRecordDecl *, uint64_t> *bases, |
| unsigned numbases, |
| const std::pair<const CXXRecordDecl *, uint64_t> *vbases, |
| unsigned numvbases) |
| : Size(size), DataSize(datasize), FieldOffsets(0), Alignment(alignment), |
| FieldCount(fieldcount), CXXInfo(new CXXRecordLayoutInfo) { |
| if (FieldCount > 0) { |
| FieldOffsets = new uint64_t[FieldCount]; |
| for (unsigned i = 0; i < FieldCount; ++i) |
| FieldOffsets[i] = fieldoffsets[i]; |
| } |
| |
| CXXInfo->PrimaryBase = PrimaryBase; |
| CXXInfo->NonVirtualSize = nonvirtualsize; |
| CXXInfo->NonVirtualAlign = nonvirtualalign; |
| for (unsigned i = 0; i != numbases; ++i) |
| CXXInfo->BaseOffsets[bases[i].first] = bases[i].second; |
| for (unsigned i = 0; i != numvbases; ++i) |
| CXXInfo->VBaseOffsets[vbases[i].first] = vbases[i].second; |
| } |
| |
| ~ASTRecordLayout() { |
| delete [] FieldOffsets; |
| delete CXXInfo; |
| } |
| |
| ASTRecordLayout(const ASTRecordLayout&); // DO NOT IMPLEMENT |
| void operator=(const ASTRecordLayout&); // DO NOT IMPLEMENT |
| public: |
| |
| /// getAlignment - Get the record alignment in bits. |
| unsigned getAlignment() const { return Alignment; } |
| |
| /// getSize - Get the record size in bits. |
| uint64_t getSize() const { return Size; } |
| |
| /// getFieldCount - Get the number of fields in the layout. |
| unsigned getFieldCount() const { return FieldCount; } |
| |
| /// getFieldOffset - Get the offset of the given field index, in |
| /// bits. |
| uint64_t getFieldOffset(unsigned FieldNo) const { |
| assert (FieldNo < FieldCount && "Invalid Field No"); |
| return FieldOffsets[FieldNo]; |
| } |
| |
| /// getDataSize() - Get the record data size, which is the record size |
| /// without tail padding, in bits. |
| uint64_t getDataSize() const { |
| return DataSize; |
| } |
| |
| /// getNonVirtualSize - Get the non-virtual size (in bits) of an object, |
| /// which is the size of the object without virtual bases. |
| uint64_t getNonVirtualSize() const { |
| assert(CXXInfo && "Record layout does not have C++ specific info!"); |
| |
| return CXXInfo->NonVirtualSize; |
| } |
| |
| /// getNonVirtualSize - Get the non-virtual alignment (in bits) of an object, |
| /// which is the alignment of the object without virtual bases. |
| unsigned getNonVirtualAlign() const { |
| assert(CXXInfo && "Record layout does not have C++ specific info!"); |
| |
| return CXXInfo->NonVirtualAlign; |
| } |
| |
| /// getPrimaryBaseInfo - Get the primary base info. |
| const PrimaryBaseInfo &getPrimaryBaseInfo() const { |
| assert(CXXInfo && "Record layout does not have C++ specific info!"); |
| |
| return CXXInfo->PrimaryBase; |
| } |
| |
| // FIXME: Migrate off of this function and use getPrimaryBaseInfo directly. |
| const CXXRecordDecl *getPrimaryBase() const { |
| return getPrimaryBaseInfo().getBase(); |
| } |
| |
| // FIXME: Migrate off of this function and use getPrimaryBaseInfo directly. |
| bool getPrimaryBaseWasVirtual() const { |
| return getPrimaryBaseInfo().isVirtual(); |
| } |
| |
| /// getBaseClassOffset - Get the offset, in bits, for the given base class. |
| uint64_t getBaseClassOffset(const CXXRecordDecl *Base) const { |
| assert(CXXInfo && "Record layout does not have C++ specific info!"); |
| assert(CXXInfo->BaseOffsets.count(Base) && "Did not find base!"); |
| |
| return CXXInfo->BaseOffsets[Base]; |
| } |
| |
| /// getVBaseClassOffset - Get the offset, in bits, for the given base class. |
| uint64_t getVBaseClassOffset(const CXXRecordDecl *VBase) const { |
| assert(CXXInfo && "Record layout does not have C++ specific info!"); |
| assert(CXXInfo->VBaseOffsets.count(VBase) && "Did not find base!"); |
| |
| return CXXInfo->VBaseOffsets[VBase]; |
| } |
| |
| primary_base_info_iterator primary_base_begin() const { |
| assert(CXXInfo && "Record layout does not have C++ specific info!"); |
| |
| return primary_base_info_iterator(getPrimaryBaseInfo()); |
| } |
| |
| primary_base_info_iterator primary_base_end() const { |
| assert(CXXInfo && "Record layout does not have C++ specific info!"); |
| |
| return primary_base_info_iterator(); |
| } |
| }; |
| |
| } // end namespace clang |
| |
| #endif |