| //===--- MetadataLayout.h - Type metadata layout ----------------*- C++ -*-===// |
| // |
| // This source file is part of the Swift.org open source project |
| // |
| // Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors |
| // Licensed under Apache License v2.0 with Runtime Library Exception |
| // |
| // See https://swift.org/LICENSE.txt for license information |
| // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors |
| // |
| //===----------------------------------------------------------------------===// |
| // |
| // Information recording the layout of type metadata objects. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #ifndef SWIFT_IRGEN_METADATALAYOUT_H |
| #define SWIFT_IRGEN_METADATALAYOUT_H |
| |
| #include "IRGen.h" |
| #include "swift/SIL/SILDeclRef.h" |
| |
| namespace swift { |
| class ClassDecl; |
| class EnumDecl; |
| class StructDecl; |
| class VarDecl; |
| |
| namespace irgen { |
| class Address; |
| class IRGenFunction; |
| class IRGenModule; |
| |
| /// The total size and address point of a metadata object. |
| struct MetadataSize { |
| Size FullSize; |
| Size AddressPoint; |
| |
| /// Return the offset from the address point to the end of the |
| /// metadata object. |
| Size getOffsetToEnd() const { |
| return FullSize - AddressPoint; |
| } |
| }; |
| |
| /// A base class for various kinds of metadata layout. |
| class MetadataLayout { |
| public: |
| enum class Kind { |
| Class, |
| Struct, |
| Enum |
| // Update NominalMetadataLayout::classof if you add a non-nominal layout. |
| }; |
| |
| class StoredOffset { |
| enum State { |
| /// The high bits are an integer displacement. |
| Static = 0, |
| |
| /// The high bits are an llvm::Constant* for the displacement, |
| /// which may be null if it hasn't been computed yet. |
| Dynamic, |
| }; |
| enum : uint64_t { |
| KindBits = 1, |
| KindMask = (1 << KindBits) - 1, |
| PayloadMask = ~uint64_t(KindMask) |
| }; |
| |
| mutable uintptr_t Data; |
| public: |
| StoredOffset() : Data(0) {} |
| explicit StoredOffset(llvm::Constant *offset) |
| : Data(reinterpret_cast<uintptr_t>(offset) | Dynamic) {} |
| explicit StoredOffset(Size offset) |
| : Data((static_cast<uint64_t>(offset.getValue()) << KindBits) | Static) { |
| assert(!offset.isZero() && "cannot store a zero offset"); |
| assert(getStaticOffset() == offset && "overflow"); |
| } |
| |
| bool isValid() const { return Data != 0; } |
| bool isStatic() const { return isValid() && (Data & KindMask) == Static; } |
| bool isDynamic() const { return (Data & KindMask) == Dynamic; } |
| Size getStaticOffset() const { |
| assert(isStatic()); |
| return Size(static_cast<int64_t>(Data) >> KindBits); |
| } |
| llvm::Constant *getDynamicOffsetVariable() const { |
| assert(isDynamic()); |
| return reinterpret_cast<llvm::Constant*>(Data & PayloadMask); |
| } |
| void setDynamicOffsetVariable(llvm::Constant *pointer) const { |
| assert(isDynamic()); |
| Data = reinterpret_cast<uintptr_t>(pointer) | Dynamic; |
| } |
| }; |
| |
| private: |
| Kind TheKind; |
| |
| protected: |
| MetadataSize TheSize; |
| |
| MetadataLayout(Kind theKind) : TheKind(theKind) {} |
| |
| MetadataLayout(const MetadataLayout &other) = delete; |
| MetadataLayout &operator=(const MetadataLayout &other) = delete; |
| |
| public: |
| /// Destruct and deallocate this layout object. |
| void destroy() const; |
| |
| Kind getKind() const { return TheKind; } |
| |
| MetadataSize getSize() const { return TheSize; } |
| }; |
| |
| /// Base class for nominal type metadata layouts. |
| class NominalMetadataLayout : public MetadataLayout { |
| protected: |
| StoredOffset GenericRequirements; |
| StoredOffset Parent; |
| |
| NominalMetadataLayout(Kind kind) : MetadataLayout(kind) {} |
| |
| public: |
| bool hasGenericRequirements() const { |
| return GenericRequirements.isValid(); |
| } |
| |
| /// Should only be used when emitting the nominal type descriptor. |
| Size getStaticGenericRequirementsOffset() const; |
| |
| Offset getGenericRequirementsOffset(IRGenFunction &IGF) const; |
| |
| Offset getParentOffset(IRGenFunction &IGF) const; |
| |
| static bool classof(const MetadataLayout *layout) { |
| return true; // No non-nominal metadata for now. |
| } |
| }; |
| |
| /// Layout for class type metadata. |
| class ClassMetadataLayout : public NominalMetadataLayout { |
| public: |
| class MethodInfo { |
| Offset TheOffset; |
| public: |
| MethodInfo(Offset offset) |
| : TheOffset(offset) {} |
| Offset getOffset() const { return TheOffset; } |
| }; |
| |
| private: |
| StoredOffset InstanceSize; |
| StoredOffset InstanceAlignMask; |
| |
| struct StoredMethodInfo { |
| StoredOffset TheOffset; |
| StoredMethodInfo(StoredOffset offset) : TheOffset(offset) {} |
| }; |
| llvm::DenseMap<SILDeclRef, StoredMethodInfo> MethodInfos; |
| |
| /// Field offsets for various fields. |
| llvm::DenseMap<VarDecl*, StoredOffset> FieldOffsets; |
| |
| /// The start of the vtable. |
| StoredOffset VTableOffset; |
| |
| /// The start of the field-offset vector. |
| StoredOffset FieldOffsetVector; |
| |
| const StoredMethodInfo &getStoredMethodInfo(SILDeclRef method) const { |
| auto it = MethodInfos.find(method); |
| assert(it != MethodInfos.end()); |
| return it->second; |
| } |
| |
| const StoredOffset &getStoredFieldOffset(VarDecl *field) const { |
| auto it = FieldOffsets.find(field); |
| assert(it != FieldOffsets.end()); |
| return it->second; |
| } |
| |
| friend class IRGenModule; |
| ClassMetadataLayout(IRGenModule &IGM, ClassDecl *theClass); |
| |
| public: |
| Size getInstanceSizeOffset() const; |
| |
| Size getInstanceAlignMaskOffset() const; |
| |
| /// Should only be used when emitting the nominal type descriptor. |
| Size getStaticVTableOffset() const; |
| |
| /// Returns the start of the vtable in the class metadata. |
| Offset getVTableOffset(IRGenFunction &IGF) const; |
| |
| /// Returns the size of the vtable, in words. |
| unsigned getVTableSize() const { |
| return MethodInfos.size(); |
| } |
| |
| MethodInfo getMethodInfo(IRGenFunction &IGF, SILDeclRef method) const; |
| |
| /// Assuming that the given method is at a static offset in the metadata, |
| /// return that static offset. |
| /// |
| /// DEPRECATED: callers should be updated to handle this in a |
| /// more arbitrary fashion. |
| Size getStaticMethodOffset(SILDeclRef method) const; |
| |
| Offset getFieldOffset(IRGenFunction &IGF, VarDecl *field) const; |
| |
| /// Assuming that the given field offset is at a static offset in |
| /// the metadata, return that static offset. |
| /// |
| /// DEPRECATED: callers should be updated to handle this in a |
| /// more arbitrary fashion. |
| Size getStaticFieldOffset(VarDecl *field) const; |
| |
| /// Should only be used when emitting the nominal type descriptor. |
| Size getStaticFieldOffsetVectorOffset() const; |
| |
| Offset getFieldOffsetVectorOffset(IRGenFunction &IGF) const; |
| |
| static bool classof(const MetadataLayout *layout) { |
| return layout->getKind() == Kind::Class; |
| } |
| }; |
| |
| /// Layout for enum type metadata. |
| class EnumMetadataLayout : public NominalMetadataLayout { |
| /// The offset of the payload size field, if there is one. |
| StoredOffset PayloadSizeOffset; |
| |
| // TODO: presumably it would be useful to store *something* here |
| // for resilience. |
| |
| friend class IRGenModule; |
| EnumMetadataLayout(IRGenModule &IGM, EnumDecl *theEnum); |
| |
| public: |
| bool hasPayloadSizeOffset() const { |
| return PayloadSizeOffset.isValid(); |
| } |
| |
| Offset getPayloadSizeOffset() const; |
| |
| static bool classof(const MetadataLayout *layout) { |
| return layout->getKind() == Kind::Enum; |
| } |
| }; |
| |
| /// Layout for struct type metadata. |
| class StructMetadataLayout : public NominalMetadataLayout { |
| llvm::DenseMap<VarDecl*, StoredOffset> FieldOffsets; |
| |
| /// The start of the field-offset vector. |
| StoredOffset FieldOffsetVector; |
| |
| const StoredOffset &getStoredFieldOffset(VarDecl *field) const { |
| auto it = FieldOffsets.find(field); |
| assert(it != FieldOffsets.end()); |
| return it->second; |
| } |
| |
| friend class IRGenModule; |
| StructMetadataLayout(IRGenModule &IGM, StructDecl *theStruct); |
| |
| public: |
| |
| Offset getFieldOffset(IRGenFunction &IGF, VarDecl *field) const; |
| |
| /// Assuming that the given field offset is at a static offset in |
| /// the metadata, return that static offset. |
| /// |
| /// DEPRECATED: callers should be updated to handle this in a |
| /// more arbitrary fashion. |
| Size getStaticFieldOffset(VarDecl *field) const; |
| |
| Offset getFieldOffsetVectorOffset() const; |
| |
| static bool classof(const MetadataLayout *layout) { |
| return layout->getKind() == Kind::Struct; |
| } |
| }; |
| |
| /// Emit the address of the 'parent' slot in the given nominal-type metadata. |
| Address emitAddressOfParentMetadataSlot(IRGenFunction &IGF, |
| llvm::Value *metadata, |
| NominalTypeDecl *decl); |
| |
| /// Emit the address of the field-offset slot in the given class metadata. |
| Address emitAddressOfClassFieldOffset(IRGenFunction &IGF, |
| llvm::Value *metadata, |
| ClassDecl *theClass, |
| VarDecl *field); |
| |
| /// Get the offset to a field offset in the class type metadata. |
| /// |
| /// DEPRECATED: callers should be updated to handle this in a more |
| /// arbitrary fashion. |
| Size getClassFieldOffsetOffset(IRGenModule &IGM, |
| ClassDecl *theClass, |
| VarDecl *field); |
| |
| /// Emit the address of the field-offset vector in the given class or struct |
| /// metadata. |
| Address emitAddressOfFieldOffsetVector(IRGenFunction &IGF, |
| llvm::Value *metadata, |
| NominalTypeDecl *theDecl); |
| |
| } // end namespace irgen |
| } // end namespace swift |
| |
| #endif |