//===--- 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/ABI/KeyPath.h" #include "swift/AST/Ownership.h" #include "swift/Basic/LLVM.h" #include "swift/Basic/FlagSet.h" #include "swift/Runtime/Unreachable.h" #include #include 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 struct TargetMetadata; using Metadata = TargetMetadata; /// 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 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; /// 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, /// Whether this metadata is a specialization of a generic metadata pattern /// which was created during compilation. IsStaticSpecialization = 0x8, /// Whether this metadata is a specialization of a generic metadata pattern /// which was created during compilation and made to be canonical by /// modifying the metadata accessor. IsCanonicalStaticSpecialization = 0x10, }; 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, ExtraDiscriminatorShift = 16, ExtraDiscriminatorMask = 0xFFFF0000, }; 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; } MethodDescriptorFlags withExtraDiscriminator(uint16_t value) const { auto copy = *this; copy.Value = (copy.Value & ~ExtraDiscriminatorMask) | (int_type(value) << ExtraDiscriminatorShift); 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; } uint16_t getExtraDiscriminator() const { return (Value >> ExtraDiscriminatorShift); } 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, ExtraDiscriminatorShift = 16, ExtraDiscriminatorMask = 0xFFFF0000, }; 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; } ProtocolRequirementFlags withExtraDiscriminator(uint16_t value) const { auto copy = *this; copy.Value = (copy.Value & ~ExtraDiscriminatorMask) | (int_type(value) << ExtraDiscriminatorShift); 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; } bool isSignedWithAddress() const { return getKind() != Kind::BaseProtocol; } uint16_t getExtraDiscriminator() const { return (Value >> ExtraDiscriminatorShift); } 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, // Warning: Set if NOT class-constrained! 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, }; /// Differentiability kind for function type metadata. /// Duplicates `DifferentiabilityKind` in AutoDiff.h. enum class FunctionMetadataDifferentiabilityKind: uint8_t { NonDifferentiable = 0b00, Normal = 0b01, Linear = 0b11 }; /// Flags in a function type metadata record. template 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, DifferentiableMask = 0x08000000U, LinearMask = 0x10000000U }; 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 withConvention(FunctionMetadataConvention c) const { return TargetFunctionTypeFlags((Data & ~ConventionMask) | (int_type(c) << ConventionShift)); } constexpr TargetFunctionTypeFlags withThrows(bool throws) const { return TargetFunctionTypeFlags((Data & ~ThrowsMask) | (throws ? ThrowsMask : 0)); } constexpr TargetFunctionTypeFlags withDifferentiabilityKind( FunctionMetadataDifferentiabilityKind differentiability) const { return TargetFunctionTypeFlags( (Data & ~DifferentiableMask & ~LinearMask) | (differentiability == FunctionMetadataDifferentiabilityKind::Normal ? DifferentiableMask : 0) | (differentiability == FunctionMetadataDifferentiabilityKind::Linear ? LinearMask : 0)); } constexpr TargetFunctionTypeFlags withParameterFlags(bool hasFlags) const { return TargetFunctionTypeFlags((Data & ~ParamFlagsMask) | (hasFlags ? ParamFlagsMask : 0)); } constexpr TargetFunctionTypeFlags withEscaping(bool isEscaping) const { return TargetFunctionTypeFlags((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); } bool isDifferentiable() const { return getDifferentiabilityKind() >= FunctionMetadataDifferentiabilityKind::Normal; } FunctionMetadataDifferentiabilityKind getDifferentiabilityKind() const { if (bool(Data & DifferentiableMask)) return FunctionMetadataDifferentiabilityKind::Normal; if (bool(Data & LinearMask)) return FunctionMetadataDifferentiabilityKind::Linear; return FunctionMetadataDifferentiabilityKind::NonDifferentiable; } int_type getIntValue() const { return Data; } static TargetFunctionTypeFlags fromIntValue(int_type Data) { return TargetFunctionTypeFlags(Data); } bool operator==(TargetFunctionTypeFlags other) const { return Data == other.Data; } bool operator!=(TargetFunctionTypeFlags other) const { return Data != other.Data; } }; using FunctionTypeFlags = TargetFunctionTypeFlags; template class TargetParameterTypeFlags { enum : int_type { ValueOwnershipMask = 0x7F, VariadicMask = 0x80, AutoClosureMask = 0x100, NoDerivativeMask = 0x200 }; int_type Data; constexpr TargetParameterTypeFlags(int_type Data) : Data(Data) {} public: constexpr TargetParameterTypeFlags() : Data(0) {} constexpr TargetParameterTypeFlags withValueOwnership(ValueOwnership ownership) const { return TargetParameterTypeFlags((Data & ~ValueOwnershipMask) | (int_type)ownership); } constexpr TargetParameterTypeFlags withVariadic(bool isVariadic) const { return TargetParameterTypeFlags((Data & ~VariadicMask) | (isVariadic ? VariadicMask : 0)); } constexpr TargetParameterTypeFlags withAutoClosure(bool isAutoClosure) const { return TargetParameterTypeFlags( (Data & ~AutoClosureMask) | (isAutoClosure ? AutoClosureMask : 0)); } bool isNone() const { return Data == 0; } bool isVariadic() const { return Data & VariadicMask; } bool isAutoClosure() const { return Data & AutoClosureMask; } bool isNoDerivative() const { return Data & NoDerivativeMask; } ValueOwnership getValueOwnership() const { return (ValueOwnership)(Data & ValueOwnershipMask); } int_type getIntValue() const { return Data; } static TargetParameterTypeFlags fromIntValue(int_type Data) { return TargetParameterTypeFlags(Data); } bool operator==(TargetParameterTypeFlags other) const { return Data == other.Data; } bool operator!=(TargetParameterTypeFlags other) const { return Data != other.Data; } }; using ParameterFlags = TargetParameterTypeFlags; template 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 withNonConstantLabels( bool hasNonConstantLabels) const { return TargetTupleTypeFlags( (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 fromIntValue(int_type Data) { return TargetTupleTypeFlags(Data); } bool operator==(TargetTupleTypeFlags other) const { return Data == other.Data; } bool operator!=(TargetTupleTypeFlags other) const { return Data != other.Data; } }; using TupleTypeFlags = TargetTupleTypeFlags; /// 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); } namespace SpecialPointerAuthDiscriminators { // All of these values are the stable string hash of the corresponding // variable name: // (computeStableStringHash % 65535 + 1) /// HeapMetadataHeader::destroy const uint16_t HeapDestructor = 0xbbbf; /// Type descriptor data pointers. const uint16_t TypeDescriptor = 0xae86; /// Runtime function variables exported by the runtime. const uint16_t RuntimeFunctionEntry = 0x625b; /// Value witness functions. const uint16_t InitializeBufferWithCopyOfBuffer = 0xda4a; const uint16_t Destroy = 0x04f8; const uint16_t InitializeWithCopy = 0xe3ba; const uint16_t AssignWithCopy = 0x8751; const uint16_t InitializeWithTake = 0x48d8; const uint16_t AssignWithTake = 0xefda; const uint16_t DestroyArray = 0x2398; const uint16_t InitializeArrayWithCopy = 0xa05c; const uint16_t InitializeArrayWithTakeFrontToBack = 0x1c3e; const uint16_t InitializeArrayWithTakeBackToFront = 0x8dd3; const uint16_t StoreExtraInhabitant = 0x79c5; const uint16_t GetExtraInhabitantIndex = 0x2ca8; const uint16_t GetEnumTag = 0xa3b5; const uint16_t DestructiveProjectEnumData = 0x041d; const uint16_t DestructiveInjectEnumTag = 0xb2e4; const uint16_t GetEnumTagSinglePayload = 0x60f0; const uint16_t StoreEnumTagSinglePayload = 0xa0d1; /// KeyPath metadata functions. const uint16_t KeyPathDestroy = _SwiftKeyPath_ptrauth_ArgumentDestroy; const uint16_t KeyPathCopy = _SwiftKeyPath_ptrauth_ArgumentCopy; const uint16_t KeyPathEquals = _SwiftKeyPath_ptrauth_ArgumentEquals; const uint16_t KeyPathHash = _SwiftKeyPath_ptrauth_ArgumentHash; const uint16_t KeyPathGetter = _SwiftKeyPath_ptrauth_Getter; const uint16_t KeyPathNonmutatingSetter = _SwiftKeyPath_ptrauth_NonmutatingSetter; const uint16_t KeyPathMutatingSetter = _SwiftKeyPath_ptrauth_MutatingSetter; const uint16_t KeyPathGetLayout = _SwiftKeyPath_ptrauth_ArgumentLayout; const uint16_t KeyPathInitializer = _SwiftKeyPath_ptrauth_ArgumentInit; const uint16_t KeyPathMetadataAccessor = _SwiftKeyPath_ptrauth_MetadataAccessor; /// ObjC bridging entry points. const uint16_t ObjectiveCTypeDiscriminator = 0x31c3; // = 12739 const uint16_t bridgeToObjectiveCDiscriminator = 0xbca0; // = 48288 const uint16_t forceBridgeFromObjectiveCDiscriminator = 0x22fb; // = 8955 const uint16_t conditionallyBridgeFromObjectiveCDiscriminator = 0x9a9b; // = 39579 /// Dynamic replacement pointers. const uint16_t DynamicReplacementScope = 0x48F0; // = 18672 const uint16_t DynamicReplacementKey = 0x2C7D; // = 11389 /// Resume functions for yield-once coroutines that yield a single /// opaque borrowed/inout value. These aren't actually hard-coded, but /// they're important enough to be worth writing in one place. const uint16_t OpaqueReadResumeFunction = 56769; const uint16_t OpaqueModifyResumeFunction = 3909; } /// 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, /// This context descriptor represents an opaque type alias. OpaqueType = 4, /// 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 { 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 { 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 { 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 { 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 { 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, /// Do instances of this pattern have a bitset of flags that occur at the /// end of the metadata, after the extra data if there is any? HasTrailingFlags = 1, // 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_FLAG_ACCESSORS(HasTrailingFlags, hasTrailingFlags, setHasTrailingFlags) 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 { using IntType = size_t; using super = FlagSet; 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()); } }; struct MetadataTrailingFlags : public FlagSet { enum { /// Whether this metadata is a specialization of a generic metadata pattern /// which was created during compilation. IsStaticSpecialization = 0, /// Whether this metadata is a specialization of a generic metadata pattern /// which was created during compilation and made to be canonical by /// modifying the metadata accessor. IsCanonicalStaticSpecialization = 1, }; explicit MetadataTrailingFlags(uint64_t bits) : FlagSet(bits) {} constexpr MetadataTrailingFlags() {} FLAGSET_DEFINE_FLAG_ACCESSORS(IsStaticSpecialization, isStaticSpecialization, setIsStaticSpecialization) FLAGSET_DEFINE_FLAG_ACCESSORS(IsCanonicalStaticSpecialization, isCanonicalStaticSpecialization, setIsCanonicalStaticSpecialization) }; /// 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