| //===--- 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/Basic/LLVM.h" |
| #include "swift/Basic/FlagSet.h" |
| #include "swift/Runtime/Unreachable.h" |
| |
| #include <stdlib.h> |
| #include <stdint.h> |
| |
| namespace swift { |
| |
| enum { |
| /// The number of words (pointers) in a value buffer. |
| NumWords_ValueBuffer = 3, |
| |
| /// The number of words in a metadata completion context. |
| NumWords_MetadataCompletionContext = 4, |
| |
| /// The number of words in a yield-once coroutine buffer. |
| NumWords_YieldOnceBuffer = 4, |
| |
| /// The number of words in a yield-many coroutine buffer. |
| NumWords_YieldManyBuffer = 8, |
| }; |
| |
| struct InProcess; |
| template <typename Runtime> struct TargetMetadata; |
| using Metadata = TargetMetadata<InProcess>; |
| |
| /// Non-type metadata kinds have this bit set. |
| const unsigned MetadataKindIsNonType = 0x400; |
| |
| /// Non-heap metadata kinds have this bit set. |
| const unsigned MetadataKindIsNonHeap = 0x200; |
| |
| // The above two flags are negative because the "class" kind has to be zero, |
| // and class metadata is both type and heap metadata. |
| |
| /// Runtime-private metadata has this bit set. The compiler must not statically |
| /// generate metadata objects with these kinds, and external tools should not |
| /// rely on the stability of these values or the precise binary layout of |
| /// their associated data structures. |
| const unsigned MetadataKindIsRuntimePrivate = 0x100; |
| |
| /// 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" |
| |
| /// The largest possible non-isa-pointer metadata kind value. |
| /// |
| /// This is included in the enumeration to prevent against attempts to |
| /// exhaustively match metadata kinds. Future Swift runtimes or compilers |
| /// may introduce new metadata kinds, so for forward compatibility, the |
| /// runtime must tolerate metadata with unknown kinds. |
| /// This specific value is not mapped to a valid metadata kind at this time, |
| /// however. |
| LastEnumerated = 0x7FF, |
| }; |
| |
| const unsigned LastEnumeratedMetadataKind = |
| (unsigned)MetadataKind::LastEnumerated; |
| |
| inline bool isHeapMetadataKind(MetadataKind k) { |
| return !((uint32_t)k & MetadataKindIsNonHeap); |
| } |
| inline bool isTypeMetadataKind(MetadataKind k) { |
| return !((uint32_t)k & MetadataKindIsNonType); |
| } |
| inline bool isRuntimePrivateMetadataKind(MetadataKind k) { |
| return (uint32_t)k & MetadataKindIsRuntimePrivate; |
| } |
| |
| /// 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); |
| } |
| |
| StringRef getStringForMetadataKind(MetadataKind kind); |
| |
| /// Kinds of Swift nominal type descriptor records. |
| enum class NominalTypeKind : uint32_t { |
| #define NOMINALTYPEMETADATAKIND(name, value) name = value, |
| #include "MetadataKind.def" |
| }; |
| |
| /// The maximum supported type alignment. |
| const size_t MaximumAlignment = 16; |
| |
| /// Flags stored in the value-witness table. |
| template <typename int_type> |
| class TargetValueWitnessFlags { |
| public: |
| // The polarity of these bits is chosen so that, when doing struct layout, the |
| // flags of the field types can be mostly bitwise-or'ed together to derive the |
| // flags for the struct. (The "non-inline" and "has-extra-inhabitants" bits |
| // still require additional fixup.) |
| enum : uint32_t { |
| AlignmentMask = 0x000000FF, |
| // unused 0x0000FF00, |
| IsNonPOD = 0x00010000, |
| IsNonInline = 0x00020000, |
| // unused 0x00040000, |
| HasSpareBits = 0x00080000, |
| IsNonBitwiseTakable = 0x00100000, |
| HasEnumWitnesses = 0x00200000, |
| Incomplete = 0x00400000, |
| // unused 0xFF800000, |
| }; |
| |
| static constexpr const uint32_t MaxNumExtraInhabitants = 0x7FFFFFFF; |
| |
| private: |
| uint32_t Data; |
| |
| explicit constexpr TargetValueWitnessFlags(uint32_t data) : Data(data) {} |
| |
| public: |
| constexpr TargetValueWitnessFlags() : Data(0) {} |
| |
| /// The required alignment of the first byte of an object of this |
| /// type, expressed as a mask of the low bits that must not be set |
| /// in the pointer. |
| /// |
| /// This representation can be easily converted to the 'alignof' |
| /// result by merely adding 1, but it is more directly useful for |
| /// performing dynamic structure layouts, and it grants an |
| /// additional bit of precision in a compact field without needing |
| /// to switch to an exponent representation. |
| /// |
| /// For example, if the type needs to be 8-byte aligned, the |
| /// appropriate alignment mask should be 0x7. |
| size_t getAlignmentMask() const { |
| return (Data & AlignmentMask); |
| } |
| constexpr TargetValueWitnessFlags withAlignmentMask(size_t alignMask) const { |
| return TargetValueWitnessFlags((Data & ~AlignmentMask) | alignMask); |
| } |
| |
| size_t getAlignment() const { return getAlignmentMask() + 1; } |
| constexpr TargetValueWitnessFlags withAlignment(size_t alignment) const { |
| return withAlignmentMask(alignment - 1); |
| } |
| |
| /// True if the type requires out-of-line allocation of its storage. |
| /// This can be the case because the value requires more storage or if it is |
| /// not bitwise takable. |
| bool isInlineStorage() const { return !(Data & IsNonInline); } |
| constexpr TargetValueWitnessFlags withInlineStorage(bool isInline) const { |
| return TargetValueWitnessFlags((Data & ~IsNonInline) | |
| (isInline ? 0 : IsNonInline)); |
| } |
| |
| /// True if values of this type can be copied with memcpy and |
| /// destroyed with a no-op. |
| bool isPOD() const { return !(Data & IsNonPOD); } |
| constexpr TargetValueWitnessFlags withPOD(bool isPOD) const { |
| return TargetValueWitnessFlags((Data & ~IsNonPOD) | |
| (isPOD ? 0 : IsNonPOD)); |
| } |
| |
| /// True if values of this type can be taken with memcpy. Unlike C++ 'move', |
| /// 'take' is a destructive operation that invalidates the source object, so |
| /// most types can be taken with a simple bitwise copy. Only types with side |
| /// table references, like @weak references, or types with opaque value |
| /// semantics, like imported C++ types, are not bitwise-takable. |
| bool isBitwiseTakable() const { return !(Data & IsNonBitwiseTakable); } |
| constexpr TargetValueWitnessFlags withBitwiseTakable(bool isBT) const { |
| return TargetValueWitnessFlags((Data & ~IsNonBitwiseTakable) | |
| (isBT ? 0 : IsNonBitwiseTakable)); |
| } |
| |
| /// True if this type's binary representation is that of an enum, and the |
| /// enum value witness table entries are available in this type's value |
| /// witness table. |
| bool hasEnumWitnesses() const { return Data & HasEnumWitnesses; } |
| constexpr TargetValueWitnessFlags |
| withEnumWitnesses(bool hasEnumWitnesses) const { |
| return TargetValueWitnessFlags((Data & ~HasEnumWitnesses) | |
| (hasEnumWitnesses ? HasEnumWitnesses : 0)); |
| } |
| |
| /// True if the type with this value-witness table is incomplete, |
| /// meaning that its external layout (size, etc.) is meaningless |
| /// pending completion of the metadata layout. |
| bool isIncomplete() const { return Data & Incomplete; } |
| constexpr TargetValueWitnessFlags |
| withIncomplete(bool isIncomplete) const { |
| return TargetValueWitnessFlags((Data & ~Incomplete) | |
| (isIncomplete ? Incomplete : 0)); |
| } |
| |
| constexpr uint32_t getOpaqueValue() const { |
| return Data; |
| } |
| }; |
| using ValueWitnessFlags = TargetValueWitnessFlags<size_t>; |
| |
| /// 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. |
| /// These flags are valid only when isTypeMetadata(). |
| /// When !isTypeMetadata() these flags will collide with other Swift ABIs. |
| enum class ClassFlags : uint32_t { |
| /// Is this a Swift class from the Darwin pre-stable ABI? |
| /// This bit is clear in stable ABI Swift classes. |
| /// The Objective-C runtime also reads this bit. |
| IsSwiftPreStableABI = 0x1, |
| |
| /// Does this class use Swift refcounting? |
| UsesSwiftRefcounting = 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, |
| ModifyCoroutine, |
| ReadCoroutine, |
| }; |
| |
| 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 TypeReferenceKind : unsigned { |
| /// The conformance is for a nominal type referenced directly; |
| /// getTypeDescriptor() points to the type context descriptor. |
| DirectTypeDescriptor = 0x00, |
| |
| /// The conformance is for a nominal type referenced indirectly; |
| /// getTypeDescriptor() points to the type context descriptor. |
| IndirectTypeDescriptor = 0x01, |
| |
| /// The conformance is for an Objective-C class that should be looked up |
| /// by class name. |
| DirectObjCClassName = 0x02, |
| |
| /// The conformance is for an Objective-C class that has no nominal type |
| /// descriptor. |
| /// getIndirectObjCClass() points to a variable that contains the pointer to |
| /// the class object, which then requires a runtime call to get metadata. |
| /// |
| /// On platforms without Objective-C interoperability, this case is |
| /// unused. |
| IndirectObjCClass = 0x03, |
| |
| // We only reserve three bits for this in the various places we store it. |
| |
| First_Kind = DirectTypeDescriptor, |
| Last_Kind = IndirectObjCClass, |
| }; |
| |
| /// 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 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; |
| } |
| |
| #ifndef NDEBUG |
| LLVM_ATTRIBUTE_DEPRECATED(void dump() const LLVM_ATTRIBUTE_USED, |
| "Only for use in the debugger"); |
| #endif |
| }; |
| |
| /// Flags that go in a ProtocolRequirement structure. |
| class ProtocolRequirementFlags { |
| public: |
| typedef uint32_t int_type; |
| enum class Kind { |
| BaseProtocol, |
| Method, |
| Init, |
| Getter, |
| Setter, |
| ReadCoroutine, |
| ModifyCoroutine, |
| 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; } |
| |
| enum : uintptr_t { |
| /// Bit used to indicate that an associated type witness is a pointer to |
| /// a mangled name (vs. a pointer to metadata). |
| AssociatedTypeMangledNameBit = 0x01, |
| }; |
| |
| enum : uint8_t { |
| /// Prefix byte used to identify an associated type whose mangled name |
| /// is relative to the protocol's context rather than the conforming |
| /// type's context. |
| AssociatedTypeInProtocolContextByte = 0xFF |
| }; |
| }; |
| |
| /// Flags that go in a TargetConformanceDescriptor structure. |
| class ConformanceFlags { |
| public: |
| typedef uint32_t int_type; |
| |
| private: |
| enum : int_type { |
| UnusedLowBits = 0x07, // historical conformance kind |
| |
| TypeMetadataKindMask = 0x7 << 3, // 8 type reference kinds |
| TypeMetadataKindShift = 3, |
| |
| IsRetroactiveMask = 0x01 << 6, |
| IsSynthesizedNonUniqueMask = 0x01 << 7, |
| |
| NumConditionalRequirementsMask = 0xFF << 8, |
| NumConditionalRequirementsShift = 8, |
| |
| HasResilientWitnessesMask = 0x01 << 16, |
| HasGenericWitnessTableMask = 0x01 << 17, |
| }; |
| |
| int_type Value; |
| |
| public: |
| ConformanceFlags(int_type value = 0) : Value(value) {} |
| |
| ConformanceFlags withTypeReferenceKind(TypeReferenceKind kind) const { |
| return ConformanceFlags((Value & ~TypeMetadataKindMask) |
| | (int_type(kind) << TypeMetadataKindShift)); |
| } |
| |
| ConformanceFlags withIsRetroactive(bool isRetroactive) const { |
| return ConformanceFlags((Value & ~IsRetroactiveMask) |
| | (isRetroactive? IsRetroactiveMask : 0)); |
| } |
| |
| ConformanceFlags withIsSynthesizedNonUnique( |
| bool isSynthesizedNonUnique) const { |
| return ConformanceFlags( |
| (Value & ~IsSynthesizedNonUniqueMask) |
| | (isSynthesizedNonUnique ? IsSynthesizedNonUniqueMask : 0)); |
| } |
| |
| ConformanceFlags withNumConditionalRequirements(unsigned n) const { |
| return ConformanceFlags((Value & ~NumConditionalRequirementsMask) |
| | (n << NumConditionalRequirementsShift)); |
| } |
| |
| ConformanceFlags withHasResilientWitnesses(bool hasResilientWitnesses) const { |
| return ConformanceFlags((Value & ~HasResilientWitnessesMask) |
| | (hasResilientWitnesses? HasResilientWitnessesMask |
| : 0)); |
| } |
| |
| ConformanceFlags withHasGenericWitnessTable( |
| bool hasGenericWitnessTable) const { |
| return ConformanceFlags((Value & ~HasGenericWitnessTableMask) |
| | (hasGenericWitnessTable |
| ? HasGenericWitnessTableMask |
| : 0)); |
| } |
| |
| /// Retrieve the type reference kind kind. |
| TypeReferenceKind getTypeReferenceKind() const { |
| return TypeReferenceKind( |
| (Value & TypeMetadataKindMask) >> TypeMetadataKindShift); |
| } |
| |
| /// Is the conformance "retroactive"? |
| /// |
| /// A conformance is retroactive when it occurs in a module that is |
| /// neither the module in which the protocol is defined nor the module |
| /// in which the conforming type is defined. With retroactive conformance, |
| /// it is possible to detect a conflict at run time. |
| bool isRetroactive() const { return Value & IsRetroactiveMask; } |
| |
| /// Is the conformance synthesized in a non-unique manner? |
| /// |
| /// The Swift compiler will synthesize conformances on behalf of some |
| /// imported entities (e.g., C typedefs with the swift_wrapper attribute). |
| /// Such conformances are retroactive by nature, but the presence of multiple |
| /// such conformances is not a conflict because all synthesized conformances |
| /// will be equivalent. |
| bool isSynthesizedNonUnique() const { |
| return Value & IsSynthesizedNonUniqueMask; |
| } |
| |
| /// Retrieve the # of conditional requirements. |
| unsigned getNumConditionalRequirements() const { |
| return (Value & NumConditionalRequirementsMask) |
| >> NumConditionalRequirementsShift; |
| } |
| |
| /// Whether this conformance has any resilient witnesses. |
| bool hasResilientWitnesses() const { |
| return Value & HasResilientWitnessesMask; |
| } |
| |
| /// Whether this conformance has a generic witness table that may need to |
| /// be instantiated. |
| bool hasGenericWitnessTable() const { |
| return Value & HasGenericWitnessTableMask; |
| } |
| |
| int_type getIntValue() const { return Value; } |
| }; |
| |
| /// Flags in an existential type metadata record. |
| class ExistentialTypeFlags { |
| public: |
| typedef uint32_t int_type; |
| |
| private: |
| 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 { |
| // If we were ever to run out of space for function flags (8 bits) |
| // one of the flag bits could be used to identify that the rest of |
| // the flags is going to be stored somewhere else in the metadata. |
| enum : int_type { |
| NumParametersMask = 0x0000FFFFU, |
| ConventionMask = 0x00FF0000U, |
| ConventionShift = 16U, |
| ThrowsMask = 0x01000000U, |
| ParamFlagsMask = 0x02000000U, |
| EscapingMask = 0x04000000U, |
| }; |
| int_type Data; |
| |
| constexpr TargetFunctionTypeFlags(int_type Data) : Data(Data) {} |
| public: |
| constexpr TargetFunctionTypeFlags() : Data(0) {} |
| |
| constexpr TargetFunctionTypeFlags |
| withNumParameters(unsigned numParams) const { |
| return TargetFunctionTypeFlags((Data & ~NumParametersMask) | numParams); |
| } |
| |
| 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)); |
| } |
| |
| constexpr TargetFunctionTypeFlags<int_type> |
| withParameterFlags(bool hasFlags) const { |
| return TargetFunctionTypeFlags<int_type>((Data & ~ParamFlagsMask) | |
| (hasFlags ? ParamFlagsMask : 0)); |
| } |
| |
| constexpr TargetFunctionTypeFlags<int_type> |
| withEscaping(bool isEscaping) const { |
| return TargetFunctionTypeFlags<int_type>((Data & ~EscapingMask) | |
| (isEscaping ? EscapingMask : 0)); |
| } |
| |
| unsigned getNumParameters() const { return Data & NumParametersMask; } |
| |
| FunctionMetadataConvention getConvention() const { |
| return FunctionMetadataConvention((Data&ConventionMask) >> ConventionShift); |
| } |
| |
| bool throws() const { |
| return bool(Data & ThrowsMask); |
| } |
| |
| bool isEscaping() const { |
| return bool (Data & EscapingMask); |
| } |
| |
| bool hasParameterFlags() const { return bool(Data & ParamFlagsMask); } |
| |
| 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>; |
| |
| template <typename int_type> |
| class TargetParameterTypeFlags { |
| enum : int_type { |
| ValueOwnershipMask = 0x7F, |
| VariadicMask = 0x80, |
| AutoClosureMask = 0x100, |
| }; |
| int_type Data; |
| |
| constexpr TargetParameterTypeFlags(int_type Data) : Data(Data) {} |
| |
| public: |
| constexpr TargetParameterTypeFlags() : Data(0) {} |
| |
| constexpr TargetParameterTypeFlags<int_type> |
| withValueOwnership(ValueOwnership ownership) const { |
| return TargetParameterTypeFlags<int_type>((Data & ~ValueOwnershipMask) | |
| (int_type)ownership); |
| } |
| |
| constexpr TargetParameterTypeFlags<int_type> |
| withVariadic(bool isVariadic) const { |
| return TargetParameterTypeFlags<int_type>((Data & ~VariadicMask) | |
| (isVariadic ? VariadicMask : 0)); |
| } |
| |
| constexpr TargetParameterTypeFlags<int_type> |
| withAutoClosure(bool isAutoClosure) const { |
| return TargetParameterTypeFlags<int_type>( |
| (Data & ~AutoClosureMask) | (isAutoClosure ? AutoClosureMask : 0)); |
| } |
| |
| bool isNone() const { return Data == 0; } |
| bool isVariadic() const { return Data & VariadicMask; } |
| bool isAutoClosure() const { return Data & AutoClosureMask; } |
| |
| ValueOwnership getValueOwnership() const { |
| return (ValueOwnership)(Data & ValueOwnershipMask); |
| } |
| |
| int_type getIntValue() const { return Data; } |
| |
| static TargetParameterTypeFlags<int_type> fromIntValue(int_type Data) { |
| return TargetParameterTypeFlags(Data); |
| } |
| |
| bool operator==(TargetParameterTypeFlags<int_type> other) const { |
| return Data == other.Data; |
| } |
| bool operator!=(TargetParameterTypeFlags<int_type> other) const { |
| return Data != other.Data; |
| } |
| }; |
| using ParameterFlags = TargetParameterTypeFlags<uint32_t>; |
| |
| template <typename int_type> |
| class TargetTupleTypeFlags { |
| enum : int_type { |
| NumElementsMask = 0x0000FFFFU, |
| NonConstantLabelsMask = 0x00010000U, |
| }; |
| int_type Data; |
| |
| public: |
| constexpr TargetTupleTypeFlags() : Data(0) {} |
| constexpr TargetTupleTypeFlags(int_type Data) : Data(Data) {} |
| |
| constexpr TargetTupleTypeFlags |
| withNumElements(unsigned numElements) const { |
| return TargetTupleTypeFlags((Data & ~NumElementsMask) | numElements); |
| } |
| |
| constexpr TargetTupleTypeFlags<int_type> withNonConstantLabels( |
| bool hasNonConstantLabels) const { |
| return TargetTupleTypeFlags<int_type>( |
| (Data & ~NonConstantLabelsMask) | |
| (hasNonConstantLabels ? NonConstantLabelsMask : 0)); |
| } |
| |
| unsigned getNumElements() const { return Data & NumElementsMask; } |
| |
| bool hasNonConstantLabels() const { return Data & NonConstantLabelsMask; } |
| |
| int_type getIntValue() const { return Data; } |
| |
| static TargetTupleTypeFlags<int_type> fromIntValue(int_type Data) { |
| return TargetTupleTypeFlags(Data); |
| } |
| |
| bool operator==(TargetTupleTypeFlags<int_type> other) const { |
| return Data == other.Data; |
| } |
| bool operator!=(TargetTupleTypeFlags<int_type> other) const { |
| return Data != other.Data; |
| } |
| }; |
| using TupleTypeFlags = TargetTupleTypeFlags<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, |
| // ActionMask can grow without breaking the ABI because the runtime controls |
| // how these flags are encoded in the "value buffer". However, any additional |
| // actions must be compatible with the original behavior for the old, smaller |
| // ActionMask (older runtimes will continue to treat them as either a simple |
| // Read or Modify). |
| ActionMask = 0x1, |
| |
| // The runtime should track this access to check against subsequent accesses. |
| Tracking = 0x20 |
| }; |
| 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 isTracking(ExclusivityFlags flags) { |
| return uintptr_t(flags) & uintptr_t(ExclusivityFlags::Tracking); |
| } |
| |
| /// Flags for struct layout. |
| enum class StructLayoutFlags : uintptr_t { |
| /// Reserve space for 256 layout algorithms. |
| AlgorithmMask = 0xff, |
| |
| /// The ABI baseline algorithm, i.e. the algorithm implemented in Swift 5. |
| Swift5Algorithm = 0x00, |
| |
| /// Is the value-witness table mutable in place, or does layout need to |
| /// clone it? |
| IsVWTMutable = 0x100, |
| }; |
| static inline StructLayoutFlags operator|(StructLayoutFlags lhs, |
| StructLayoutFlags rhs) { |
| return StructLayoutFlags(uintptr_t(lhs) | uintptr_t(rhs)); |
| } |
| static inline StructLayoutFlags &operator|=(StructLayoutFlags &lhs, |
| StructLayoutFlags rhs) { |
| return (lhs = (lhs | rhs)); |
| } |
| static inline StructLayoutFlags getLayoutAlgorithm(StructLayoutFlags flags) { |
| return StructLayoutFlags(uintptr_t(flags) |
| & uintptr_t(StructLayoutFlags::AlgorithmMask)); |
| } |
| static inline bool isValueWitnessTableMutable(StructLayoutFlags flags) { |
| return uintptr_t(flags) & uintptr_t(StructLayoutFlags::IsVWTMutable); |
| } |
| |
| /// Flags for class layout. |
| enum class ClassLayoutFlags : uintptr_t { |
| /// Reserve space for 256 layout algorithms. |
| AlgorithmMask = 0xff, |
| |
| /// The ABI baseline algorithm, i.e. the algorithm implemented in Swift 5. |
| Swift5Algorithm = 0x00, |
| |
| /// If true, the vtable for this class and all of its superclasses was emitted |
| /// statically in the class metadata. If false, the superclass vtable is |
| /// copied from superclass metadata, and the immediate class vtable is |
| /// initialized from the type context descriptor. |
| HasStaticVTable = 0x100, |
| }; |
| static inline ClassLayoutFlags operator|(ClassLayoutFlags lhs, |
| ClassLayoutFlags rhs) { |
| return ClassLayoutFlags(uintptr_t(lhs) | uintptr_t(rhs)); |
| } |
| static inline ClassLayoutFlags &operator|=(ClassLayoutFlags &lhs, |
| ClassLayoutFlags rhs) { |
| return (lhs = (lhs | rhs)); |
| } |
| static inline ClassLayoutFlags getLayoutAlgorithm(ClassLayoutFlags flags) { |
| return ClassLayoutFlags(uintptr_t(flags) |
| & uintptr_t(ClassLayoutFlags::AlgorithmMask)); |
| } |
| static inline bool hasStaticVTable(ClassLayoutFlags flags) { |
| return uintptr_t(flags) & uintptr_t(ClassLayoutFlags::HasStaticVTable); |
| } |
| |
| /// Flags for enum layout. |
| enum class EnumLayoutFlags : uintptr_t { |
| /// Reserve space for 256 layout algorithms. |
| AlgorithmMask = 0xff, |
| |
| /// The ABI baseline algorithm, i.e. the algorithm implemented in Swift 5. |
| Swift5Algorithm = 0x00, |
| |
| /// Is the value-witness table mutable in place, or does layout need to |
| /// clone it? |
| IsVWTMutable = 0x100, |
| }; |
| static inline EnumLayoutFlags operator|(EnumLayoutFlags lhs, |
| EnumLayoutFlags rhs) { |
| return EnumLayoutFlags(uintptr_t(lhs) | uintptr_t(rhs)); |
| } |
| static inline EnumLayoutFlags &operator|=(EnumLayoutFlags &lhs, |
| EnumLayoutFlags rhs) { |
| return (lhs = (lhs | rhs)); |
| } |
| static inline EnumLayoutFlags getLayoutAlgorithm(EnumLayoutFlags flags) { |
| return EnumLayoutFlags(uintptr_t(flags) |
| & uintptr_t(EnumLayoutFlags::AlgorithmMask)); |
| } |
| static inline bool isValueWitnessTableMutable(EnumLayoutFlags flags) { |
| return uintptr_t(flags) & uintptr_t(EnumLayoutFlags::IsVWTMutable); |
| } |
| |
| /// The number of arguments that will be passed directly to a generic |
| /// nominal type access function. The remaining arguments (if any) will be |
| /// passed as an array. That array has enough storage for all of the arguments, |
| /// but only fills in the elements not passed directly. The callee may |
| /// mutate the array to fill in the direct arguments. |
| constexpr unsigned NumDirectGenericTypeMetadataAccessFunctionArgs = 3; |
| |
| /// The offset (in pointers) to the first requirement in a witness table. |
| constexpr unsigned WitnessTableFirstRequirementOffset = 1; |
| |
| /// Kinds of context descriptor. |
| enum class ContextDescriptorKind : uint8_t { |
| /// This context descriptor represents a module. |
| Module = 0, |
| |
| /// This context descriptor represents an extension. |
| Extension = 1, |
| |
| /// This context descriptor represents an anonymous possibly-generic context |
| /// such as a function body. |
| Anonymous = 2, |
| |
| /// This context descriptor represents a protocol context. |
| Protocol = 3, |
| |
| /// First kind that represents a type of any sort. |
| Type_First = 16, |
| |
| /// This context descriptor represents a class. |
| Class = Type_First, |
| |
| /// This context descriptor represents a struct. |
| Struct = Type_First + 1, |
| |
| /// This context descriptor represents an enum. |
| Enum = Type_First + 2, |
| |
| /// Last kind that represents a type of any sort. |
| Type_Last = 31, |
| }; |
| |
| /// Common flags stored in the first 32-bit word of any context descriptor. |
| struct ContextDescriptorFlags { |
| private: |
| uint32_t Value; |
| |
| explicit constexpr ContextDescriptorFlags(uint32_t Value) |
| : Value(Value) {} |
| public: |
| constexpr ContextDescriptorFlags() : Value(0) {} |
| constexpr ContextDescriptorFlags(ContextDescriptorKind kind, |
| bool isGeneric, |
| bool isUnique, |
| uint8_t version, |
| uint16_t kindSpecificFlags) |
| : ContextDescriptorFlags(ContextDescriptorFlags() |
| .withKind(kind) |
| .withGeneric(isGeneric) |
| .withUnique(isUnique) |
| .withVersion(version) |
| .withKindSpecificFlags(kindSpecificFlags)) |
| {} |
| |
| /// The kind of context this descriptor describes. |
| constexpr ContextDescriptorKind getKind() const { |
| return ContextDescriptorKind(Value & 0x1Fu); |
| } |
| |
| /// Whether the context being described is generic. |
| constexpr bool isGeneric() const { |
| return (Value & 0x80u) != 0; |
| } |
| |
| /// Whether this is a unique record describing the referenced context. |
| constexpr bool isUnique() const { |
| return (Value & 0x40u) != 0; |
| } |
| |
| /// The format version of the descriptor. Higher version numbers may have |
| /// additional fields that aren't present in older versions. |
| constexpr uint8_t getVersion() const { |
| return (Value >> 8u) & 0xFFu; |
| } |
| |
| /// The most significant two bytes of the flags word, which can have |
| /// kind-specific meaning. |
| constexpr uint16_t getKindSpecificFlags() const { |
| return (Value >> 16u) & 0xFFFFu; |
| } |
| |
| constexpr ContextDescriptorFlags withKind(ContextDescriptorKind kind) const { |
| return assert((uint8_t(kind) & 0x1F) == uint8_t(kind)), |
| ContextDescriptorFlags((Value & 0xFFFFFFE0u) | uint8_t(kind)); |
| } |
| |
| constexpr ContextDescriptorFlags withGeneric(bool isGeneric) const { |
| return ContextDescriptorFlags((Value & 0xFFFFFF7Fu) |
| | (isGeneric ? 0x80u : 0)); |
| } |
| |
| constexpr ContextDescriptorFlags withUnique(bool isUnique) const { |
| return ContextDescriptorFlags((Value & 0xFFFFFFBFu) |
| | (isUnique ? 0x40u : 0)); |
| } |
| |
| constexpr ContextDescriptorFlags withVersion(uint8_t version) const { |
| return ContextDescriptorFlags((Value & 0xFFFF00FFu) | (version << 8u)); |
| } |
| |
| constexpr ContextDescriptorFlags |
| withKindSpecificFlags(uint16_t flags) const { |
| return ContextDescriptorFlags((Value & 0xFFFFu) | (flags << 16u)); |
| } |
| |
| constexpr uint32_t getIntValue() const { |
| return Value; |
| } |
| }; |
| |
| /// Flags for nominal type context descriptors. These values are used as the |
| /// kindSpecificFlags of the ContextDescriptorFlags for the type. |
| class TypeContextDescriptorFlags : public FlagSet<uint16_t> { |
| enum { |
| // All of these values are bit offsets or widths. |
| // Generic flags build upwards from 0. |
| // Type-specific flags build downwards from 15. |
| |
| /// Whether there's something unusual about how the metadata is |
| /// initialized. |
| /// |
| /// Meaningful for all type-descriptor kinds. |
| MetadataInitialization = 0, |
| MetadataInitialization_width = 2, |
| |
| /// Set if the type has extended import information. |
| /// |
| /// If true, a sequence of strings follow the null terminator in the |
| /// descriptor, terminated by an empty string (i.e. by two null |
| /// terminators in a row). See TypeImportInfo for the details of |
| /// these strings and the order in which they appear. |
| /// |
| /// Meaningful for all type-descriptor kinds. |
| HasImportInfo = 2, |
| |
| // Type-specific flags: |
| |
| /// The kind of reference that this class makes to its resilient superclass |
| /// descriptor. A TypeReferenceKind. |
| /// |
| /// Only meaningful for class descriptors. |
| Class_ResilientSuperclassReferenceKind = 9, |
| Class_ResilientSuperclassReferenceKind_width = 3, |
| |
| /// Whether the immediate class members in this metadata are allocated |
| /// at negative offsets. For now, we don't use this. |
| Class_AreImmediateMembersNegative = 12, |
| |
| /// Set if the context descriptor is for a class with resilient ancestry. |
| /// |
| /// Only meaningful for class descriptors. |
| Class_HasResilientSuperclass = 13, |
| |
| /// Set if the context descriptor includes metadata for dynamically |
| /// installing method overrides at metadata instantiation time. |
| Class_HasOverrideTable = 14, |
| |
| /// Set if the context descriptor includes metadata for dynamically |
| /// constructing a class's vtables at metadata instantiation time. |
| /// |
| /// Only meaningful for class descriptors. |
| Class_HasVTable = 15, |
| }; |
| |
| public: |
| explicit TypeContextDescriptorFlags(uint16_t bits) : FlagSet(bits) {} |
| constexpr TypeContextDescriptorFlags() {} |
| |
| enum MetadataInitializationKind { |
| /// There are either no special rules for initializing the metadata |
| /// or the metadata is generic. (Genericity is set in the |
| /// non-kind-specific descriptor flags.) |
| NoMetadataInitialization = 0, |
| |
| /// The type requires non-trivial singleton initialization using the |
| /// "in-place" code pattern. |
| SingletonMetadataInitialization = 1, |
| |
| /// The type requires non-trivial singleton initialization using the |
| /// "foreign" code pattern. |
| ForeignMetadataInitialization = 2, |
| |
| // We only have two bits here, so if you add a third special kind, |
| // include more flag bits in its out-of-line storage. |
| }; |
| |
| FLAGSET_DEFINE_FIELD_ACCESSORS(MetadataInitialization, |
| MetadataInitialization_width, |
| MetadataInitializationKind, |
| getMetadataInitialization, |
| setMetadataInitialization) |
| |
| bool hasSingletonMetadataInitialization() const { |
| return getMetadataInitialization() == SingletonMetadataInitialization; |
| } |
| |
| bool hasForeignMetadataInitialization() const { |
| return getMetadataInitialization() == ForeignMetadataInitialization; |
| } |
| |
| FLAGSET_DEFINE_FLAG_ACCESSORS(HasImportInfo, hasImportInfo, setHasImportInfo) |
| |
| FLAGSET_DEFINE_FLAG_ACCESSORS(Class_HasVTable, |
| class_hasVTable, |
| class_setHasVTable) |
| FLAGSET_DEFINE_FLAG_ACCESSORS(Class_HasOverrideTable, |
| class_hasOverrideTable, |
| class_setHasOverrideTable) |
| FLAGSET_DEFINE_FLAG_ACCESSORS(Class_HasResilientSuperclass, |
| class_hasResilientSuperclass, |
| class_setHasResilientSuperclass) |
| FLAGSET_DEFINE_FLAG_ACCESSORS(Class_AreImmediateMembersNegative, |
| class_areImmediateMembersNegative, |
| class_setAreImmediateMembersNegative) |
| |
| FLAGSET_DEFINE_FIELD_ACCESSORS(Class_ResilientSuperclassReferenceKind, |
| Class_ResilientSuperclassReferenceKind_width, |
| TypeReferenceKind, |
| class_getResilientSuperclassReferenceKind, |
| class_setResilientSuperclassReferenceKind) |
| }; |
| |
| /// Extra flags for resilient classes, since we need more than 16 bits of |
| /// flags there. |
| class ExtraClassDescriptorFlags : public FlagSet<uint32_t> { |
| enum { |
| /// Set if the context descriptor includes a pointer to an Objective-C |
| /// resilient class stub structure. See the description of |
| /// TargetObjCResilientClassStubInfo in Metadata.h for details. |
| /// |
| /// Only meaningful for class descriptors when Objective-C interop is |
| /// enabled. |
| HasObjCResilientClassStub = 0, |
| }; |
| |
| public: |
| explicit ExtraClassDescriptorFlags(uint32_t bits) : FlagSet(bits) {} |
| constexpr ExtraClassDescriptorFlags() {} |
| |
| FLAGSET_DEFINE_FLAG_ACCESSORS(HasObjCResilientClassStub, |
| hasObjCResilientClassStub, |
| setObjCResilientClassStub) |
| }; |
| |
| /// Flags for protocol context descriptors. These values are used as the |
| /// kindSpecificFlags of the ContextDescriptorFlags for the protocol. |
| class ProtocolContextDescriptorFlags : public FlagSet<uint16_t> { |
| enum { |
| /// Whether this protocol is class-constrained. |
| HasClassConstraint = 0, |
| HasClassConstraint_width = 1, |
| |
| /// Whether this protocol is resilient. |
| IsResilient = 1, |
| |
| /// Special protocol value. |
| SpecialProtocolKind = 2, |
| SpecialProtocolKind_width = 6, |
| }; |
| |
| public: |
| explicit ProtocolContextDescriptorFlags(uint16_t bits) : FlagSet(bits) {} |
| constexpr ProtocolContextDescriptorFlags() {} |
| |
| FLAGSET_DEFINE_FLAG_ACCESSORS(IsResilient, isResilient, setIsResilient) |
| |
| FLAGSET_DEFINE_FIELD_ACCESSORS(HasClassConstraint, |
| HasClassConstraint_width, |
| ProtocolClassConstraint, |
| getClassConstraint, |
| setClassConstraint) |
| |
| FLAGSET_DEFINE_FIELD_ACCESSORS(SpecialProtocolKind, |
| SpecialProtocolKind_width, |
| SpecialProtocol, |
| getSpecialProtocol, |
| setSpecialProtocol) |
| }; |
| |
| /// Flags for anonymous type context descriptors. These values are used as the |
| /// kindSpecificFlags of the ContextDescriptorFlags for the anonymous context. |
| class AnonymousContextDescriptorFlags : public FlagSet<uint16_t> { |
| enum { |
| /// Whether this anonymous context descriptor is followed by its |
| /// mangled name, which can be used to match the descriptor at runtime. |
| HasMangledName = 0, |
| }; |
| |
| public: |
| explicit AnonymousContextDescriptorFlags(uint16_t bits) : FlagSet(bits) {} |
| constexpr AnonymousContextDescriptorFlags() {} |
| |
| FLAGSET_DEFINE_FLAG_ACCESSORS(HasMangledName, hasMangledName, |
| setHasMangledName) |
| }; |
| |
| enum class GenericParamKind : uint8_t { |
| /// A type parameter. |
| Type = 0, |
| |
| Max = 0x3F, |
| }; |
| |
| class GenericParamDescriptor { |
| uint8_t Value; |
| |
| explicit constexpr GenericParamDescriptor(uint8_t Value) |
| : Value(Value) {} |
| public: |
| constexpr GenericParamDescriptor(GenericParamKind kind, |
| bool hasKeyArgument, |
| bool hasExtraArgument) |
| : GenericParamDescriptor(GenericParamDescriptor(0) |
| .withKind(kind) |
| .withKeyArgument(hasKeyArgument) |
| .withExtraArgument(hasExtraArgument)) |
| {} |
| |
| constexpr bool hasKeyArgument() const { |
| return (Value & 0x80u) != 0; |
| } |
| |
| constexpr bool hasExtraArgument() const { |
| return (Value & 0x40u) != 0; |
| } |
| |
| constexpr GenericParamKind getKind() const { |
| return GenericParamKind(Value & 0x3Fu); |
| } |
| |
| constexpr GenericParamDescriptor |
| withKeyArgument(bool hasKeyArgument) const { |
| return GenericParamDescriptor((Value & 0x7Fu) |
| | (hasKeyArgument ? 0x80u : 0)); |
| } |
| |
| constexpr GenericParamDescriptor |
| withExtraArgument(bool hasExtraArgument) const { |
| return GenericParamDescriptor((Value & 0xBFu) |
| | (hasExtraArgument ? 0x40u : 0)); |
| } |
| |
| constexpr GenericParamDescriptor withKind(GenericParamKind kind) const { |
| return assert((uint8_t(kind) & 0x3Fu) == uint8_t(kind)), |
| GenericParamDescriptor((Value & 0xC0u) | uint8_t(kind)); |
| } |
| |
| constexpr uint8_t getIntValue() const { |
| return Value; |
| } |
| }; |
| |
| enum class GenericRequirementKind : uint8_t { |
| /// A protocol requirement. |
| Protocol = 0, |
| /// A same-type requirement. |
| SameType = 1, |
| /// A base class requirement. |
| BaseClass = 2, |
| /// A "same-conformance" requirement, implied by a same-type or base-class |
| /// constraint that binds a parameter with protocol requirements. |
| SameConformance = 3, |
| /// A layout constraint. |
| Layout = 0x1F, |
| }; |
| |
| class GenericRequirementFlags { |
| uint32_t Value; |
| |
| explicit constexpr GenericRequirementFlags(uint32_t Value) |
| : Value(Value) {} |
| public: |
| constexpr GenericRequirementFlags(GenericRequirementKind kind, |
| bool hasKeyArgument, |
| bool hasExtraArgument) |
| : GenericRequirementFlags(GenericRequirementFlags(0) |
| .withKind(kind) |
| .withKeyArgument(hasKeyArgument) |
| .withExtraArgument(hasExtraArgument)) |
| {} |
| |
| constexpr bool hasKeyArgument() const { |
| return (Value & 0x80u) != 0; |
| } |
| |
| constexpr bool hasExtraArgument() const { |
| return (Value & 0x40u) != 0; |
| } |
| |
| constexpr GenericRequirementKind getKind() const { |
| return GenericRequirementKind(Value & 0x1Fu); |
| } |
| |
| constexpr GenericRequirementFlags |
| withKeyArgument(bool hasKeyArgument) const { |
| return GenericRequirementFlags((Value & 0x7Fu) |
| | (hasKeyArgument ? 0x80u : 0)); |
| } |
| |
| constexpr GenericRequirementFlags |
| withExtraArgument(bool hasExtraArgument) const { |
| return GenericRequirementFlags((Value & 0xBFu) |
| | (hasExtraArgument ? 0x40u : 0)); |
| } |
| |
| constexpr GenericRequirementFlags |
| withKind(GenericRequirementKind kind) const { |
| return assert((uint8_t(kind) & 0x1Fu) == uint8_t(kind)), |
| GenericRequirementFlags((Value & 0xE0u) | uint8_t(kind)); |
| } |
| |
| constexpr uint32_t getIntValue() const { |
| return Value; |
| } |
| }; |
| |
| enum class GenericRequirementLayoutKind : uint32_t { |
| // A class constraint. |
| Class = 0, |
| }; |
| |
| class GenericEnvironmentFlags { |
| uint32_t Value; |
| |
| enum : uint32_t { |
| NumGenericParameterLevelsMask = 0xFFF, |
| NumGenericRequirementsShift = 12, |
| NumGenericRequirementsMask = 0xFFFF << NumGenericRequirementsShift, |
| }; |
| |
| constexpr explicit GenericEnvironmentFlags(uint32_t value) : Value(value) { } |
| |
| public: |
| constexpr GenericEnvironmentFlags() : Value(0) { } |
| |
| constexpr GenericEnvironmentFlags |
| withNumGenericParameterLevels(uint16_t numGenericParameterLevels) const { |
| return GenericEnvironmentFlags((Value &~ NumGenericParameterLevelsMask) |
| | numGenericParameterLevels); |
| } |
| |
| constexpr GenericEnvironmentFlags |
| withNumGenericRequirements(uint16_t numGenericRequirements) const { |
| return GenericEnvironmentFlags((Value &~ NumGenericRequirementsMask) |
| | (numGenericRequirements << NumGenericRequirementsShift)); |
| } |
| |
| constexpr unsigned getNumGenericParameterLevels() const { |
| return Value & NumGenericParameterLevelsMask; |
| } |
| |
| constexpr unsigned getNumGenericRequirements() const { |
| return (Value & NumGenericRequirementsMask) >> NumGenericRequirementsShift; |
| } |
| |
| constexpr uint32_t getIntValue() const { |
| return Value; |
| } |
| }; |
| |
| /// Flags used by generic metadata patterns. |
| class GenericMetadataPatternFlags : public FlagSet<uint32_t> { |
| enum { |
| // All of these values are bit offsets or widths. |
| // General flags build up from 0. |
| // Kind-specific flags build down from 31. |
| |
| /// Does this pattern have an extra-data pattern? |
| HasExtraDataPattern = 0, |
| |
| // Class-specific flags. |
| |
| /// Does this pattern have an immediate-members pattern? |
| Class_HasImmediateMembersPattern = 31, |
| |
| // Value-specific flags. |
| |
| /// For value metadata: the metadata kind of the type. |
| Value_MetadataKind = 21, |
| Value_MetadataKind_width = 11, |
| }; |
| |
| public: |
| explicit GenericMetadataPatternFlags(uint32_t bits) : FlagSet(bits) {} |
| constexpr GenericMetadataPatternFlags() {} |
| |
| FLAGSET_DEFINE_FLAG_ACCESSORS(Class_HasImmediateMembersPattern, |
| class_hasImmediateMembersPattern, |
| class_setHasImmediateMembersPattern) |
| |
| FLAGSET_DEFINE_FLAG_ACCESSORS(HasExtraDataPattern, |
| hasExtraDataPattern, |
| setHasExtraDataPattern) |
| |
| FLAGSET_DEFINE_FIELD_ACCESSORS(Value_MetadataKind, |
| Value_MetadataKind_width, |
| MetadataKind, |
| value_getMetadataKind, |
| value_setMetadataKind) |
| }; |
| |
| /// The public state of a metadata. |
| enum class MetadataState : size_t { |
| // The values of this enum are set up to give us some future flexibility |
| // in adding states. The compiler emits unsigned comparisons against |
| // these values, so adding states that aren't totally ordered with at |
| // least the existing values will pose a problem; but we also use a |
| // gradually-shrinking bitset in case it's useful to track states as |
| // separate capabilities. Specific values have been chosen so that a |
| // MetadataRequest of 0 represents a blocking complete request, which |
| // is the most likely request from ordinary code. The total size of a |
| // state is kept to 8 bits so that a full request, even with additional |
| // flags, can be materialized as a single immediate on common ISAs, and |
| // so that the state can be extracted with a byte truncation. |
| // The spacing between states reflects guesswork about where new |
| // states/capabilities are most likely to be added. |
| |
| /// The metadata is fully complete. By definition, this is the |
| /// end-state of all metadata. Generally, metadata is expected to be |
| /// complete before it can be passed to arbitrary code, e.g. as |
| /// a generic argument to a function or as a metatype value. |
| /// |
| /// In addition to the requirements of NonTransitiveComplete, certain |
| /// transitive completeness guarantees must hold. Most importantly, |
| /// complete nominal type metadata transitively guarantee the completion |
| /// of their stored generic type arguments and superclass metadata. |
| Complete = 0x00, |
| |
| /// The metadata is fully complete except for any transitive completeness |
| /// guarantees. |
| /// |
| /// In addition to the requirements of LayoutComplete, metadata in this |
| /// state must be prepared for all basic type operations. This includes: |
| /// |
| /// - any sort of internal layout necessary to allocate and work |
| /// with concrete values of the type, such as the instance layout |
| /// of a class; |
| /// |
| /// - any sort of external dynamic registration that might be required |
| /// for the type, such as the realization of a class by the Objective-C |
| /// runtime; and |
| /// |
| /// - the initialization of any other information kept in the metadata |
| /// object, such as a class's v-table. |
| NonTransitiveComplete = 0x01, |
| |
| /// The metadata is ready for the layout of other types that store values |
| /// of this type. |
| /// |
| /// In addition to the requirements of Abstract, metadata in this state |
| /// must have a valid value witness table, meaning that its size, |
| /// alignment, and basic type properties (such as POD-ness) have been |
| /// computed. |
| LayoutComplete = 0x3F, |
| |
| /// The metadata has its basic identity established. It is possible to |
| /// determine what formal type it corresponds to. Among other things, it |
| /// is possible to use the runtime mangling facilities with the type. |
| /// |
| /// For example, a metadata for a generic struct has a metadata kind, |
| /// a type descriptor, and all of its type arguments. However, it does not |
| /// necessarily have a meaningful value-witness table. |
| /// |
| /// References to other types that are not part of the type's basic identity |
| /// may not yet have been established. Most crucially, this includes the |
| /// superclass pointer. |
| Abstract = 0xFF, |
| }; |
| |
| /// Something that can be static_asserted in all the places where we do |
| /// comparisons on metadata states. |
| constexpr const bool MetadataStateIsReverseOrdered = true; |
| |
| /// Return true if the first metadata state is at least as advanced as the |
| /// second. |
| inline bool isAtLeast(MetadataState lhs, MetadataState rhs) { |
| static_assert(MetadataStateIsReverseOrdered, |
| "relying on the ordering of MetadataState here"); |
| return size_t(lhs) <= size_t(rhs); |
| } |
| |
| /// Kinds of requests for metadata. |
| class MetadataRequest : public FlagSet<size_t> { |
| using IntType = size_t; |
| using super = FlagSet<IntType>; |
| |
| public: |
| enum : IntType { |
| State_bit = 0, |
| State_width = 8, |
| |
| /// A blocking request will not return until the runtime is able to produce |
| /// metadata with the given kind. A non-blocking request will return |
| /// "immediately", producing an abstract metadata and a flag saying that |
| /// the operation failed. |
| /// |
| /// An abstract request will never be non-zero. |
| NonBlocking_bit = 8, |
| }; |
| |
| MetadataRequest(MetadataState state, bool isNonBlocking = false) { |
| setState(state); |
| setIsNonBlocking(isNonBlocking); |
| } |
| explicit MetadataRequest(IntType bits) : super(bits) {} |
| constexpr MetadataRequest() {} |
| |
| FLAGSET_DEFINE_EQUALITY(MetadataRequest) |
| |
| FLAGSET_DEFINE_FIELD_ACCESSORS(State_bit, |
| State_width, |
| MetadataState, |
| getState, |
| setState) |
| |
| FLAGSET_DEFINE_FLAG_ACCESSORS(NonBlocking_bit, |
| isNonBlocking, |
| setIsNonBlocking) |
| bool isBlocking() const { return !isNonBlocking(); } |
| |
| /// Is this request satisfied by a metadata that's in the given state? |
| bool isSatisfiedBy(MetadataState state) const { |
| return isAtLeast(state, getState()); |
| } |
| }; |
| |
| /// Flags for Builtin.IntegerLiteral values. |
| class IntegerLiteralFlags { |
| public: |
| enum : size_t { |
| IsNegativeFlag = 0x1, |
| |
| // Save some space for other flags. |
| |
| BitWidthShift = 8, |
| }; |
| |
| private: |
| size_t Data; |
| |
| explicit IntegerLiteralFlags(size_t data) : Data(data) {} |
| |
| public: |
| constexpr IntegerLiteralFlags(size_t bitWidth, bool isNegative) |
| : Data((bitWidth << BitWidthShift) |
| | (isNegative ? IsNegativeFlag : 0)) {} |
| |
| /// Return true if the value is negative. |
| bool isNegative() const { return Data & IsNegativeFlag; } |
| |
| /// Return the minimum number of bits necessary to store the value in |
| /// two's complement, including a leading sign bit. |
| unsigned getBitWidth() const { return Data >> BitWidthShift; } |
| |
| size_t getOpaqueValue() const { return Data; } |
| static IntegerLiteralFlags getFromOpaqueValue(size_t value) { |
| return IntegerLiteralFlags(value); |
| } |
| }; |
| |
| } // end namespace swift |
| |
| #endif /* SWIFT_ABI_METADATAVALUES_H */ |