mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
1756 lines
59 KiB
C++
1756 lines
59 KiB
C++
//===--- 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,
|
|
|
|
/// 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<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 */
|