| //===--- MetadataValues.h - Compiler/runtime ABI Metadata -------*- 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 |
| // |
| //===----------------------------------------------------------------------===// |
| // |
| // This header is shared between the runtime and the compiler and |
| // includes target-independent information which can be usefully shared |
| // between them. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #ifndef SWIFT_ABI_METADATAVALUES_H |
| #define SWIFT_ABI_METADATAVALUES_H |
| |
| #include "swift/AST/Ownership.h" |
| #include "swift/Runtime/Unreachable.h" |
| |
| #include <stdlib.h> |
| #include <stdint.h> |
| |
| namespace swift { |
| |
| struct InProcess; |
| template <typename Runtime> struct TargetMetadata; |
| using Metadata = TargetMetadata<InProcess>; |
| |
| /// Kinds of Swift metadata records. Some of these are types, some |
| /// aren't. |
| enum class MetadataKind : uint32_t { |
| #define METADATAKIND(name, value) name = value, |
| #define ABSTRACTMETADATAKIND(name, start, end) \ |
| name##_Start = start, name##_End = end, |
| #include "MetadataKind.def" |
| }; |
| |
| const unsigned LastEnumeratedMetadataKind = 2047; |
| |
| /// Try to translate the 'isa' value of a type/heap metadata into a value |
| /// of the MetadataKind enum. |
| inline MetadataKind getEnumeratedMetadataKind(uint64_t kind) { |
| if (kind > LastEnumeratedMetadataKind) |
| return MetadataKind::Class; |
| return MetadataKind(kind); |
| } |
| |
| /// Kinds of Swift nominal type descriptor records. |
| enum class NominalTypeKind : uint32_t { |
| #define NOMINALTYPEMETADATAKIND(name, value) name = value, |
| #include "MetadataKind.def" |
| }; |
| |
| /// Flags for dynamic-cast operations. |
| enum class DynamicCastFlags : size_t { |
| /// All flags clear. |
| Default = 0x0, |
| |
| /// True if the cast is not permitted to fail. |
| Unconditional = 0x1, |
| |
| /// True if the cast should 'take' the source value on success; |
| /// false if the value should be copied. |
| TakeOnSuccess = 0x2, |
| |
| /// True if the cast should destroy the source value on failure; |
| /// false if the value should be left in place. |
| DestroyOnFailure = 0x4, |
| }; |
| inline bool operator&(DynamicCastFlags a, DynamicCastFlags b) { |
| return (size_t(a) & size_t(b)) != 0; |
| } |
| inline DynamicCastFlags operator|(DynamicCastFlags a, DynamicCastFlags b) { |
| return DynamicCastFlags(size_t(a) | size_t(b)); |
| } |
| inline DynamicCastFlags operator-(DynamicCastFlags a, DynamicCastFlags b) { |
| return DynamicCastFlags(size_t(a) & ~size_t(b)); |
| } |
| inline DynamicCastFlags &operator|=(DynamicCastFlags &a, DynamicCastFlags b) { |
| return a = (a | b); |
| } |
| |
| /// Swift class flags. |
| enum class ClassFlags : uint32_t { |
| /// Is this a Swift 1 class? |
| IsSwift1 = 0x1, |
| |
| /// Does this class use Swift 1.0 refcounting? |
| UsesSwift1Refcounting = 0x2, |
| |
| /// Has this class a custom name, specified with the @objc attribute? |
| HasCustomObjCName = 0x4 |
| }; |
| inline bool operator&(ClassFlags a, ClassFlags b) { |
| return (uint32_t(a) & uint32_t(b)) != 0; |
| } |
| inline ClassFlags operator|(ClassFlags a, ClassFlags b) { |
| return ClassFlags(uint32_t(a) | uint32_t(b)); |
| } |
| inline ClassFlags &operator|=(ClassFlags &a, ClassFlags b) { |
| return a = (a | b); |
| } |
| |
| /// Flags that go in a MethodDescriptor structure. |
| class MethodDescriptorFlags { |
| public: |
| typedef uint32_t int_type; |
| enum class Kind { |
| Method, |
| Init, |
| Getter, |
| Setter, |
| MaterializeForSet, |
| }; |
| |
| private: |
| enum : int_type { |
| KindMask = 0x0F, // 16 kinds should be enough for anybody |
| IsInstanceMask = 0x10, |
| IsDynamicMask = 0x20, |
| }; |
| |
| int_type Value; |
| |
| public: |
| MethodDescriptorFlags(Kind kind) : Value(unsigned(kind)) {} |
| |
| MethodDescriptorFlags withIsInstance(bool isInstance) const { |
| auto copy = *this; |
| if (isInstance) { |
| copy.Value |= IsInstanceMask; |
| } else { |
| copy.Value &= ~IsInstanceMask; |
| } |
| return copy; |
| } |
| |
| MethodDescriptorFlags withIsDynamic(bool isDynamic) const { |
| auto copy = *this; |
| if (isDynamic) |
| copy.Value |= IsDynamicMask; |
| else |
| copy.Value &= ~IsDynamicMask; |
| return copy; |
| } |
| |
| Kind getKind() const { return Kind(Value & KindMask); } |
| |
| /// Is the method marked 'dynamic'? |
| bool isDynamic() const { return Value & IsDynamicMask; } |
| |
| /// Is the method an instance member? |
| /// |
| /// Note that 'init' is not considered an instance member. |
| bool isInstance() const { return Value & IsInstanceMask; } |
| |
| int_type getIntValue() const { return Value; } |
| }; |
| |
| enum : unsigned { |
| /// Number of words reserved in generic metadata patterns. |
| NumGenericMetadataPrivateDataWords = 16, |
| }; |
| |
| /// Kinds of type metadata/protocol conformance records. |
| enum class TypeMetadataRecordKind : unsigned { |
| /// The conformance is universal and might apply to any type. |
| /// getDirectType() is nil. |
| Universal, |
| |
| /// The conformance is for a nongeneric native struct or enum type. |
| /// getDirectType() points to the canonical metadata for the type. |
| UniqueDirectType, |
| |
| /// The conformance is for a nongeneric foreign struct or enum type. |
| /// getDirectType() points to a nonunique metadata record for the type, which |
| /// needs to be uniqued by the runtime. |
| NonuniqueDirectType, |
| |
| /// The conformance is for a nongeneric class type. |
| /// getIndirectClass() points to a variable that contains the pointer to the |
| /// class object, which may be ObjC and thus require a runtime call to get |
| /// metadata. |
| /// |
| /// On platforms without ObjC interop, this indirection isn't necessary, |
| /// and classes could be emitted as UniqueDirectType. |
| UniqueIndirectClass, |
| |
| /// The conformance is for a generic or resilient type. |
| /// getNominalTypeDescriptor() points to the nominal type descriptor shared |
| /// by all metadata instantiations of this type. |
| UniqueNominalTypeDescriptor, |
| |
| /// The conformance is for a nongeneric class type. |
| /// getDirectType() points to the unique class object. |
| /// |
| /// FIXME: This shouldn't exist. On ObjC interop platforms, class references |
| /// must be indirected (using UniqueIndirectClass). On non-ObjC interop |
| /// platforms, the class object always is the type metadata. |
| UniqueDirectClass = 0xF, |
| }; |
| |
| /// Kinds of reference to protocol conformance. |
| enum class ProtocolConformanceReferenceKind : unsigned { |
| /// A direct reference to a protocol witness table. |
| WitnessTable, |
| /// A function pointer that can be called to access the protocol witness |
| /// table. |
| WitnessTableAccessor, |
| }; |
| |
| // Type metadata record discriminant |
| struct TypeMetadataRecordFlags { |
| protected: |
| using int_type = unsigned; |
| int_type Data; |
| |
| enum : int_type { |
| TypeKindMask = 0x0000000FU, |
| TypeKindShift = 0, |
| }; |
| |
| public: |
| constexpr TypeMetadataRecordFlags() : Data(0) {} |
| constexpr TypeMetadataRecordFlags(int_type Data) : Data(Data) {} |
| |
| constexpr TypeMetadataRecordKind getTypeKind() const { |
| return TypeMetadataRecordKind((Data & TypeKindMask) >> TypeKindShift); |
| } |
| constexpr TypeMetadataRecordFlags withTypeKind( |
| TypeMetadataRecordKind ptk) const { |
| return TypeMetadataRecordFlags( |
| (Data & ~TypeKindMask) | (int_type(ptk) << TypeKindShift)); |
| } |
| |
| int_type getValue() const { return Data; } |
| }; |
| |
| // Protocol conformance discriminant |
| struct ProtocolConformanceFlags : public TypeMetadataRecordFlags { |
| private: |
| enum : int_type { |
| ConformanceKindMask = 0x00000010U, |
| ConformanceKindShift = 4, |
| }; |
| |
| public: |
| constexpr ProtocolConformanceFlags() : TypeMetadataRecordFlags(0) {} |
| constexpr ProtocolConformanceFlags(int_type Data) : TypeMetadataRecordFlags(Data) {} |
| |
| constexpr ProtocolConformanceFlags withTypeKind( |
| TypeMetadataRecordKind ptk) const { |
| return ProtocolConformanceFlags( |
| (Data & ~TypeKindMask) | (int_type(ptk) << TypeKindShift)); |
| } |
| constexpr ProtocolConformanceReferenceKind getConformanceKind() const { |
| return ProtocolConformanceReferenceKind((Data & ConformanceKindMask) |
| >> ConformanceKindShift); |
| } |
| constexpr ProtocolConformanceFlags withConformanceKind( |
| ProtocolConformanceReferenceKind pck) const { |
| return ProtocolConformanceFlags( |
| (Data & ~ConformanceKindMask) | (int_type(pck) << ConformanceKindShift)); |
| } |
| }; |
| |
| /// Flag that indicates whether an existential type is class-constrained or not. |
| enum class ProtocolClassConstraint : bool { |
| /// The protocol is class-constrained, so only class types can conform to it. |
| /// |
| /// This must be 0 for ABI compatibility with Objective-C protocol_t records. |
| Class = false, |
| /// Any type can conform to the protocol. |
| Any = true, |
| }; |
| |
| /// Identifiers for protocols with special meaning to the Swift runtime. |
| enum class SpecialProtocol: uint8_t { |
| /// Not a special protocol. |
| /// |
| /// This must be 0 for ABI compatibility with Objective-C protocol_t records. |
| None = 0, |
| /// The Error protocol. |
| Error = 1, |
| }; |
| |
| /// Identifiers for protocol method dispatch strategies. |
| enum class ProtocolDispatchStrategy: uint8_t { |
| /// Uses ObjC method dispatch. |
| /// |
| /// This must be 0 for ABI compatibility with Objective-C protocol_t records. |
| ObjC = 0, |
| |
| /// Uses Swift protocol witness table dispatch. |
| /// |
| /// To invoke methods of this protocol, a pointer to a protocol witness table |
| /// corresponding to the protocol conformance must be available. |
| Swift = 1, |
| }; |
| |
| /// Flags in a generic nominal type descriptor. |
| class GenericParameterDescriptorFlags { |
| typedef uint16_t int_type; |
| enum : int_type { |
| HasVTable = 0x0004, |
| }; |
| int_type Data; |
| |
| constexpr GenericParameterDescriptorFlags(int_type data) : Data(data) {} |
| public: |
| constexpr GenericParameterDescriptorFlags() : Data(0) {} |
| |
| constexpr GenericParameterDescriptorFlags withHasVTable(bool b) const { |
| return GenericParameterDescriptorFlags(b ? (Data | HasVTable) |
| : (Data & ~HasVTable)); |
| } |
| |
| /// If this type is a class, does it have a vtable? If so, the number |
| /// of vtable entries immediately follows the generic requirement |
| /// descriptor. |
| bool hasVTable() const { |
| return Data & HasVTable; |
| } |
| |
| int_type getIntValue() const { |
| return Data; |
| } |
| |
| static GenericParameterDescriptorFlags fromIntValue(int_type Data) { |
| return GenericParameterDescriptorFlags(Data); |
| } |
| |
| bool operator==(GenericParameterDescriptorFlags other) const { |
| return Data == other.Data; |
| } |
| bool operator!=(GenericParameterDescriptorFlags other) const { |
| return Data != other.Data; |
| } |
| }; |
| |
| |
| /// Flags for protocol descriptors. |
| class ProtocolDescriptorFlags { |
| typedef uint32_t int_type; |
| enum : int_type { |
| IsSwift = 1U << 0U, |
| ClassConstraint = 1U << 1U, |
| |
| DispatchStrategyMask = 0xFU << 2U, |
| DispatchStrategyShift = 2, |
| |
| SpecialProtocolMask = 0x000003C0U, |
| SpecialProtocolShift = 6, |
| |
| IsResilient = 1U << 10U, |
| |
| /// Reserved by the ObjC runtime. |
| _ObjCReserved = 0xFFFF0000U, |
| }; |
| |
| int_type Data; |
| |
| constexpr ProtocolDescriptorFlags(int_type Data) : Data(Data) {} |
| public: |
| constexpr ProtocolDescriptorFlags() : Data(0) {} |
| constexpr ProtocolDescriptorFlags withSwift(bool s) const { |
| return ProtocolDescriptorFlags((Data & ~IsSwift) | (s ? IsSwift : 0)); |
| } |
| constexpr ProtocolDescriptorFlags withClassConstraint( |
| ProtocolClassConstraint c) const { |
| return ProtocolDescriptorFlags((Data & ~ClassConstraint) |
| | (bool(c) ? ClassConstraint : 0)); |
| } |
| constexpr ProtocolDescriptorFlags withDispatchStrategy( |
| ProtocolDispatchStrategy s) const { |
| return ProtocolDescriptorFlags((Data & ~DispatchStrategyMask) |
| | (int_type(s) << DispatchStrategyShift)); |
| } |
| constexpr ProtocolDescriptorFlags |
| withSpecialProtocol(SpecialProtocol sp) const { |
| return ProtocolDescriptorFlags((Data & ~SpecialProtocolMask) |
| | (int_type(sp) << SpecialProtocolShift)); |
| } |
| constexpr ProtocolDescriptorFlags withResilient(bool s) const { |
| return ProtocolDescriptorFlags((Data & ~IsResilient) | (s ? IsResilient : 0)); |
| } |
| |
| /// Was the protocol defined in Swift 1 or 2? |
| bool isSwift() const { return Data & IsSwift; } |
| |
| /// Is the protocol class-constrained? |
| ProtocolClassConstraint getClassConstraint() const { |
| return ProtocolClassConstraint(bool(Data & ClassConstraint)); |
| } |
| |
| /// What dispatch strategy does this protocol use? |
| ProtocolDispatchStrategy getDispatchStrategy() const { |
| return ProtocolDispatchStrategy((Data & DispatchStrategyMask) |
| >> DispatchStrategyShift); |
| } |
| |
| /// Does the protocol require a witness table for method dispatch? |
| bool needsWitnessTable() const { |
| return needsWitnessTable(getDispatchStrategy()); |
| } |
| |
| static bool needsWitnessTable(ProtocolDispatchStrategy strategy) { |
| switch (strategy) { |
| case ProtocolDispatchStrategy::ObjC: |
| return false; |
| case ProtocolDispatchStrategy::Swift: |
| return true; |
| } |
| |
| swift_runtime_unreachable("Unhandled ProtocolDispatchStrategy in switch."); |
| } |
| |
| /// Return the identifier if this is a special runtime-known protocol. |
| SpecialProtocol getSpecialProtocol() const { |
| return SpecialProtocol(uint8_t((Data & SpecialProtocolMask) |
| >> SpecialProtocolShift)); |
| } |
| |
| /// Can new requirements with default witnesses be added resiliently? |
| bool isResilient() const { return Data & IsResilient; } |
| |
| int_type getIntValue() const { |
| return Data; |
| } |
| }; |
| |
| /// Flags that go in a ProtocolRequirement structure. |
| class ProtocolRequirementFlags { |
| public: |
| typedef uint32_t int_type; |
| enum class Kind { |
| BaseProtocol, |
| Method, |
| Init, |
| Getter, |
| Setter, |
| MaterializeForSet, |
| AssociatedTypeAccessFunction, |
| AssociatedConformanceAccessFunction, |
| }; |
| |
| private: |
| enum : int_type { |
| KindMask = 0x0F, // 16 kinds should be enough for anybody |
| IsInstanceMask = 0x10, |
| }; |
| |
| int_type Value; |
| |
| public: |
| ProtocolRequirementFlags(Kind kind) : Value(unsigned(kind)) {} |
| |
| ProtocolRequirementFlags withIsInstance(bool isInstance) const { |
| auto copy = *this; |
| if (isInstance) { |
| copy.Value |= IsInstanceMask; |
| } else { |
| copy.Value &= ~IsInstanceMask; |
| } |
| return copy; |
| } |
| |
| Kind getKind() const { return Kind(Value & KindMask); } |
| |
| /// Is the method an instance member? |
| /// |
| /// Note that 'init' is not considered an instance member. |
| bool isInstance() const { return Value & IsInstanceMask; } |
| |
| int_type getIntValue() const { return Value; } |
| }; |
| |
| /// Flags in an existential type metadata record. |
| class ExistentialTypeFlags { |
| typedef size_t int_type; |
| enum : int_type { |
| NumWitnessTablesMask = 0x00FFFFFFU, |
| ClassConstraintMask = 0x80000000U, |
| HasSuperclassMask = 0x40000000U, |
| SpecialProtocolMask = 0x3F000000U, |
| SpecialProtocolShift = 24U, |
| }; |
| int_type Data; |
| |
| public: |
| constexpr ExistentialTypeFlags(int_type Data) : Data(Data) {} |
| constexpr ExistentialTypeFlags() : Data(0) {} |
| constexpr ExistentialTypeFlags withNumWitnessTables(unsigned numTables) const { |
| return ExistentialTypeFlags((Data & ~NumWitnessTablesMask) | numTables); |
| } |
| constexpr ExistentialTypeFlags |
| withClassConstraint(ProtocolClassConstraint c) const { |
| return ExistentialTypeFlags((Data & ~ClassConstraintMask) |
| | (bool(c) ? ClassConstraintMask : 0)); |
| } |
| constexpr ExistentialTypeFlags |
| withHasSuperclass(bool hasSuperclass) const { |
| return ExistentialTypeFlags((Data & ~HasSuperclassMask) |
| | (hasSuperclass ? HasSuperclassMask : 0)); |
| } |
| constexpr ExistentialTypeFlags |
| withSpecialProtocol(SpecialProtocol sp) const { |
| return ExistentialTypeFlags((Data & ~SpecialProtocolMask) |
| | (int_type(sp) << SpecialProtocolShift)); |
| } |
| |
| unsigned getNumWitnessTables() const { |
| return Data & NumWitnessTablesMask; |
| } |
| |
| ProtocolClassConstraint getClassConstraint() const { |
| return ProtocolClassConstraint(bool(Data & ClassConstraintMask)); |
| } |
| |
| bool hasSuperclassConstraint() const { |
| return bool(Data & HasSuperclassMask); |
| } |
| |
| /// Return whether this existential type represents an uncomposed special |
| /// protocol. |
| SpecialProtocol getSpecialProtocol() const { |
| return SpecialProtocol(uint8_t((Data & SpecialProtocolMask) |
| >> SpecialProtocolShift)); |
| } |
| |
| int_type getIntValue() const { |
| return Data; |
| } |
| }; |
| |
| /// Convention values for function type metadata. |
| enum class FunctionMetadataConvention: uint8_t { |
| Swift = 0, |
| Block = 1, |
| Thin = 2, |
| CFunctionPointer = 3, |
| }; |
| |
| /// Flags in a function type metadata record. |
| template <typename int_type> |
| class TargetFunctionTypeFlags { |
| enum : int_type { |
| NumArgumentsMask = 0x00FFFFFFU, |
| ConventionMask = 0x0F000000U, |
| ConventionShift = 24U, |
| ThrowsMask = 0x10000000U, |
| }; |
| int_type Data; |
| |
| constexpr TargetFunctionTypeFlags(int_type Data) : Data(Data) {} |
| public: |
| constexpr TargetFunctionTypeFlags() : Data(0) {} |
| |
| constexpr TargetFunctionTypeFlags withNumArguments(unsigned numArguments) const { |
| return TargetFunctionTypeFlags((Data & ~NumArgumentsMask) | numArguments); |
| } |
| |
| constexpr TargetFunctionTypeFlags<int_type> |
| withConvention(FunctionMetadataConvention c) const { |
| return TargetFunctionTypeFlags((Data & ~ConventionMask) |
| | (int_type(c) << ConventionShift)); |
| } |
| |
| constexpr TargetFunctionTypeFlags<int_type> |
| withThrows(bool throws) const { |
| return TargetFunctionTypeFlags<int_type>((Data & ~ThrowsMask) | |
| (throws ? ThrowsMask : 0)); |
| } |
| |
| unsigned getNumArguments() const { |
| return Data & NumArgumentsMask; |
| } |
| |
| FunctionMetadataConvention getConvention() const { |
| return FunctionMetadataConvention((Data&ConventionMask) >> ConventionShift); |
| } |
| |
| bool throws() const { |
| return bool(Data & ThrowsMask); |
| } |
| |
| int_type getIntValue() const { |
| return Data; |
| } |
| |
| static TargetFunctionTypeFlags<int_type> fromIntValue(int_type Data) { |
| return TargetFunctionTypeFlags(Data); |
| } |
| |
| bool operator==(TargetFunctionTypeFlags<int_type> other) const { |
| return Data == other.Data; |
| } |
| bool operator!=(TargetFunctionTypeFlags<int_type> other) const { |
| return Data != other.Data; |
| } |
| }; |
| using FunctionTypeFlags = TargetFunctionTypeFlags<size_t>; |
| |
| /// Field types and flags as represented in a nominal type's field/case type |
| /// vector. |
| class FieldType { |
| typedef uintptr_t int_type; |
| // Type metadata is always at least pointer-aligned, so we get at least two |
| // low bits to stash flags. We could use three low bits on 64-bit, and maybe |
| // some high bits as well. |
| enum : int_type { |
| Indirect = 1, |
| Weak = 2, |
| |
| TypeMask = ((uintptr_t)-1) & ~(alignof(void*) - 1), |
| }; |
| int_type Data; |
| |
| constexpr FieldType(int_type Data) : Data(Data) {} |
| public: |
| constexpr FieldType() : Data(0) {} |
| FieldType withType(const Metadata *T) const { |
| return FieldType((Data & ~TypeMask) | (uintptr_t)T); |
| } |
| |
| constexpr FieldType withIndirect(bool indirect) const { |
| return FieldType((Data & ~Indirect) |
| | (indirect ? Indirect : 0)); |
| } |
| |
| constexpr FieldType withWeak(bool weak) const { |
| return FieldType((Data & ~Weak) |
| | (weak ? Weak : 0)); |
| } |
| |
| bool isIndirect() const { |
| return bool(Data & Indirect); |
| } |
| |
| bool isWeak() const { |
| return bool(Data & Weak); |
| } |
| |
| const Metadata *getType() const { |
| return (const Metadata *)(Data & TypeMask); |
| } |
| |
| int_type getIntValue() const { |
| return Data; |
| } |
| }; |
| |
| /// Flags for exclusivity-checking operations. |
| enum class ExclusivityFlags : uintptr_t { |
| Read = 0x0, |
| Modify = 0x1, |
| // Leave space for other actions. |
| // Don't rely on ActionMask in stable ABI. |
| ActionMask = 0x1, |
| |
| // Downgrade exclusivity failures to a warning. |
| WarningOnly = 0x10 |
| }; |
| static inline ExclusivityFlags operator|(ExclusivityFlags lhs, |
| ExclusivityFlags rhs) { |
| return ExclusivityFlags(uintptr_t(lhs) | uintptr_t(rhs)); |
| } |
| static inline ExclusivityFlags &operator|=(ExclusivityFlags &lhs, |
| ExclusivityFlags rhs) { |
| return (lhs = (lhs | rhs)); |
| } |
| static inline ExclusivityFlags getAccessAction(ExclusivityFlags flags) { |
| return ExclusivityFlags(uintptr_t(flags) |
| & uintptr_t(ExclusivityFlags::ActionMask)); |
| } |
| static inline bool isWarningOnly(ExclusivityFlags flags) { |
| return uintptr_t(flags) & uintptr_t(ExclusivityFlags::WarningOnly); |
| } |
| |
| } // end namespace swift |
| |
| #endif /* SWIFT_ABI_METADATAVALUES_H */ |