//===--- Metadata.h - Swift Language ABI Metadata Support -------*- 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 // //===----------------------------------------------------------------------===// // // Swift ABI for generating and uniquing metadata. // //===----------------------------------------------------------------------===// #ifndef SWIFT_RUNTIME_METADATA_H #define SWIFT_RUNTIME_METADATA_H #include #include #include #include #include #include #include #include #include #include #include "llvm/ADT/ArrayRef.h" #include "swift/Runtime/Config.h" #include "swift/ABI/MetadataValues.h" #include "swift/ABI/System.h" #include "swift/ABI/TrailingObjects.h" #include "swift/Basic/Malloc.h" #include "swift/Basic/FlaggedPointer.h" #include "swift/Basic/RelativePointer.h" #include "swift/Demangling/Demangle.h" #include "swift/Demangling/ManglingMacros.h" #include "swift/Reflection/Records.h" #include "swift/Runtime/Unreachable.h" #include "../../../stdlib/public/SwiftShims/HeapObject.h" #if SWIFT_OBJC_INTEROP #include #endif #include "llvm/ADT/STLExtras.h" #include "llvm/Support/Casting.h" namespace swift { #if SWIFT_OBJC_INTEROP // Const cast shorthands for ObjC types. /// Cast to id, discarding const if necessary. template static inline id id_const_cast(const T* value) { return reinterpret_cast(const_cast(value)); } /// Cast to Class, discarding const if necessary. template static inline Class class_const_cast(const T* value) { return reinterpret_cast(const_cast(value)); } /// Cast to Protocol*, discarding const if necessary. template static inline Protocol* protocol_const_cast(const T* value) { return reinterpret_cast(const_cast(value)); } /// Cast from a CF type, discarding const if necessary. template static inline T cf_const_cast(const void* value) { return reinterpret_cast(const_cast(value)); } #endif template struct RuntimeTarget; template <> struct RuntimeTarget<4> { using StoredPointer = uint32_t; using StoredSize = uint32_t; static constexpr size_t PointerSize = 4; }; template <> struct RuntimeTarget<8> { using StoredPointer = uint64_t; using StoredSize = uint64_t; static constexpr size_t PointerSize = 8; }; /// In-process native runtime target. /// /// For interactions in the runtime, this should be the equivalent of working /// with a plain old pointer type. struct InProcess { static constexpr size_t PointerSize = sizeof(uintptr_t); using StoredPointer = uintptr_t; using StoredSize = size_t; template using Pointer = T*; template using FarRelativeDirectPointer = FarRelativeDirectPointer; template using FarRelativeIndirectablePointer = FarRelativeIndirectablePointer; template using RelativeDirectPointer = RelativeDirectPointer; }; /// Represents a pointer in another address space. /// /// This type should not have * or -> operators -- you must as a memory reader /// to read the data at the stored address on your behalf. template struct ExternalPointer { using StoredPointer = typename Runtime::StoredPointer; StoredPointer PointerValue; }; /// An external process's runtime target, which may be a different architecture. template struct External { using StoredPointer = typename Runtime::StoredPointer; using StoredSize = typename Runtime::StoredSize; static constexpr size_t PointerSize = Runtime::PointerSize; const StoredPointer PointerValue; template using Pointer = StoredPointer; template using FarRelativeDirectPointer = StoredPointer; template using FarRelativeIndirectablePointer = StoredSize; template using RelativeDirectPointer = int32_t; }; /// Template for branching on native pointer types versus external ones template class Pointee> using TargetMetadataPointer = typename Runtime::template Pointer>; template class Pointee> using ConstTargetMetadataPointer = typename Runtime::template Pointer>; template using TargetPointer = typename Runtime::template Pointer; template class Pointee, bool Nullable = true> using ConstTargetFarRelativeDirectPointer = typename Runtime::template FarRelativeDirectPointer, Nullable>; template using TargetRelativeDirectPointer = typename Runtime::template RelativeDirectPointer; template using TargetFarRelativeIndirectablePointer = typename Runtime::template FarRelativeIndirectablePointer; struct HeapObject; class WeakReference; template struct TargetMetadata; using Metadata = TargetMetadata; template struct TargetProtocolConformanceDescriptor; /// Storage for an arbitrary value. In C/C++ terms, this is an /// 'object', because it is rooted in memory. /// /// The context dictates what type is actually stored in this object, /// and so this type is intentionally incomplete. /// /// An object can be in one of two states: /// - An uninitialized object has a completely unspecified state. /// - An initialized object holds a valid value of the type. struct OpaqueValue; /// A fixed-size buffer for local values. It is capable of owning /// (possibly in side-allocated memory) the storage necessary /// to hold a value of an arbitrary type. Because it is fixed-size, /// it can be allocated in places that must be agnostic to the /// actual type: for example, within objects of existential type, /// or for local variables in generic functions. /// /// The context dictates its type, which ultimately means providing /// access to a value witness table by which the value can be /// accessed and manipulated. /// /// A buffer can directly store three pointers and is pointer-aligned. /// Three pointers is a sweet spot for Swift, because it means we can /// store a structure containing a pointer, a size, and an owning /// object, which is a common pattern in code due to ARC. In a GC /// environment, this could be reduced to two pointers without much loss. /// /// A buffer can be in one of three states: /// - An unallocated buffer has a completely unspecified state. /// - An allocated buffer has been initialized so that it /// owns uninitialized value storage for the stored type. /// - An initialized buffer is an allocated buffer whose value /// storage has been initialized. template struct TargetValueBuffer { TargetPointer PrivateData[NumWords_ValueBuffer]; }; using ValueBuffer = TargetValueBuffer; /// Can a value with the given size and alignment be allocated inline? constexpr inline bool canBeInline(size_t size, size_t alignment) { return size <= sizeof(ValueBuffer) && alignment <= alignof(ValueBuffer); } template constexpr inline bool canBeInline() { return canBeInline(sizeof(T), alignof(T)); } struct ValueWitnessTable; /// Flags stored in the value-witness table. class ValueWitnessFlags { typedef size_t int_type; // 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 : int_type { AlignmentMask = 0x0000FFFF, IsNonPOD = 0x00010000, IsNonInline = 0x00020000, HasExtraInhabitants = 0x00040000, HasSpareBits = 0x00080000, IsNonBitwiseTakable = 0x00100000, HasEnumWitnesses = 0x00200000, // Everything else is reserved. }; int_type Data; constexpr ValueWitnessFlags(int_type data) : Data(data) {} public: constexpr ValueWitnessFlags() : 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 ValueWitnessFlags withAlignmentMask(size_t alignMask) const { return ValueWitnessFlags((Data & ~AlignmentMask) | alignMask); } size_t getAlignment() const { return getAlignmentMask() + 1; } constexpr ValueWitnessFlags withAlignment(size_t alignment) const { return withAlignmentMask(alignment - 1); } /// True if the type requires out-of-line allocation of its storage. bool isInlineStorage() const { return !(Data & IsNonInline); } constexpr ValueWitnessFlags withInlineStorage(bool isInline) const { return ValueWitnessFlags((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 ValueWitnessFlags withPOD(bool isPOD) const { return ValueWitnessFlags((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 ValueWitnessFlags withBitwiseTakable(bool isBT) const { return ValueWitnessFlags((Data & ~IsNonBitwiseTakable) | (isBT ? 0 : IsNonBitwiseTakable)); } /// True if this type's binary representation has extra inhabitants, that is, /// bit patterns that do not form valid values of the type. /// /// If true, then the extra inhabitant value witness table entries are /// available in this type's value witness table. bool hasExtraInhabitants() const { return Data & HasExtraInhabitants; } /// 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 ValueWitnessFlags withExtraInhabitants(bool hasExtraInhabitants) const { return ValueWitnessFlags((Data & ~HasExtraInhabitants) | (hasExtraInhabitants ? HasExtraInhabitants : 0)); } constexpr ValueWitnessFlags withEnumWitnesses(bool hasEnumWitnesses) const { return ValueWitnessFlags((Data & ~HasEnumWitnesses) | (hasEnumWitnesses ? HasEnumWitnesses : 0)); } }; /// Flags stored in a value-witness table with extra inhabitants. class ExtraInhabitantFlags { typedef size_t int_type; enum : int_type { NumExtraInhabitantsMask = 0x7FFFFFFFU, }; int_type Data; constexpr ExtraInhabitantFlags(int_type data) : Data(data) {} public: constexpr ExtraInhabitantFlags() : Data(0) {} /// The number of extra inhabitants in the type's representation. int getNumExtraInhabitants() const { return Data & NumExtraInhabitantsMask; } constexpr ExtraInhabitantFlags withNumExtraInhabitants(unsigned numExtraInhabitants) const { return ExtraInhabitantFlags((Data & ~NumExtraInhabitantsMask) | numExtraInhabitants); } }; namespace value_witness_types { // Note that, for now, we aren't strict about 'const'. #define WANT_ALL_VALUE_WITNESSES #define DATA_VALUE_WITNESS(lowerId, upperId, type) #define FUNCTION_VALUE_WITNESS(lowerId, upperId, returnType, paramTypes) \ typedef returnType (*lowerId) paramTypes; #define MUTABLE_VALUE_TYPE OpaqueValue * #define IMMUTABLE_VALUE_TYPE const OpaqueValue * #define MUTABLE_BUFFER_TYPE ValueBuffer * #define IMMUTABLE_BUFFER_TYPE const ValueBuffer * #define TYPE_TYPE const Metadata * #define SIZE_TYPE size_t #define INT_TYPE int #define UINT_TYPE unsigned #define VOID_TYPE void #include "swift/ABI/ValueWitness.def" // Handle the data witnesses explicitly so we can use more specific // types for the flags enums. typedef size_t size; typedef ValueWitnessFlags flags; typedef size_t stride; typedef ExtraInhabitantFlags extraInhabitantFlags; } // end namespace value_witness_types /// A standard routine, suitable for placement in the value witness /// table, for copying an opaque POD object. SWIFT_RUNTIME_EXPORT OpaqueValue *swift_copyPOD(OpaqueValue *dest, OpaqueValue *src, const Metadata *self); struct TypeLayout; /// A value-witness table. A value witness table is built around /// the requirements of some specific type. The information in /// a value-witness table is intended to be sufficient to lay out /// and manipulate values of an arbitrary type. struct ValueWitnessTable { // For the meaning of all of these witnesses, consult the comments // on their associated typedefs, above. #define WANT_ONLY_REQUIRED_VALUE_WITNESSES #define VALUE_WITNESS(LOWER_ID, UPPER_ID) \ value_witness_types::LOWER_ID LOWER_ID; #include "swift/ABI/ValueWitness.def" /// Would values of a type with the given layout requirements be /// allocated inline? static bool isValueInline(size_t size, size_t alignment) { return (size <= sizeof(ValueBuffer) && alignment <= alignof(ValueBuffer)); } /// Are values of this type allocated inline? bool isValueInline() const { return flags.isInlineStorage(); } /// Is this type POD? bool isPOD() const { return flags.isPOD(); } /// Is this type bitwise-takable? bool isBitwiseTakable() const { return flags.isBitwiseTakable(); } /// Return the size of this type. Unlike in C, this has not been /// padded up to the alignment; that value is maintained as /// 'stride'. size_t getSize() const { return size; } /// Return the stride of this type. This is the size rounded up to /// be a multiple of the alignment. size_t getStride() const { return stride; } /// Return the alignment required by this type, in bytes. size_t getAlignment() const { return flags.getAlignment(); } /// The alignment mask of this type. An offset may be rounded up to /// the required alignment by adding this mask and masking by its /// bit-negation. /// /// For example, if the type needs to be 8-byte aligned, the value /// of this witness is 0x7. size_t getAlignmentMask() const { return flags.getAlignmentMask(); } /// The number of extra inhabitants, that is, bit patterns that do not form /// valid values of the type, in this type's binary representation. unsigned getNumExtraInhabitants() const; /// Assert that this value witness table is an extra-inhabitants /// value witness table and return it as such. /// /// This has an awful name because it's supposed to be internal to /// this file. Code outside this file should use LLVM's cast/dyn_cast. /// We don't want to use those here because we need to avoid accidentally /// introducing ABI dependencies on LLVM structures. const struct ExtraInhabitantsValueWitnessTable *_asXIVWT() const; /// Assert that this value witness table is an enum value witness table /// and return it as such. /// /// This has an awful name because it's supposed to be internal to /// this file. Code outside this file should use LLVM's cast/dyn_cast. /// We don't want to use those here because we need to avoid accidentally /// introducing ABI dependencies on LLVM structures. const struct EnumValueWitnessTable *_asEVWT() const; /// Get the type layout record within this value witness table. const TypeLayout *getTypeLayout() const { return reinterpret_cast(&size); } }; /// A value-witness table with extra inhabitants entry points. /// These entry points are available only if the HasExtraInhabitants flag bit is /// set in the 'flags' field. struct ExtraInhabitantsValueWitnessTable : ValueWitnessTable { #define WANT_ONLY_EXTRA_INHABITANT_VALUE_WITNESSES #define VALUE_WITNESS(LOWER_ID, UPPER_ID) \ value_witness_types::LOWER_ID LOWER_ID; #include "swift/ABI/ValueWitness.def" #define SET_WITNESS(NAME) base.NAME, constexpr ExtraInhabitantsValueWitnessTable() : ValueWitnessTable{}, extraInhabitantFlags(), storeExtraInhabitant(nullptr), getExtraInhabitantIndex(nullptr) {} constexpr ExtraInhabitantsValueWitnessTable( const ValueWitnessTable &base, value_witness_types::extraInhabitantFlags eif, value_witness_types::storeExtraInhabitant sei, value_witness_types::getExtraInhabitantIndex geii) : ValueWitnessTable(base), extraInhabitantFlags(eif), storeExtraInhabitant(sei), getExtraInhabitantIndex(geii) {} static bool classof(const ValueWitnessTable *table) { return table->flags.hasExtraInhabitants(); } }; /// A value-witness table with enum entry points. /// These entry points are available only if the HasEnumWitnesses flag bit is /// set in the 'flags' field. struct EnumValueWitnessTable : ExtraInhabitantsValueWitnessTable { #define WANT_ONLY_ENUM_VALUE_WITNESSES #define VALUE_WITNESS(LOWER_ID, UPPER_ID) \ value_witness_types::LOWER_ID LOWER_ID; #include "swift/ABI/ValueWitness.def" constexpr EnumValueWitnessTable() : ExtraInhabitantsValueWitnessTable(), getEnumTag(nullptr), destructiveProjectEnumData(nullptr), destructiveInjectEnumTag(nullptr) {} constexpr EnumValueWitnessTable( const ExtraInhabitantsValueWitnessTable &base, value_witness_types::getEnumTag getEnumTag, value_witness_types::destructiveProjectEnumData destructiveProjectEnumData, value_witness_types::destructiveInjectEnumTag destructiveInjectEnumTag) : ExtraInhabitantsValueWitnessTable(base), getEnumTag(getEnumTag), destructiveProjectEnumData(destructiveProjectEnumData), destructiveInjectEnumTag(destructiveInjectEnumTag) {} static bool classof(const ValueWitnessTable *table) { return table->flags.hasEnumWitnesses(); } }; /// A type layout record. This is the subset of the value witness table that is /// necessary to perform dependent layout of generic value types. It excludes /// the value witness functions and includes only the size, alignment, /// extra inhabitants, and miscellaneous flags about the type. struct TypeLayout { value_witness_types::size size; value_witness_types::flags flags; value_witness_types::stride stride; private: // Only available if the "hasExtraInhabitants" flag is set. value_witness_types::extraInhabitantFlags extraInhabitantFlags; void _static_assert_layout(); public: value_witness_types::extraInhabitantFlags getExtraInhabitantFlags() const { assert(flags.hasExtraInhabitants()); return extraInhabitantFlags; } const TypeLayout *getTypeLayout() const { return this; } /// The number of extra inhabitants, that is, bit patterns that do not form /// valid values of the type, in this type's binary representation. unsigned getNumExtraInhabitants() const; }; inline void TypeLayout::_static_assert_layout() { #define CHECK_TYPE_LAYOUT_OFFSET(FIELD) \ static_assert(offsetof(ExtraInhabitantsValueWitnessTable, FIELD) \ - offsetof(ExtraInhabitantsValueWitnessTable, size) \ == offsetof(TypeLayout, FIELD), \ "layout of " #FIELD " in TypeLayout doesn't match " \ "value witness table") CHECK_TYPE_LAYOUT_OFFSET(size); CHECK_TYPE_LAYOUT_OFFSET(flags); CHECK_TYPE_LAYOUT_OFFSET(stride); CHECK_TYPE_LAYOUT_OFFSET(extraInhabitantFlags); #undef CHECK_TYPE_LAYOUT_OFFSET } inline const ExtraInhabitantsValueWitnessTable * ValueWitnessTable::_asXIVWT() const { assert(ExtraInhabitantsValueWitnessTable::classof(this)); return static_cast(this); } inline const EnumValueWitnessTable * ValueWitnessTable::_asEVWT() const { assert(EnumValueWitnessTable::classof(this)); return static_cast(this); } inline unsigned ValueWitnessTable::getNumExtraInhabitants() const { // If the table does not have extra inhabitant witnesses, then there are zero. if (!flags.hasExtraInhabitants()) return 0; return this->_asXIVWT()->extraInhabitantFlags.getNumExtraInhabitants(); } inline unsigned TypeLayout::getNumExtraInhabitants() const { // If the table does not have extra inhabitant witnesses, then there are zero. if (!flags.hasExtraInhabitants()) return 0; return extraInhabitantFlags.getNumExtraInhabitants(); } // Standard value-witness tables. // The "Int" tables are used for arbitrary POD data with the matching // size/alignment characteristics. SWIFT_RUNTIME_EXPORT const ValueWitnessTable VALUE_WITNESS_SYM(Bi8_); // Builtin.Int8 SWIFT_RUNTIME_EXPORT const ValueWitnessTable VALUE_WITNESS_SYM(Bi16_); // Builtin.Int16 SWIFT_RUNTIME_EXPORT const ValueWitnessTable VALUE_WITNESS_SYM(Bi32_); // Builtin.Int32 SWIFT_RUNTIME_EXPORT const ValueWitnessTable VALUE_WITNESS_SYM(Bi64_); // Builtin.Int64 SWIFT_RUNTIME_EXPORT const ValueWitnessTable VALUE_WITNESS_SYM(Bi128_); // Builtin.Int128 SWIFT_RUNTIME_EXPORT const ValueWitnessTable VALUE_WITNESS_SYM(Bi256_); // Builtin.Int256 SWIFT_RUNTIME_EXPORT const ValueWitnessTable VALUE_WITNESS_SYM(Bi512_); // Builtin.Int512 // The object-pointer table can be used for arbitrary Swift refcounted // pointer types. SWIFT_RUNTIME_EXPORT const ExtraInhabitantsValueWitnessTable VALUE_WITNESS_SYM(Bo); // Builtin.NativeObject SWIFT_RUNTIME_EXPORT const ExtraInhabitantsValueWitnessTable UNOWNED_VALUE_WITNESS_SYM(Bo); // unowned Builtin.NativeObject SWIFT_RUNTIME_EXPORT const ValueWitnessTable WEAK_VALUE_WITNESS_SYM(Bo); // weak Builtin.NativeObject? SWIFT_RUNTIME_EXPORT const ExtraInhabitantsValueWitnessTable VALUE_WITNESS_SYM(Bb); // Builtin.BridgeObject SWIFT_RUNTIME_EXPORT const ExtraInhabitantsValueWitnessTable VALUE_WITNESS_SYM(Bp); // Builtin.RawPointer #if SWIFT_OBJC_INTEROP // The ObjC-pointer table can be used for arbitrary ObjC pointer types. SWIFT_RUNTIME_EXPORT const ExtraInhabitantsValueWitnessTable VALUE_WITNESS_SYM(BO); // Builtin.UnknownObject SWIFT_RUNTIME_EXPORT const ExtraInhabitantsValueWitnessTable UNOWNED_VALUE_WITNESS_SYM(BO); // unowned Builtin.UnknownObject SWIFT_RUNTIME_EXPORT const ValueWitnessTable WEAK_VALUE_WITNESS_SYM(BO); // weak Builtin.UnknownObject? #endif // The () -> () table can be used for arbitrary function types. SWIFT_RUNTIME_EXPORT const ExtraInhabitantsValueWitnessTable VALUE_WITNESS_SYM(FUNCTION_MANGLING); // () -> () // The @escaping () -> () table can be used for arbitrary escaping function types. SWIFT_RUNTIME_EXPORT const ExtraInhabitantsValueWitnessTable VALUE_WITNESS_SYM(NOESCAPE_FUNCTION_MANGLING); // @noescape () -> () // The @convention(thin) () -> () table can be used for arbitrary thin function types. SWIFT_RUNTIME_EXPORT const ExtraInhabitantsValueWitnessTable VALUE_WITNESS_SYM(THIN_FUNCTION_MANGLING); // @convention(thin) () -> () // The () table can be used for arbitrary empty types. SWIFT_RUNTIME_EXPORT const ValueWitnessTable VALUE_WITNESS_SYM(EMPTY_TUPLE_MANGLING); // () // The table for aligned-pointer-to-pointer types. SWIFT_RUNTIME_EXPORT const ExtraInhabitantsValueWitnessTable METATYPE_VALUE_WITNESS_SYM(Bo); // Builtin.NativeObject.Type /// Return the value witnesses for unmanaged pointers. static inline const ValueWitnessTable &getUnmanagedPointerValueWitnesses() { #if __POINTER_WIDTH__ == 64 return VALUE_WITNESS_SYM(Bi64_); #else return VALUE_WITNESS_SYM(Bi32_); #endif } /// Return value witnesses for a pointer-aligned pointer type. static inline const ExtraInhabitantsValueWitnessTable & getUnmanagedPointerPointerValueWitnesses() { return METATYPE_VALUE_WITNESS_SYM(Bo); } /// The header before a metadata object which appears on all type /// metadata. Note that heap metadata are not necessarily type /// metadata, even for objects of a heap type: for example, objects of /// Objective-C type possess a form of heap metadata (an Objective-C /// Class pointer), but this metadata lacks the type metadata header. /// This case can be distinguished using the isTypeMetadata() flag /// on ClassMetadata. template struct TargetTypeMetadataHeader { /// A pointer to the value-witnesses for this type. This is only /// present for type metadata. TargetPointer ValueWitnesses; }; using TypeMetadataHeader = TargetTypeMetadataHeader; /// A "full" metadata pointer is simply an adjusted address point on a /// metadata object; it points to the beginning of the metadata's /// allocation, rather than to the canonical address point of the /// metadata object. template struct FullMetadata : T::HeaderType, T { typedef typename T::HeaderType HeaderType; FullMetadata() = default; constexpr FullMetadata(const HeaderType &header, const T &metadata) : HeaderType(header), T(metadata) {} }; /// Given a canonical metadata pointer, produce the adjusted metadata pointer. template static inline FullMetadata *asFullMetadata(T *metadata) { return (FullMetadata*) (((typename T::HeaderType*) metadata) - 1); } template static inline const FullMetadata *asFullMetadata(const T *metadata) { return asFullMetadata(const_cast(metadata)); } // std::result_of is busted in Xcode 5. This is a simplified reimplementation // that isn't SFINAE-safe. namespace { template struct _ResultOf; template struct _ResultOf { using type = R; }; } template struct TargetGenericMetadataInstantiationCache; template struct TargetClassMetadata; template struct TargetStructMetadata; template struct TargetOpaqueMetadata; template struct TargetValueMetadata; template struct TargetForeignClassMetadata; template class TargetTypeContextDescriptor; template class TargetClassDescriptor; template class TargetValueTypeDescriptor; template class TargetEnumDescriptor; template class TargetStructDescriptor; // FIXME: https://bugs.swift.org/browse/SR-1155 #pragma clang diagnostic push #pragma clang diagnostic ignored "-Winvalid-offsetof" /// The common structure of all type metadata. template struct TargetMetadata { using StoredPointer = typename Runtime::StoredPointer; constexpr TargetMetadata() : Kind(static_cast(MetadataKind::Class)) {} constexpr TargetMetadata(MetadataKind Kind) : Kind(static_cast(Kind)) {} /// The basic header type. typedef TargetTypeMetadataHeader HeaderType; private: /// The kind. Only valid for non-class metadata; getKind() must be used to get /// the kind value. StoredPointer Kind; public: /// Get the metadata kind. MetadataKind getKind() const { return getEnumeratedMetadataKind(Kind); } /// Set the metadata kind. void setKind(MetadataKind kind) { Kind = static_cast(kind); } /// Is this a class object--the metadata record for a Swift class (which also /// serves as the class object), or the class object for an ObjC class (which /// is not metadata)? bool isClassObject() const { return static_cast(getKind()) == MetadataKind::Class; } /// Does the given metadata kind represent metadata for some kind of class? static bool isAnyKindOfClass(MetadataKind k) { switch (k) { case MetadataKind::Class: case MetadataKind::ObjCClassWrapper: case MetadataKind::ForeignClass: return true; case MetadataKind::Function: case MetadataKind::Struct: case MetadataKind::Enum: case MetadataKind::Optional: case MetadataKind::Opaque: case MetadataKind::Tuple: case MetadataKind::Existential: case MetadataKind::Metatype: case MetadataKind::ExistentialMetatype: case MetadataKind::HeapLocalVariable: case MetadataKind::HeapGenericLocalVariable: case MetadataKind::ErrorObject: return false; } swift_runtime_unreachable("Unhandled MetadataKind in switch."); } /// Is this metadata for an existential type? bool isAnyExistentialType() const { switch (getKind()) { case MetadataKind::ExistentialMetatype: case MetadataKind::Existential: return true; case MetadataKind::Metatype: case MetadataKind::Class: case MetadataKind::ObjCClassWrapper: case MetadataKind::ForeignClass: case MetadataKind::Struct: case MetadataKind::Enum: case MetadataKind::Optional: case MetadataKind::Opaque: case MetadataKind::Tuple: case MetadataKind::Function: case MetadataKind::HeapLocalVariable: case MetadataKind::HeapGenericLocalVariable: case MetadataKind::ErrorObject: return false; } swift_runtime_unreachable("Unhandled MetadataKind in switch."); } /// Is this either type metadata or a class object for any kind of class? bool isAnyClass() const { return isAnyKindOfClass(getKind()); } const ValueWitnessTable *getValueWitnesses() const { return asFullMetadata(this)->ValueWitnesses; } const TypeLayout *getTypeLayout() const { return getValueWitnesses()->getTypeLayout(); } void setValueWitnesses(const ValueWitnessTable *table) { asFullMetadata(this)->ValueWitnesses = table; } // Define forwarders for value witnesses. These invoke this metadata's value // witness table with itself as the 'self' parameter. #define WANT_ONLY_REQUIRED_VALUE_WITNESSES #define FUNCTION_VALUE_WITNESS(WITNESS, UPPER, RET_TYPE, PARAM_TYPES) \ template \ _ResultOf::type \ vw_##WITNESS(A &&...args) const { \ return getValueWitnesses()->WITNESS(std::forward(args)..., this); \ } #define DATA_VALUE_WITNESS(LOWER, UPPER, TYPE) #include "swift/ABI/ValueWitness.def" int vw_getExtraInhabitantIndex(const OpaqueValue *value) const { return getValueWitnesses()->_asXIVWT()->getExtraInhabitantIndex(value, this); } void vw_storeExtraInhabitant(OpaqueValue *value, int index) const { getValueWitnesses()->_asXIVWT()->storeExtraInhabitant(value, index, this); } int vw_getEnumTag(const OpaqueValue *value) const { return getValueWitnesses()->_asEVWT()->getEnumTag(const_cast(value), this); } void vw_destructiveProjectEnumData(OpaqueValue *value) const { getValueWitnesses()->_asEVWT()->destructiveProjectEnumData(value, this); } void vw_destructiveInjectEnumTag(OpaqueValue *value, unsigned tag) const { getValueWitnesses()->_asEVWT()->destructiveInjectEnumTag(value, tag, this); } /// Allocate an out-of-line buffer if values of this type don't fit in the /// ValueBuffer. /// NOTE: This is not a box for copy-on-write existentials. OpaqueValue *allocateBufferIn(ValueBuffer *buffer) const; /// Deallocate an out-of-line buffer stored in 'buffer' if values of this type /// are not stored inline in the ValueBuffer. void deallocateBufferIn(ValueBuffer *buffer) const; // Allocate an out-of-line buffer box (reference counted) if values of this // type don't fit in the ValueBuffer. // NOTE: This *is* a box for copy-on-write existentials. OpaqueValue *allocateBoxForExistentialIn(ValueBuffer *Buffer) const; /// Get the nominal type descriptor if this metadata describes a nominal type, /// or return null if it does not. ConstTargetMetadataPointer getTypeContextDescriptor() const { switch (getKind()) { case MetadataKind::Class: { const auto cls = static_cast *>(this); if (!cls->isTypeMetadata()) return nullptr; if (cls->isArtificialSubclass()) return nullptr; return cls->getDescription(); } case MetadataKind::Struct: case MetadataKind::Enum: case MetadataKind::Optional: return static_cast *>(this) ->Description; case MetadataKind::ForeignClass: return static_cast *>(this) ->Description; case MetadataKind::Opaque: case MetadataKind::Tuple: case MetadataKind::Function: case MetadataKind::Existential: case MetadataKind::ExistentialMetatype: case MetadataKind::Metatype: case MetadataKind::ObjCClassWrapper: case MetadataKind::HeapLocalVariable: case MetadataKind::HeapGenericLocalVariable: case MetadataKind::ErrorObject: return nullptr; } swift_runtime_unreachable("Unhandled MetadataKind in switch."); } /// Get the class object for this type if it has one, or return null if the /// type is not a class (or not a class with a class object). const TargetClassMetadata *getClassObject() const; /// Retrieve the generic arguments of this type, if it has any. ConstTargetMetadataPointer const * getGenericArgs() const { auto description = getTypeContextDescriptor(); if (!description) return nullptr; auto generics = description->getGenericContext(); if (!generics) return nullptr; auto asWords = reinterpret_cast< ConstTargetMetadataPointer const *>(this); return asWords + description->getGenericArgumentOffset(this); } bool satisfiesClassConstraint() const; #if SWIFT_OBJC_INTEROP /// Get the ObjC class object for this type if it has one, or return null if /// the type is not a class (or not a class with a class object). /// This is allowed for InProcess values only. template typename std::enable_if::value, Class>::type getObjCClassObject() const { return reinterpret_cast( const_cast*>( getClassObject())); } #endif #ifndef NDEBUG LLVM_ATTRIBUTE_DEPRECATED(void dump() const LLVM_ATTRIBUTE_USED, "Only meant for use in the debugger"); #endif protected: friend struct TargetOpaqueMetadata; /// Metadata should not be publicly copied or moved. constexpr TargetMetadata(const TargetMetadata &) = default; TargetMetadata &operator=(const TargetMetadata &) = default; constexpr TargetMetadata(TargetMetadata &&) = default; TargetMetadata &operator=(TargetMetadata &&) = default; }; /// The common structure of opaque metadata. Adds nothing. template struct TargetOpaqueMetadata { typedef TargetTypeMetadataHeader HeaderType; // We have to represent this as a member so we can list-initialize it. TargetMetadata base; }; using OpaqueMetadata = TargetOpaqueMetadata; // Standard POD opaque metadata. // The "Int" metadata are used for arbitrary POD data with the // matching characteristics. using FullOpaqueMetadata = FullMetadata; #define BUILTIN_TYPE(Symbol, Name) \ SWIFT_RUNTIME_EXPORT \ const FullOpaqueMetadata METADATA_SYM(Symbol); #include "swift/Runtime/BuiltinTypes.def" /// The prefix on a heap metadata. struct HeapMetadataHeaderPrefix { /// Destroy the object, returning the allocated size of the object /// or 0 if the object shouldn't be deallocated. SWIFT_CC(swift) void (*destroy)(SWIFT_CONTEXT HeapObject *); }; /// The header present on all heap metadata. struct HeapMetadataHeader : HeapMetadataHeaderPrefix, TypeMetadataHeader { constexpr HeapMetadataHeader(const HeapMetadataHeaderPrefix &heapPrefix, const TypeMetadataHeader &typePrefix) : HeapMetadataHeaderPrefix(heapPrefix), TypeMetadataHeader(typePrefix) {} }; /// The common structure of all metadata for heap-allocated types. A /// pointer to one of these can be retrieved by loading the 'isa' /// field of any heap object, whether it was managed by Swift or by /// Objective-C. However, when loading from an Objective-C object, /// this metadata may not have the heap-metadata header, and it may /// not be the Swift type metadata for the object's dynamic type. template struct TargetHeapMetadata : TargetMetadata { typedef HeapMetadataHeader HeaderType; TargetHeapMetadata() = default; constexpr TargetHeapMetadata(const TargetMetadata &base) : TargetMetadata(base) {} }; using HeapMetadata = TargetHeapMetadata; template struct TargetMethodDescriptor { /// The method implementation. TargetRelativeDirectPointer Impl; /// Flags describing the method. MethodDescriptorFlags Flags; // TODO: add method types or anything else needed for reflection. }; /// Header for a class vtable descriptor. This is a variable-sized /// structure that describes how to find and parse a vtable /// within the type metadata for a class. template struct TargetVTableDescriptorHeader { using StoredPointer = typename Runtime::StoredPointer; private: /// The offset of the vtable for this class in its metadata, if any, /// in words. /// /// If this class has a resilient superclass, this offset is relative to the /// the start of the immediate class's metadata. Otherwise, it is relative /// to the metadata address point. uint32_t VTableOffset; public: /// The number of vtable entries. This is the number of MethodDescriptor /// records following the vtable header in the class's nominal type /// descriptor, which is equal to the number of words this subclass's vtable /// entries occupy in instantiated class metadata. uint32_t VTableSize; uint32_t getVTableOffset(const TargetClassMetadata *metadata) const { const auto *description = metadata->getDescription(); if (description->hasResilientSuperclass()) return metadata->SuperClass->getSizeInWords() + VTableOffset; return VTableOffset; } }; typedef SWIFT_CC(swift) void (*ClassIVarDestroyer)(SWIFT_CONTEXT HeapObject *); /// The structure of all class metadata. This structure is embedded /// directly within the class's heap metadata structure and therefore /// cannot be extended without an ABI break. /// /// Note that the layout of this type is compatible with the layout of /// an Objective-C class. template struct TargetClassMetadata : public TargetHeapMetadata { using StoredPointer = typename Runtime::StoredPointer; using StoredSize = typename Runtime::StoredSize; friend class ReflectionContext; TargetClassMetadata() = default; constexpr TargetClassMetadata(const TargetHeapMetadata &base, ConstTargetMetadataPointer superClass, StoredPointer data, ClassFlags flags, StoredPointer ivarDestroyer, StoredPointer size, StoredPointer addressPoint, StoredPointer alignMask, StoredPointer classSize, StoredPointer classAddressPoint) : TargetHeapMetadata(base), SuperClass(superClass), CacheData {0, 0}, Data(data), Flags(flags), InstanceAddressPoint(addressPoint), InstanceSize(size), InstanceAlignMask(alignMask), Reserved(0), ClassSize(classSize), ClassAddressPoint(classAddressPoint), Description(nullptr), IVarDestroyer(ivarDestroyer) {} // Description's copy ctor is deleted so we have to do this the hard way. TargetClassMetadata(const TargetClassMetadata &other) : TargetHeapMetadata(other), SuperClass(other.SuperClass), CacheData{other.CacheData[0], other.CacheData[1]}, Data(other.Data), Flags(other.Flags), InstanceAddressPoint(other.InstanceAddressPoint), InstanceSize(other.InstanceSize), InstanceAlignMask(other.InstanceAlignMask), Reserved(other.Reserved), ClassSize(other.ClassSize), ClassAddressPoint(other.ClassAddressPoint), Description(other.Description), IVarDestroyer(other.IVarDestroyer) {} /// The metadata for the superclass. This is null for the root class. ConstTargetMetadataPointer SuperClass; /// The cache data is used for certain dynamic lookups; it is owned /// by the runtime and generally needs to interoperate with /// Objective-C's use. StoredPointer CacheData[2]; /// The data pointer is used for out-of-line metadata and is /// generally opaque, except that the compiler sets the low bit in /// order to indicate that this is a Swift metatype and therefore /// that the type metadata header is present. StoredPointer Data; static constexpr StoredPointer offsetToData() { return offsetof(TargetClassMetadata, Data); } /// Is this object a valid swift type metadata? bool isTypeMetadata() const { return (Data & SWIFT_CLASS_IS_SWIFT_MASK); } /// A different perspective on the same bit bool isPureObjC() const { return !isTypeMetadata(); } private: // The remaining fields are valid only when isTypeMetadata(). // The Objective-C runtime knows the offsets to some of these fields. // Be careful when changing them. /// Swift-specific class flags. ClassFlags Flags; /// The address point of instances of this type. uint32_t InstanceAddressPoint; /// The required size of instances of this type. /// 'InstanceAddressPoint' bytes go before the address point; /// 'InstanceSize - InstanceAddressPoint' bytes go after it. uint32_t InstanceSize; /// The alignment mask of the address point of instances of this type. uint16_t InstanceAlignMask; /// Reserved for runtime use. uint16_t Reserved; /// The total size of the class object, including prefix and suffix /// extents. uint32_t ClassSize; /// The offset of the address point within the class object. uint32_t ClassAddressPoint; /// An out-of-line Swift-specific description of the type, or null /// if this is an artificial subclass. We currently provide no /// supported mechanism for making a non-artificial subclass /// dynamically. ConstTargetMetadataPointer Description; /// A function for destroying instance variables, used to clean up /// after an early return from a constructor. StoredPointer IVarDestroyer; // After this come the class members, laid out as follows: // - class members for the superclass (recursively) // - metadata reference for the parent, if applicable // - generic parameters for this class // - class variables (if we choose to support these) // - "tabulated" virtual methods public: ConstTargetMetadataPointer getDescription() const { assert(isTypeMetadata()); return Description; } void setDescription(const TargetClassDescriptor *description) { Description = description; } /// Only valid if the target is in-process. ClassIVarDestroyer getIVarDestroyer() const { assert(isTypeMetadata()); return reinterpret_cast(IVarDestroyer); } /// Is this class an artificial subclass, such as one dynamically /// created for various dynamic purposes like KVO? bool isArtificialSubclass() const { assert(isTypeMetadata()); return Description == 0; } void setArtificialSubclass() { assert(isTypeMetadata()); Description = 0; } ClassFlags getFlags() const { assert(isTypeMetadata()); return Flags; } void setFlags(ClassFlags flags) { assert(isTypeMetadata()); Flags = flags; } StoredSize getInstanceSize() const { assert(isTypeMetadata()); return InstanceSize; } void setInstanceSize(StoredSize size) { assert(isTypeMetadata()); InstanceSize = size; } StoredPointer getInstanceAddressPoint() const { assert(isTypeMetadata()); return InstanceAddressPoint; } void setInstanceAddressPoint(StoredSize size) { assert(isTypeMetadata()); InstanceAddressPoint = size; } StoredPointer getInstanceAlignMask() const { assert(isTypeMetadata()); return InstanceAlignMask; } void setInstanceAlignMask(StoredSize mask) { assert(isTypeMetadata()); InstanceAlignMask = mask; } StoredPointer getClassSize() const { assert(isTypeMetadata()); return ClassSize; } void setClassSize(StoredSize size) { assert(isTypeMetadata()); ClassSize = size; } StoredPointer getClassAddressPoint() const { assert(isTypeMetadata()); return ClassAddressPoint; } void setClassAddressPoint(StoredSize offset) { assert(isTypeMetadata()); ClassAddressPoint = offset; } uint16_t getRuntimeReservedData() const { assert(isTypeMetadata()); return Reserved; } void setRuntimeReservedData(uint16_t data) { assert(isTypeMetadata()); Reserved = data; } /// Get a pointer to the field offset vector, if present, or null. const StoredPointer *getFieldOffsets() const { assert(isTypeMetadata()); auto offset = getDescription()->getFieldOffsetVectorOffset(this); if (offset == 0) return nullptr; auto asWords = reinterpret_cast(this); return reinterpret_cast(asWords + offset); } uint32_t getSizeInWords() const { assert(isTypeMetadata()); uint32_t size = getClassSize() - getClassAddressPoint(); assert(size % sizeof(StoredPointer) == 0); return size / sizeof(StoredPointer); } static bool classof(const TargetMetadata *metadata) { return metadata->getKind() == MetadataKind::Class; } }; using ClassMetadata = TargetClassMetadata; /// The structure of metadata for heap-allocated local variables. /// This is non-type metadata. template struct TargetHeapLocalVariableMetadata : public TargetHeapMetadata { using StoredPointer = typename Runtime::StoredPointer; uint32_t OffsetToFirstCapture; TargetPointer CaptureDescription; static bool classof(const TargetMetadata *metadata) { return metadata->getKind() == MetadataKind::HeapLocalVariable; } constexpr TargetHeapLocalVariableMetadata() : TargetHeapMetadata(MetadataKind::HeapLocalVariable), OffsetToFirstCapture(0), CaptureDescription(nullptr) {} }; using HeapLocalVariableMetadata = TargetHeapLocalVariableMetadata; /// The structure of wrapper metadata for Objective-C classes. This /// is used as a type metadata pointer when the actual class isn't /// Swift-compiled. template struct TargetObjCClassWrapperMetadata : public TargetMetadata { ConstTargetMetadataPointer Class; static bool classof(const TargetMetadata *metadata) { return metadata->getKind() == MetadataKind::ObjCClassWrapper; } }; using ObjCClassWrapperMetadata = TargetObjCClassWrapperMetadata; /// The structure of metadata for foreign types where the source /// language doesn't provide any sort of more interesting metadata for /// us to use. template struct TargetForeignTypeMetadata : public TargetMetadata { using StoredPointer = typename Runtime::StoredPointer; using StoredSize = typename Runtime::StoredSize; using InitializationFunction_t = void (TargetForeignTypeMetadata *selectedMetadata); using RuntimeMetadataPointer = ConstTargetMetadataPointer; /// An invasive cache for the runtime-uniqued lookup structure that is stored /// in the header prefix of foreign metadata records. /// /// Prior to initialization, as emitted by the compiler, this contains the /// initialization flags. /// After initialization, it holds a pointer to the actual, runtime-uniqued /// metadata for this type. struct CacheValue { StoredSize Value; /// Work around a bug in libstdc++'s std::atomic that requires the type to /// be default-constructible. CacheValue() = default; explicit CacheValue(RuntimeMetadataPointer p) : Value(reinterpret_cast(p)) {} /// Various flags. The largest flag bit should be less than 4096 so that /// a flag set is distinguishable from a valid pointer. enum : StoredSize { /// This metadata has an initialization callback function. If /// this flag is not set, the metadata object needn't actually /// have a InitializationFunction field, and that field will be /// undefined. HasInitializationFunction = 0x1, LargestFlagMask = 0xFFF, }; /// True if the metadata record associated with this cache has not been /// initialized, so contains a flag set describing parameters to the /// initialization operation. isFlags() == !isInitialized() bool isFlags() const { return Value <= LargestFlagMask; } /// True if the metadata record associated with this cache has an /// initialization function which must be run if it is picked as the /// canonical metadata record for its key. /// /// Undefined if !isFlags(). bool hasInitializationFunction() const { assert(isFlags()); return Value & HasInitializationFunction; } /// True if the metadata record associated with this cache has been /// initialized, so the cache contains an absolute pointer to the /// canonical metadata record for its key. isInitialized() == !isFlags() bool isInitialized() const { return !isFlags(); } /// Gets the cached pointer to the unique canonical metadata record for /// this metadata record's key. /// /// Undefined if !isInitialized(). RuntimeMetadataPointer getCachedUniqueMetadata() const { assert(isInitialized()); return RuntimeMetadataPointer(Value); } }; /// Foreign type metadata may have extra header fields depending on /// the flags. struct HeaderPrefix { /// An optional callback performed when a particular metadata object /// is chosen as the unique structure. /// /// If there is no initialization function, this metadata record can be /// assumed to be immutable (except for the \c Unique invasive cache /// field). The field is not present unless the HasInitializationFunction /// flag is set. RelativeDirectPointer InitializationFunction; /// The uniquing key for the metadata record. Metadata records with the /// same Name string are considered equivalent by the runtime, and the /// runtime will pick one to be canonical. RelativeDirectPointer Name; mutable std::atomic Cache; }; struct HeaderType : HeaderPrefix, TypeMetadataHeader {}; TargetPointer getName() const { return reinterpret_cast>( asFullMetadata(this)->Name.get()); } CacheValue getCacheValue() const { /// NB: This can be a relaxed-order load if there is no initialization /// function. On platforms Swift currently targets, consume is no more /// expensive than relaxed, so there's no reason to branch here (and LLVM /// isn't smart enough to eliminate it when it's not needed). /// /// A port to a platform where relaxed is significantly less expensive than /// consume (historically, Alpha) would probably want to preserve the /// 'hasInitializationFunction' bit in its own word to be able to avoid /// the consuming load when not needed. return asFullMetadata(this)->Cache .load(SWIFT_MEMORY_ORDER_CONSUME); } void setCachedUniqueMetadata(RuntimeMetadataPointer unique) const { auto cache = getCacheValue(); // If the cache was already set to a pointer, we're done. We ought to // converge on a single unique pointer. if (cache.isInitialized()) { assert(cache.getCachedUniqueMetadata() == unique && "already set unique metadata to something else"); return; } auto newCache = CacheValue(unique); // If there is no initialization function, this can be a relaxed store. if (cache.hasInitializationFunction()) asFullMetadata(this)->Cache.store(newCache, std::memory_order_relaxed); // Otherwise, we need a release store to publish the result of // initialization. else asFullMetadata(this)->Cache.store(newCache, std::memory_order_release); } /// Return the initialization function for this metadata record. /// /// As a prerequisite, the metadata record must not have been initialized yet, /// and must have an initialization function to begin with, otherwise the /// result is undefined. InitializationFunction_t *getInitializationFunction() const { #ifndef NDEBUG auto cache = getCacheValue(); assert(cache.hasInitializationFunction()); #endif return asFullMetadata(this)->InitializationFunction; } }; using ForeignTypeMetadata = TargetForeignTypeMetadata; /// The structure of metadata objects for foreign class types. /// A foreign class is a foreign type with reference semantics and /// Swift-supported reference counting. Generally this requires /// special logic in the importer. /// /// We assume for now that foreign classes are entirely opaque /// to Swift introspection. template struct TargetForeignClassMetadata : public TargetForeignTypeMetadata { using StoredPointer = typename Runtime::StoredPointer; /// An out-of-line description of the type. ConstTargetMetadataPointer Description; /// The superclass of the foreign class, if any. ConstTargetMetadataPointer SuperClass; /// Reserved space. For now, these should be zero-initialized. StoredPointer Reserved[3]; static bool classof(const TargetMetadata *metadata) { return metadata->getKind() == MetadataKind::ForeignClass; } }; using ForeignClassMetadata = TargetForeignClassMetadata; /// The common structure of metadata for structs and enums. template struct TargetValueMetadata : public TargetMetadata { using StoredPointer = typename Runtime::StoredPointer; TargetValueMetadata(MetadataKind Kind, const TargetTypeContextDescriptor *description) : TargetMetadata(Kind), Description(description) {} /// An out-of-line description of the type. ConstTargetMetadataPointer Description; static bool classof(const TargetMetadata *metadata) { return metadata->getKind() == MetadataKind::Struct || metadata->getKind() == MetadataKind::Enum || metadata->getKind() == MetadataKind::Optional; } ConstTargetMetadataPointer getDescription() const { return Description; } }; using ValueMetadata = TargetValueMetadata; /// The structure of type metadata for structs. template struct TargetStructMetadata : public TargetValueMetadata { using StoredPointer = typename Runtime::StoredPointer; using TargetValueMetadata::TargetValueMetadata; const TargetStructDescriptor *getDescription() const { return llvm::cast>(this->Description); } /// Get a pointer to the field offset vector, if present, or null. const StoredPointer *getFieldOffsets() const { auto offset = getDescription()->FieldOffsetVectorOffset; if (offset == 0) return nullptr; auto asWords = reinterpret_cast(this); return reinterpret_cast(asWords + offset); } static bool classof(const TargetMetadata *metadata) { return metadata->getKind() == MetadataKind::Struct; } }; using StructMetadata = TargetStructMetadata; /// The structure of type metadata for enums. template struct TargetEnumMetadata : public TargetValueMetadata { using StoredPointer = typename Runtime::StoredPointer; using StoredSize = typename Runtime::StoredSize; using TargetValueMetadata::TargetValueMetadata; const TargetEnumDescriptor *getDescription() const { return llvm::cast>(this->Description); } /// True if the metadata records the size of the payload area. bool hasPayloadSize() const { return getDescription()->hasPayloadSizeOffset(); } /// Retrieve the size of the payload area. /// /// `hasPayloadSize` must be true for this to be valid. StoredSize getPayloadSize() const { assert(hasPayloadSize()); auto offset = getDescription()->getPayloadSizeOffset(); const StoredSize *asWords = reinterpret_cast(this); asWords += offset; return *asWords; } StoredSize &getPayloadSize() { assert(hasPayloadSize()); auto offset = getDescription()->getPayloadSizeOffset(); StoredSize *asWords = reinterpret_cast(this); asWords += offset; return *asWords; } static bool classof(const TargetMetadata *metadata) { return metadata->getKind() == MetadataKind::Enum || metadata->getKind() == MetadataKind::Optional; } }; using EnumMetadata = TargetEnumMetadata; /// The structure of function type metadata. template struct TargetFunctionTypeMetadata : public TargetMetadata { using StoredSize = typename Runtime::StoredSize; using Parameter = ConstTargetMetadataPointer; TargetFunctionTypeFlags Flags; /// The type metadata for the result type. ConstTargetMetadataPointer ResultType; Parameter *getParameters() { return reinterpret_cast(this + 1); } const Parameter *getParameters() const { return reinterpret_cast(this + 1); } Parameter getParameter(unsigned index) const { assert(index < getNumParameters()); return getParameters()[index]; } ParameterFlags getParameterFlags(unsigned index) const { assert(index < getNumParameters()); auto flags = hasParameterFlags() ? getParameterFlags()[index] : 0; return ParameterFlags::fromIntValue(flags); } StoredSize getNumParameters() const { return Flags.getNumParameters(); } FunctionMetadataConvention getConvention() const { return Flags.getConvention(); } bool throws() const { return Flags.throws(); } bool hasParameterFlags() const { return Flags.hasParameterFlags(); } bool isEscaping() const { return Flags.isEscaping(); } static constexpr StoredSize OffsetToFlags = sizeof(TargetMetadata); static bool classof(const TargetMetadata *metadata) { return metadata->getKind() == MetadataKind::Function; } uint32_t *getParameterFlags() { return reinterpret_cast(getParameters() + getNumParameters()); } const uint32_t *getParameterFlags() const { return reinterpret_cast(getParameters() + getNumParameters()); } }; using FunctionTypeMetadata = TargetFunctionTypeMetadata; /// The structure of metadata for metatypes. template struct TargetMetatypeMetadata : public TargetMetadata { /// The type metadata for the element. ConstTargetMetadataPointer InstanceType; static bool classof(const TargetMetadata *metadata) { return metadata->getKind() == MetadataKind::Metatype; } }; using MetatypeMetadata = TargetMetatypeMetadata; /// The structure of tuple type metadata. template struct TargetTupleTypeMetadata : public TargetMetadata { using StoredSize = typename Runtime::StoredSize; TargetTupleTypeMetadata() = default; constexpr TargetTupleTypeMetadata(const TargetMetadata &base, StoredSize numElements, TargetPointer labels) : TargetMetadata(base), NumElements(numElements), Labels(labels) {} /// The number of elements. StoredSize NumElements; /// The labels string; see swift_getTupleTypeMetadata. TargetPointer Labels; struct Element { /// The type of the element. ConstTargetMetadataPointer Type; /// The offset of the tuple element within the tuple. StoredSize Offset; OpaqueValue *findIn(OpaqueValue *tuple) const { return (OpaqueValue*) (((char*) tuple) + Offset); } }; Element *getElements() { return reinterpret_cast(this + 1); } const Element *getElements() const { return reinterpret_cast(this + 1); } const Element &getElement(unsigned i) const { return getElements()[i]; } Element &getElement(unsigned i) { return getElements()[i]; } static constexpr StoredSize OffsetToNumElements = sizeof(TargetMetadata); static bool classof(const TargetMetadata *metadata) { return metadata->getKind() == MetadataKind::Tuple; } }; using TupleTypeMetadata = TargetTupleTypeMetadata; /// The standard metadata for the empty tuple type. SWIFT_RUNTIME_EXPORT const FullMetadata METADATA_SYM(EMPTY_TUPLE_MANGLING); template struct TargetProtocolDescriptor; /// An array of protocol descriptors with a header and tail-allocated elements. template struct TargetProtocolDescriptorList { using StoredPointer = typename Runtime::StoredPointer; StoredPointer NumProtocols; ConstTargetMetadataPointer * getProtocols() { return reinterpret_cast< ConstTargetMetadataPointer< Runtime, TargetProtocolDescriptor> *>(this + 1); } ConstTargetMetadataPointer const * getProtocols() const { return reinterpret_cast< ConstTargetMetadataPointer< Runtime, TargetProtocolDescriptor> const *>(this + 1); } ConstTargetMetadataPointer const & operator[](size_t i) const { return getProtocols()[i]; } ConstTargetMetadataPointer & operator[](size_t i) { return getProtocols()[i]; } constexpr TargetProtocolDescriptorList() : NumProtocols(0) {} protected: constexpr TargetProtocolDescriptorList(StoredPointer NumProtocols) : NumProtocols(NumProtocols) {} }; using ProtocolDescriptorList = TargetProtocolDescriptorList; /// A literal class for creating constant protocol descriptors in the runtime. template struct TargetLiteralProtocolDescriptorList : TargetProtocolDescriptorList { const TargetProtocolDescriptorList *Protocols[NUM_PROTOCOLS]; template constexpr TargetLiteralProtocolDescriptorList(DescriptorPointers...elements) : TargetProtocolDescriptorList(NUM_PROTOCOLS), Protocols{elements...} {} }; using LiteralProtocolDescriptorList = TargetProtocolDescriptorList; template struct TargetProtocolRequirement { ProtocolRequirementFlags Flags; // TODO: name, type /// The optional default implementation of the protocol. RelativeDirectPointer DefaultImplementation; }; using ProtocolRequirement = TargetProtocolRequirement; /// A protocol descriptor. This is not type metadata, but is referenced by /// existential type metadata records to describe a protocol constraint. /// Its layout is compatible with the Objective-C runtime's 'protocol_t' record /// layout. template struct TargetProtocolDescriptor { using StoredPointer = typename Runtime::StoredPointer; /// Unused by the Swift runtime. TargetPointer _ObjC_Isa; /// The mangled name of the protocol. TargetPointer Name; /// The list of protocols this protocol refines. ConstTargetMetadataPointer InheritedProtocols; /// Unused by the Swift runtime. TargetPointer _ObjC_InstanceMethods, _ObjC_ClassMethods, _ObjC_OptionalInstanceMethods, _ObjC_OptionalClassMethods, _ObjC_InstanceProperties; /// Size of the descriptor record. uint32_t DescriptorSize; /// Additional flags. ProtocolDescriptorFlags Flags; /// The number of non-defaultable requirements in the protocol. uint16_t NumMandatoryRequirements; /// The number of requirements described by the Requirements array. /// If any requirements beyond MinimumWitnessTableSizeInWords are present /// in the witness table template, they will be not be overwritten with /// defaults. uint16_t NumRequirements; /// Requirement descriptions. RelativeDirectPointer> Requirements; /// The superclass of which all conforming types must be a subclass. RelativeDirectPointer, /*Nullable=*/true> Superclass; /// Associated type names, as a space-separated list in the same order /// as the requirements. RelativeDirectPointer AssociatedTypeNames; void *getDefaultWitness(unsigned index) const { return Requirements.get()[index].DefaultImplementation.get(); } // This is only used in unittests/Metadata.cpp. constexpr TargetProtocolDescriptor(const char *Name, const TargetProtocolDescriptorList *Inherited, ProtocolDescriptorFlags Flags) : _ObjC_Isa(nullptr), Name(Name), InheritedProtocols(Inherited), _ObjC_InstanceMethods(nullptr), _ObjC_ClassMethods(nullptr), _ObjC_OptionalInstanceMethods(nullptr), _ObjC_OptionalClassMethods(nullptr), _ObjC_InstanceProperties(nullptr), DescriptorSize(sizeof(TargetProtocolDescriptor)), Flags(Flags), NumMandatoryRequirements(0), NumRequirements(0), Requirements(nullptr), Superclass(nullptr), AssociatedTypeNames(nullptr) {} #ifndef NDEBUG LLVM_ATTRIBUTE_DEPRECATED(void dump() const LLVM_ATTRIBUTE_USED, "only for use in the debugger"); #endif }; using ProtocolDescriptor = TargetProtocolDescriptor; /// A witness table for a protocol. /// /// With the exception of the initial protocol conformance descriptor, /// the layout of a witness table is dependent on the protocol being /// represented. template struct TargetWitnessTable { /// The protocol conformance descriptor from which this witness table /// was generated. ConstTargetMetadataPointer Description; }; using WitnessTable = TargetWitnessTable; template using TargetWitnessTablePointer = ConstTargetMetadataPointer; using WitnessTablePointer = TargetWitnessTablePointer; /// The possible physical representations of existential types. enum class ExistentialTypeRepresentation { /// The type uses an opaque existential representation. Opaque, /// The type uses a class existential representation. Class, /// The type uses the Error boxed existential representation. Error, }; /// The structure of existential type metadata. template struct TargetExistentialTypeMetadata : public TargetMetadata { using StoredPointer = typename Runtime::StoredPointer; /// The number of witness tables and class-constrained-ness of the type. ExistentialTypeFlags Flags; /// The protocol constraints. TargetProtocolDescriptorList Protocols; /// NB: Protocols has a tail-emplaced array; additional fields cannot follow. constexpr TargetExistentialTypeMetadata() : TargetMetadata(MetadataKind::Existential), Flags(ExistentialTypeFlags()), Protocols() {} /// Get the representation form this existential type uses. ExistentialTypeRepresentation getRepresentation() const; /// True if it's valid to take ownership of the value in the existential /// container if we own the container. bool mayTakeValue(const OpaqueValue *container) const; /// Clean up an existential container whose value is uninitialized. void deinitExistentialContainer(OpaqueValue *container) const; /// Project the value pointer from an existential container of the type /// described by this metadata. const OpaqueValue *projectValue(const OpaqueValue *container) const; OpaqueValue *projectValue(OpaqueValue *container) const { return const_cast(projectValue((const OpaqueValue*)container)); } /// Get the dynamic type from an existential container of the type described /// by this metadata. const TargetMetadata * getDynamicType(const OpaqueValue *container) const; /// Get a witness table from an existential container of the type described /// by this metadata. const TargetWitnessTable * getWitnessTable( const OpaqueValue *container, unsigned i) const; /// Return true iff all the protocol constraints are @objc. bool isObjC() const { return isClassBounded() && Flags.getNumWitnessTables() == 0; } bool isClassBounded() const { return Flags.getClassConstraint() == ProtocolClassConstraint::Class; } const TargetMetadata *getSuperclassConstraint() const { if (!Flags.hasSuperclassConstraint()) return nullptr; // Get a pointer to tail-allocated storage for this metadata record. auto Pointer = reinterpret_cast< ConstTargetMetadataPointer const *>(this + 1); // The superclass immediately follows the list of protocol descriptors. return Pointer[Protocols.NumProtocols]; } static bool classof(const TargetMetadata *metadata) { return metadata->getKind() == MetadataKind::Existential; } static constexpr StoredPointer OffsetToNumProtocols = sizeof(TargetMetadata) + sizeof(ExistentialTypeFlags); }; using ExistentialTypeMetadata = TargetExistentialTypeMetadata; /// The basic layout of an existential metatype type. template struct TargetExistentialMetatypeContainer { ConstTargetMetadataPointer Value; TargetWitnessTablePointer *getWitnessTables() { return reinterpret_cast *>(this + 1); } TargetWitnessTablePointer const *getWitnessTables() const { return reinterpret_cast const *>(this+1); } void copyTypeInto(TargetExistentialMetatypeContainer *dest, unsigned numTables) const { for (unsigned i = 0; i != numTables; ++i) dest->getWitnessTables()[i] = getWitnessTables()[i]; } }; using ExistentialMetatypeContainer = TargetExistentialMetatypeContainer; /// The structure of metadata for existential metatypes. template struct TargetExistentialMetatypeMetadata : public TargetMetadata { /// The type metadata for the element. ConstTargetMetadataPointer InstanceType; /// The number of witness tables and class-constrained-ness of the /// underlying type. ExistentialTypeFlags Flags; static bool classof(const TargetMetadata *metadata) { return metadata->getKind() == MetadataKind::ExistentialMetatype; } /// Return true iff all the protocol constraints are @objc. bool isObjC() const { return isClassBounded() && Flags.getNumWitnessTables() == 0; } bool isClassBounded() const { return Flags.getClassConstraint() == ProtocolClassConstraint::Class; } }; using ExistentialMetatypeMetadata = TargetExistentialMetatypeMetadata; /// The instantiation cache for generic metadata. This must be guaranteed /// to zero-initialized before it is first accessed. Its contents are private /// to the runtime. template struct TargetGenericMetadataInstantiationCache { /// Data that the runtime can use for its own purposes. It is guaranteed /// to be zero-filled by the compiler. TargetPointer PrivateData[swift::NumGenericMetadataPrivateDataWords]; }; using GenericMetadataInstantiationCache = TargetGenericMetadataInstantiationCache; /// Heap metadata for a box, which may have been generated statically by the /// compiler or by the runtime. template struct TargetBoxHeapMetadata : public TargetHeapMetadata { /// The offset from the beginning of a box to its value. unsigned Offset; constexpr TargetBoxHeapMetadata(MetadataKind kind, unsigned offset) : TargetHeapMetadata(kind), Offset(offset) {} }; using BoxHeapMetadata = TargetBoxHeapMetadata; /// Heap metadata for runtime-instantiated generic boxes. template struct TargetGenericBoxHeapMetadata : public TargetBoxHeapMetadata { using super = TargetBoxHeapMetadata; using super::Offset; /// The type inside the box. ConstTargetMetadataPointer BoxedType; constexpr TargetGenericBoxHeapMetadata(MetadataKind kind, unsigned offset, ConstTargetMetadataPointer boxedType) : TargetBoxHeapMetadata(kind, offset), BoxedType(boxedType) {} static unsigned getHeaderOffset(const Metadata *boxedType) { // Round up the header size to alignment. unsigned alignMask = boxedType->getValueWitnesses()->getAlignmentMask(); return (sizeof(HeapObject) + alignMask) & ~alignMask; } /// Project the value out of a box of this type. OpaqueValue *project(HeapObject *box) const { auto bytes = reinterpret_cast(box); return reinterpret_cast(bytes + Offset); } /// Get the allocation size of this box. unsigned getAllocSize() const { return Offset + BoxedType->getValueWitnesses()->getSize(); } /// Get the allocation alignment of this box. unsigned getAllocAlignMask() const { // Heap allocations are at least pointer aligned. return BoxedType->getValueWitnesses()->getAlignmentMask() | (alignof(void*) - 1); } static bool classof(const TargetMetadata *metadata) { return metadata->getKind() == MetadataKind::HeapGenericLocalVariable; } }; using GenericBoxHeapMetadata = TargetGenericBoxHeapMetadata; /// \brief The control structure of a generic or resilient protocol /// conformance. /// /// Witness tables need to be instantiated at runtime in these cases: /// - For a generic conforming type, associated type requirements might be /// dependent on the conforming type. /// - For a type conforming to a resilient protocol, the runtime size of /// the witness table is not known because default requirements can be /// added resiliently. /// /// One per conformance. template struct TargetGenericWitnessTable { /// The size of the witness table in words. This amount is copied from /// the witness table template into the instantiated witness table. uint16_t WitnessTableSizeInWords; /// The amount of private storage to allocate before the address point, /// in words. This memory is zeroed out in the instantiated witness table /// template. uint16_t WitnessTablePrivateSizeInWords; /// The protocol descriptor. Only used for resilient conformances. RelativeIndirectablePointer Protocol; /// The pattern. RelativeDirectPointer> Pattern; /// The instantiation function, which is called after the template is copied. RelativeDirectPointer *instantiatedTable, const TargetMetadata *type, void * const *instantiationArgs), /*nullable*/ true> Instantiator; using PrivateDataType = void *[swift::NumGenericMetadataPrivateDataWords]; /// Private data for the instantiator. Out-of-line so that the rest /// of this structure can be constant. RelativeDirectPointer PrivateData; }; using GenericWitnessTable = TargetGenericWitnessTable; /// The structure of a type metadata record. /// /// This contains enough static information to recover type metadata from a /// name. template struct TargetTypeMetadataRecord { private: union { /// A direct reference to a nominal type descriptor. RelativeDirectPointerIntPair, TypeMetadataRecordKind> DirectNominalTypeDescriptor; /// An indirect reference to a nominal type descriptor. RelativeDirectPointerIntPair * const, TypeMetadataRecordKind> IndirectNominalTypeDescriptor; }; public: TypeMetadataRecordKind getTypeKind() const { return DirectNominalTypeDescriptor.getInt(); } const TargetTypeContextDescriptor * getTypeContextDescriptor() const { switch (getTypeKind()) { case TypeMetadataRecordKind::DirectNominalTypeDescriptor: return DirectNominalTypeDescriptor.getPointer(); case TypeMetadataRecordKind::Reserved: case TypeMetadataRecordKind::IndirectObjCClass: return nullptr; case TypeMetadataRecordKind::IndirectNominalTypeDescriptor: return *IndirectNominalTypeDescriptor.getPointer(); } return nullptr; } }; using TypeMetadataRecord = TargetTypeMetadataRecord; template struct TargetContextDescriptor; template using RelativeContextPointer = RelativeIndirectablePointer, /*nullable*/ true>; /// The structure of a protocol reference record. template struct TargetProtocolRecord { /// The protocol referenced. /// /// The remaining low bit is reserved for future use. RelativeIndirectablePointerIntPair, /*reserved=*/bool> Protocol; }; using ProtocolRecord = TargetProtocolRecord; template class TargetGenericRequirementDescriptor; /// The structure of a protocol conformance. /// /// This contains enough static information to recover the witness table for a /// type's conformance to a protocol. template struct TargetProtocolConformanceDescriptor final : public swift::ABI::TrailingObjects< TargetProtocolConformanceDescriptor, RelativeContextPointer, TargetGenericRequirementDescriptor> { using TrailingObjects = swift::ABI::TrailingObjects< TargetProtocolConformanceDescriptor, RelativeContextPointer, TargetGenericRequirementDescriptor>; friend TrailingObjects; template using OverloadToken = typename TrailingObjects::template OverloadToken; public: using WitnessTableAccessorFn = const TargetWitnessTable *(const TargetMetadata*, const TargetWitnessTable **, size_t); using GenericRequirementDescriptor = TargetGenericRequirementDescriptor; private: /// The protocol being conformed to. /// /// The remaining low bit is reserved for future use. RelativeIndirectablePointer Protocol; // Some description of the type that conforms to the protocol. union { /// A direct reference to a nominal type descriptor. RelativeDirectPointer> DirectNominalTypeDescriptor; /// An indirect reference to a nominal type descriptor. RelativeDirectPointer< ConstTargetMetadataPointer> IndirectNominalTypeDescriptor; /// An indirect reference to the metadata. RelativeDirectPointer< ConstTargetMetadataPointer> IndirectObjCClass; }; // The conformance, or a generator function for the conformance. union { /// A direct reference to the witness table for the conformance. RelativeDirectPointer> WitnessTable; /// A function that produces the witness table given an instance of the /// type. RelativeDirectPointer WitnessTableAccessor; }; /// Various flags, including the kind of conformance. ConformanceFlags Flags; public: const ProtocolDescriptor *getProtocol() const { return Protocol; } TypeMetadataRecordKind getTypeKind() const { return Flags.getTypeReferenceKind(); } typename ConformanceFlags::ConformanceKind getConformanceKind() const { return Flags.getConformanceKind(); } const TargetClassMetadata * const *getIndirectObjCClass() const { switch (getTypeKind()) { case TypeMetadataRecordKind::IndirectObjCClass: break; case TypeMetadataRecordKind::Reserved: return nullptr; case TypeMetadataRecordKind::DirectNominalTypeDescriptor: case TypeMetadataRecordKind::IndirectNominalTypeDescriptor: assert(false && "not indirect class object"); } return IndirectObjCClass.get(); } const TargetTypeContextDescriptor * getTypeContextDescriptor() const { switch (getTypeKind()) { case TypeMetadataRecordKind::DirectNominalTypeDescriptor: return DirectNominalTypeDescriptor; case TypeMetadataRecordKind::IndirectNominalTypeDescriptor: return *IndirectNominalTypeDescriptor; case TypeMetadataRecordKind::Reserved: case TypeMetadataRecordKind::IndirectObjCClass: return nullptr; } return nullptr; } /// Retrieve the context of a retroactive conformance. const TargetContextDescriptor *getRetroactiveContext() const { if (!Flags.isRetroactive()) return nullptr; return this->template getTrailingObjects>(); } /// Retrieve the conditional requirements that must also be /// satisfied llvm::ArrayRef getConditionalRequirements() const { return {this->template getTrailingObjects(), Flags.getNumConditionalRequirements()}; } /// Get the directly-referenced static witness table. const swift::TargetWitnessTable *getStaticWitnessTable() const { switch (getConformanceKind()) { case ConformanceFlags::ConformanceKind::WitnessTable: break; case ConformanceFlags::ConformanceKind::WitnessTableAccessor: case ConformanceFlags::ConformanceKind::ConditionalWitnessTableAccessor: assert(false && "not witness table"); } return WitnessTable; } WitnessTableAccessorFn *getWitnessTableAccessor() const { switch (getConformanceKind()) { case ConformanceFlags::ConformanceKind::WitnessTableAccessor: case ConformanceFlags::ConformanceKind::ConditionalWitnessTableAccessor: break; case ConformanceFlags::ConformanceKind::WitnessTable: assert(false && "not witness table accessor"); } return WitnessTableAccessor; } /// Get the canonical metadata for the type referenced by this record, or /// return null if the record references a generic or universal type. const TargetMetadata *getCanonicalTypeMetadata() const; /// Get the witness table for the specified type, realizing it if /// necessary, or return null if the conformance does not apply to the /// type. const swift::TargetWitnessTable * getWitnessTable(const TargetMetadata *type) const; #if !defined(NDEBUG) && SWIFT_OBJC_INTEROP void dump() const; #endif #ifndef NDEBUG /// Verify that the protocol descriptor obeys all invariants. /// /// We currently check that the descriptor: /// /// 1. Has a valid TypeMetadataRecordKind. /// 2. Has a valid conformance kind. void verify() const LLVM_ATTRIBUTE_USED; #endif private: size_t numTrailingObjects( OverloadToken>) const { return Flags.isRetroactive() ? 1 : 0; } size_t numTrailingObjects(OverloadToken) const { return Flags.getNumConditionalRequirements(); } }; using ProtocolConformanceDescriptor = TargetProtocolConformanceDescriptor; template using TargetProtocolConformanceRecord = RelativeDirectPointer, /*Nullable=*/false>; using ProtocolConformanceRecord = TargetProtocolConformanceRecord; template struct TargetGenericContext; /// Base class for all context descriptors. template struct TargetContextDescriptor { /// Flags describing the context, including its kind and format version. ContextDescriptorFlags Flags; /// The parent context, or null if this is a top-level context. RelativeContextPointer Parent; bool isGeneric() const { return Flags.isGeneric(); } bool isUnique() const { return Flags.isUnique(); } ContextDescriptorKind getKind() const { return Flags.getKind(); } /// Get the generic context information for this context, or null if the /// context is not generic. const TargetGenericContext *getGenericContext() const; unsigned getNumGenericParams() const { auto *genericContext = getGenericContext(); return genericContext ? genericContext->getGenericContextHeader().NumParams : 0; } private: TargetContextDescriptor(const TargetContextDescriptor &) = delete; TargetContextDescriptor(TargetContextDescriptor &&) = delete; TargetContextDescriptor &operator=(const TargetContextDescriptor &) = delete; TargetContextDescriptor &operator=(TargetContextDescriptor &&) = delete; }; using ContextDescriptor = TargetContextDescriptor; /// True if two context descriptors in the currently running program describe /// the same context. bool equalContexts(const ContextDescriptor *a, const ContextDescriptor *b); /// Descriptor for a module context. template struct TargetModuleContextDescriptor final : TargetContextDescriptor { /// The module name. RelativeDirectPointer Name; static bool classof(const TargetContextDescriptor *cd) { return cd->getKind() == ContextDescriptorKind::Module; } }; using ModuleContextDescriptor = TargetModuleContextDescriptor; struct GenericContextDescriptorHeader { unsigned NumParams, NumRequirements, NumKeyArguments, NumExtraArguments; unsigned getNumArguments() const { return NumKeyArguments + NumExtraArguments; } bool hasArguments() const { return getNumArguments() > 0; } }; /// A reference to a generic parameter that is the subject of a requirement. /// This can refer either directly to a generic parameter or to a path to an /// associated type. template class TargetGenericParamRef { union { /// The word of storage, whose low bit indicates whether there is an /// associated type path stored out-of-line and whose upper bits describe /// the generic parameter at root of the path. uint32_t Word; /// This is the associated type path stored out-of-line. The \c bool /// is used for masking purposes and is otherwise unused; instead, check /// the low bit of \c Word. RelativeDirectPointerIntPair AssociatedTypePath; }; public: /// Index of the parameter being referenced. 0 is the first generic parameter /// of the root of the context hierarchy, and subsequent parameters are /// numbered breadth-first from there. unsigned getRootParamIndex() const { // If there is no path, retrieve the index directly. if ((Word & 0x01) == 0) return Word >> 1; // Otherwise, the index is at the start of the associated type path. return *reinterpret_cast(AssociatedTypePath.getPointer()); } /// A reference to an associated type along the reference path. struct AssociatedTypeRef { /// The protocol the associated type belongs to. RelativeIndirectablePointer, /*nullable*/ false> Protocol; /// The index of the associated type metadata within a witness table for /// the protocol. unsigned Index; }; /// A forward iterator that walks through the associated type path, which is /// a zero-terminated array of AssociatedTypeRefs. class AssociatedTypeIterator { const void *addr; explicit AssociatedTypeIterator(const void *startAddr) : addr(startAddr) {} bool isEnd() const { if (addr == nullptr) return true; unsigned word; memcpy(&word, addr, sizeof(unsigned)); if (word == 0) return true; return false; } template friend class TargetGenericParamRef; public: AssociatedTypeIterator() : addr(nullptr) {} using iterator_category = std::forward_iterator_tag; using value_type = AssociatedTypeRef; using difference_type = std::ptrdiff_t; using pointer = const AssociatedTypeRef *; using reference = const AssociatedTypeRef &; bool operator==(AssociatedTypeIterator i) const { // Iterators are same if they both point at the same place, or are both // at the end (either by being initialized as an end iterator with a // null address, or by being advanced to the null terminator of an // associated type list). if (addr == i.addr) return true; if (isEnd() && i.isEnd()) return true; return false; } bool operator!=(AssociatedTypeIterator i) const { return !(*this == i); } reference operator*() const { return *reinterpret_cast(addr); } pointer operator->() const { return reinterpret_cast(addr); } AssociatedTypeIterator &operator++() { addr = reinterpret_cast(addr) + sizeof(AssociatedTypeRef); return *this; } AssociatedTypeIterator operator++(int) { auto copy = *this; ++*this; return copy; } }; /// Iterators for going through the associated type path from the root param. AssociatedTypeIterator begin() const { if (Word & 0x01) { // The associated types start after the first word, which holds the // root param index. return AssociatedTypeIterator( reinterpret_cast(AssociatedTypePath.getPointer()) + sizeof(unsigned)); } else { // This is a direct param reference, so there are no associated types. return end(); } } AssociatedTypeIterator end() const { return AssociatedTypeIterator{}; } }; using GenericParamRef = TargetGenericParamRef; template class TargetGenericRequirementDescriptor { public: GenericRequirementFlags Flags; /// The generic parameter or associated type that's constrained. TargetGenericParamRef Param; private: union { /// A mangled representation of the same-type or base class the param is /// constrained to. /// /// Only valid if the requirement has SameType or BaseClass kind. RelativeDirectPointer Type; /// The protocol the param is constrained to. /// /// Only valid if the requirement has Protocol kind. RelativeIndirectablePointer, /*nullable*/ false> Protocol; /// The conformance the param is constrained to use. /// /// Only valid if the requirement has SameConformance kind. RelativeIndirectablePointer, /*nullable*/ false> Conformance; /// The kind of layout constraint. /// /// Only valid if the requirement has Layout kind. GenericRequirementLayoutKind Layout; }; public: constexpr GenericRequirementFlags getFlags() const { return Flags; } constexpr GenericRequirementKind getKind() const { return getFlags().getKind(); } /// Retrieve the generic parameter that is the subject of this requirement. const TargetGenericParamRef &getParam() const { return Param; } /// Retrieve the protocol descriptor for a Protocol requirement. const TargetProtocolDescriptor *getProtocol() const { assert(getKind() == GenericRequirementKind::Protocol); return Protocol; } /// Retrieve the right-hand type for a SameType or BaseClass requirement. StringRef getMangledTypeName() const { assert(getKind() == GenericRequirementKind::SameType || getKind() == GenericRequirementKind::BaseClass); return swift::Demangle::makeSymbolicMangledNameStringRef(Type.get()); } /// Retrieve the protocol conformance record for a SameConformance /// requirement. const TargetProtocolConformanceRecord *getConformance() const { assert(getKind() == GenericRequirementKind::SameConformance); return Conformance; } /// Retrieve the layout constraint. GenericRequirementLayoutKind getLayout() const { assert(getKind() == GenericRequirementKind::Layout); return Layout; } /// Determine whether this generic requirement has a known kind. /// /// \returns \c false for any future generic requirement kinds. bool hasKnownKind() const { switch (getKind()) { case GenericRequirementKind::BaseClass: case GenericRequirementKind::Layout: case GenericRequirementKind::Protocol: case GenericRequirementKind::SameConformance: case GenericRequirementKind::SameType: return true; } return false; } }; using GenericRequirementDescriptor = TargetGenericRequirementDescriptor; /// CRTP class for a context descriptor that includes trailing generic /// context description. template class TrailingGenericContextObjects; template class TargetSelf, typename Runtime, typename HeaderType, typename...FollowingTrailingObjects> class TrailingGenericContextObjects< TargetSelf, HeaderType, FollowingTrailingObjects... > : protected swift::ABI::TrailingObjects, HeaderType, GenericParamDescriptor, TargetGenericRequirementDescriptor, FollowingTrailingObjects...> { protected: using Self = TargetSelf; using GenericRequirementDescriptor = TargetGenericRequirementDescriptor; using TrailingObjects = swift::ABI::TrailingObjects; friend TrailingObjects; template using OverloadToken = typename TrailingObjects::template OverloadToken; const Self *asSelf() const { return static_cast(this); } public: const HeaderType &getFullGenericContextHeader() const { assert(asSelf()->isGeneric()); return *this->template getTrailingObjects(); } const GenericContextDescriptorHeader &getGenericContextHeader() const { /// HeaderType ought to be convertible to GenericContextDescriptorHeader. return getFullGenericContextHeader(); } const TargetGenericContext *getGenericContext() const { if (!asSelf()->isGeneric()) return nullptr; // The generic context header should always be immediately followed in // memory by trailing parameter and requirement descriptors. auto *header = reinterpret_cast(&getGenericContextHeader()); return reinterpret_cast *>( header - sizeof(TargetGenericContext)); } llvm::ArrayRef getGenericParams() const { if (!asSelf()->isGeneric()) return {}; return {this->template getTrailingObjects(), getGenericContextHeader().NumParams}; } llvm::ArrayRef getGenericRequirements() const { if (!asSelf()->isGeneric()) return {}; return {this->template getTrailingObjects(), getGenericContextHeader().NumRequirements}; } protected: size_t numTrailingObjects(OverloadToken) const { return asSelf()->isGeneric() ? 1 : 0; } size_t numTrailingObjects(OverloadToken) const { return asSelf()->isGeneric() ? getGenericContextHeader().NumParams : 0; } size_t numTrailingObjects(OverloadToken) const { return asSelf()->isGeneric() ? getGenericContextHeader().NumRequirements : 0; } }; /// Reference to a generic context. template struct TargetGenericContext final : TrailingGenericContextObjects> { // This struct is supposed to be empty, but TrailingObjects respects the // unique-address-per-object C++ rule, so even if this type is empty, the // trailing objects will come after one byte of padding. This dummy field // takes up space to make the offset of the trailing objects portable. unsigned _dummy; bool isGeneric() const { return true; } }; /// Descriptor for an extension context. template struct TargetExtensionContextDescriptor final : TargetContextDescriptor, TrailingGenericContextObjects> { private: using TrailingGenericContextObjects = TrailingGenericContextObjects; /// A mangling of the `Self` type context that the extension extends. /// The mangled name represents the type in the generic context encoded by /// this descriptor. For example, a nongeneric nominal type extension will /// encode the nominal type name. A generic nominal type extension will encode /// the instance of the type with any generic arguments bound. /// /// Note that the Parent of the extension will be the module context the /// extension is declared inside. RelativeDirectPointer ExtendedContext; public: using TrailingGenericContextObjects::getGenericContext; StringRef getMangledExtendedContext() const { return Demangle::makeSymbolicMangledNameStringRef(ExtendedContext.get()); } static bool classof(const TargetContextDescriptor *cd) { return cd->getKind() == ContextDescriptorKind::Extension; } }; using ExtensionContextDescriptor = TargetExtensionContextDescriptor; template struct TargetAnonymousContextDescriptor final : TargetContextDescriptor, TrailingGenericContextObjects> { private: using TrailingGenericContextObjects = TrailingGenericContextObjects>; public: using TrailingGenericContextObjects::getGenericContext; static bool classof(const TargetContextDescriptor *cd) { return cd->getKind() == ContextDescriptorKind::Anonymous; } }; template struct TargetTypeGenericContextDescriptorHeader { /// Indicates the offset of the instantiation arguments for a type's generic /// contexts in instances of its type metadata. For a value type or class /// without resilient superclasses, this the the offset from the address /// point of the metadata. For a class with a resilient superclass, this /// offset is relative to the end of the superclass metadata. uint32_t ArgumentOffset; using InstantiationFunction_t = TargetMetadata *(const TargetTypeContextDescriptor *type, const void *arguments); /// The function to call to instantiate the template. TargetRelativeDirectPointer InstantiationFunction; /// The metadata instantiation cache. TargetRelativeDirectPointer> InstantiationCache; GenericMetadataInstantiationCache *getInstantiationCache() const { return InstantiationCache.get(); } /// The base header. Must always be the final member. GenericContextDescriptorHeader Base; operator const GenericContextDescriptorHeader &() const { return Base; } }; using TypeGenericContextDescriptorHeader = TargetTypeGenericContextDescriptorHeader; /// Wrapper class for the pointer to a metadata access function that provides /// operator() overloads to call it with the right calling convention. class MetadataAccessFunction { const Metadata * (*Function)(...); static_assert(NumDirectGenericTypeMetadataAccessFunctionArgs == 3, "Need to account for change in number of direct arguments"); template const Metadata *applyN(const void *arg0, const void *arg1, const void *arg2, llvm::ArrayRef argRest) const { using FnN = const Metadata *(const void *, const void *, const void *, const void *); return reinterpret_cast(Function)(arg0, arg1, arg2, argRest.data()); } template const Metadata *variadic_apply(const void *arg0, const void *arg1, const void *arg2, llvm::MutableArrayRef argRest, unsigned n, const void *arg3, Args...argN) const { argRest[n] = arg3; return variadic_apply(arg0, arg1, arg2, argRest, n+1, argN...); } const Metadata *variadic_apply(const void *arg0, const void *arg1, const void *arg2, llvm::MutableArrayRef argRest, unsigned n) const { return applyN(arg0, arg1, arg2, argRest); } public: explicit MetadataAccessFunction(const Metadata * (*Function)(...)) : Function(Function) {} explicit operator bool() const { return Function != nullptr; } // Invoke with an array of arguments. template const Metadata *operator()(llvm::ArrayRef args) const { switch (args.size()) { case 0: return (*this)(); case 1: return (*this)(args[0]); case 2: return (*this)(args[0], args[1]); case 3: return (*this)(args[0], args[1], args[2]); default: return applyN(args[0], args[1], args[2], args); } } // Invoke with n arguments. const Metadata *operator()() const { using Fn0 = const Metadata *(); return reinterpret_cast(Function)(); } const Metadata *operator()(const void *arg0) const { using Fn1 = const Metadata *(const void *); return reinterpret_cast(Function)(arg0); } const Metadata *operator()(const void *arg0, const void *arg1) const { using Fn2 = const Metadata *(const void *, const void *); return reinterpret_cast(Function)(arg0, arg1); } const Metadata *operator()(const void *arg0, const void *arg1, const void *arg2) const { using Fn3 = const Metadata *(const void *, const void *, const void *); return reinterpret_cast(Function)(arg0, arg1, arg2); } template const Metadata *operator()(const void *arg0, const void *arg1, const void *arg2, Args...argN) const { const void *args[3 + sizeof...(Args)]; return variadic_apply(arg0, arg1, arg2, args, 3, argN...); } }; template class TargetTypeContextDescriptor : public TargetContextDescriptor { public: /// The name of the type. TargetRelativeDirectPointer Name; /// A pointer to the metadata access function for this type. /// /// The function type here is a stand-in. You should use getAccessFunction() /// to wrap the function pointer in an accessor that uses the proper calling /// convention for a given number of arguments. TargetRelativeDirectPointer AccessFunctionPtr; MetadataAccessFunction getAccessFunction() const { return MetadataAccessFunction(AccessFunctionPtr.get()); } const TargetTypeGenericContextDescriptorHeader & getFullGenericContextHeader() const; const GenericContextDescriptorHeader &getGenericContextHeader() const { return getFullGenericContextHeader(); } /// Return the offset of the start of generic arguments in the nominal /// type's metadata. The returned value is measured in sizeof(void*). uint32_t getGenericArgumentOffset( const TargetMetadata *metadata) const; /// Return the start of the generic arguments array in the nominal /// type's metadata. The returned value is measured in sizeof(void*). const TargetMetadata * const *getGenericArguments( const TargetMetadata *metadata) const { auto offset = getGenericArgumentOffset(metadata); auto words = reinterpret_cast * const *>(metadata); return words + offset; } static bool classof(const TargetContextDescriptor *cd) { return cd->getKind() >= ContextDescriptorKind::Type_First && cd->getKind() <= ContextDescriptorKind::Type_Last; } }; using TypeContextDescriptor = TargetTypeContextDescriptor; template class TargetClassDescriptor final : public TargetTypeContextDescriptor, public TrailingGenericContextObjects, TargetTypeGenericContextDescriptorHeader, /*additional trailing objects:*/ TargetVTableDescriptorHeader, TargetMethodDescriptor> { private: using TrailingGenericContextObjects = TrailingGenericContextObjects, TargetTypeGenericContextDescriptorHeader, TargetVTableDescriptorHeader, TargetMethodDescriptor>; using TrailingObjects = typename TrailingGenericContextObjects::TrailingObjects; friend TrailingObjects; public: using MethodDescriptor = TargetMethodDescriptor; using VTableDescriptorHeader = TargetVTableDescriptorHeader; using TrailingGenericContextObjects::getGenericContext; using TrailingGenericContextObjects::getGenericContextHeader; using TrailingGenericContextObjects::getFullGenericContextHeader; /// This bit is set in the context descriptor header's kind-specific flags /// if this is a class descriptor with a vtable descriptor for runtime /// vtable instantiation. static constexpr const uint16_t HasVTableFlag = uint16_t(TypeContextDescriptorFlags::HasVTable); /// This bit is set in the context descriptor header's kind-specific flags /// if this is a class descriptor with a resilient superclass. static constexpr const uint16_t HasResilientSuperclassFlag = uint16_t(TypeContextDescriptorFlags::HasResilientSuperclass); /// The number of stored properties in the class, not including its /// superclasses. If there is a field offset vector, this is its length. uint32_t NumFields; private: /// The offset of the field offset vector for this class's stored /// properties in its metadata, in words. 0 means there is no field offset /// vector. /// /// If this class has a resilient superclass, this offset is relative to /// the size of the resilient superclass metadata. Otherwise, it is /// absolute. uint32_t FieldOffsetVectorOffset; template using OverloadToken = typename TrailingGenericContextObjects::template OverloadToken; using TrailingGenericContextObjects::numTrailingObjects; size_t numTrailingObjects(OverloadToken) const { return hasVTable() ? 1 : 0; } size_t numTrailingObjects(OverloadToken) const { if (!hasVTable()) return 0; return getVTableDescriptor()->VTableSize; } public: /// Indicates if the type represented by this descriptor /// supports reflection (C and Obj-C enums currently don't). /// FIXME: This is temporarily left as 32-bit integer to avoid /// changing layout of context descriptor. uint32_t IsReflectable; /// True if metadata records for this type have a field offset vector for /// its stored properties. bool hasFieldOffsetVector() const { return FieldOffsetVectorOffset != 0; } unsigned getFieldOffsetVectorOffset(const ClassMetadata *metadata) const { const auto *description = metadata->getDescription(); if (description->hasResilientSuperclass()) return metadata->SuperClass->getSizeInWords() + FieldOffsetVectorOffset; return FieldOffsetVectorOffset; } bool hasVTable() const { return (this->Flags.getKindSpecificFlags() & HasVTableFlag) != 0; } bool hasResilientSuperclass() const { return (this->Flags.getKindSpecificFlags() & HasResilientSuperclassFlag) != 0; } const VTableDescriptorHeader *getVTableDescriptor() const { if (!hasVTable()) return nullptr; return this->template getTrailingObjects(); } llvm::ArrayRef getMethodDescriptors() const { if (!hasVTable()) return {}; return {this->template getTrailingObjects(), numTrailingObjects(OverloadToken{})}; } /// This is factored in a silly way because remote mirrors cannot directly /// dereference the SuperClass field of class metadata. uint32_t getGenericArgumentOffset( const TargetClassMetadata *classMetadata, const TargetClassMetadata *superMetadata) const { auto Offset = getFullGenericContextHeader().ArgumentOffset; if (hasResilientSuperclass()) return superMetadata->getSizeInWords() + Offset; return Offset; } /// Return the offset of the start of generic arguments in the nominal /// type's metadata. The returned value is measured in sizeof(void*). uint32_t getGenericArgumentOffset(const TargetMetadata *metadata) const { if (hasResilientSuperclass()) { auto *classMetadata = llvm::cast(metadata); auto *superMetadata = llvm::cast(classMetadata->SuperClass); return getGenericArgumentOffset(classMetadata, superMetadata); } return getFullGenericContextHeader().ArgumentOffset; } void *getMethod(unsigned i) const { assert(hasVTable() && i < numTrailingObjects(OverloadToken{})); return getMethodDescriptors()[i].Impl.get(); } static bool classof(const TargetContextDescriptor *cd) { return cd->getKind() == ContextDescriptorKind::Class; } }; using ClassDescriptor = TargetClassDescriptor; template class TargetValueTypeDescriptor : public TargetTypeContextDescriptor { public: static bool classof(const TargetContextDescriptor *cd) { return cd->getKind() == ContextDescriptorKind::Struct || cd->getKind() == ContextDescriptorKind::Enum; } }; using ValueTypeDescriptor = TargetValueTypeDescriptor; template class TargetStructDescriptor final : public TargetValueTypeDescriptor, public TrailingGenericContextObjects, TargetTypeGenericContextDescriptorHeader> { private: using TrailingGenericContextObjects = TrailingGenericContextObjects, TargetTypeGenericContextDescriptorHeader>; using TrailingObjects = typename TrailingGenericContextObjects::TrailingObjects; friend TrailingObjects; public: using TrailingGenericContextObjects::getGenericContext; using TrailingGenericContextObjects::getGenericContextHeader; using TrailingGenericContextObjects::getFullGenericContextHeader; /// The number of stored properties in the struct. /// If there is a field offset vector, this is its length. uint32_t NumFields; /// The offset of the field offset vector for this struct's stored /// properties in its metadata, if any. 0 means there is no field offset /// vector. uint32_t FieldOffsetVectorOffset; /// Indicates if the type represented by this descriptor /// supports reflection (C and Obj-C enums currently don't). /// FIXME: This is temporarily left as 32-bit integer to avoid /// changing layout of context descriptor. uint32_t IsReflectable; /// True if metadata records for this type have a field offset vector for /// its stored properties. bool hasFieldOffsetVector() const { return FieldOffsetVectorOffset != 0; } uint32_t getGenericArgumentOffset() const { return getFullGenericContextHeader().ArgumentOffset; } static bool classof(const TargetContextDescriptor *cd) { return cd->getKind() == ContextDescriptorKind::Struct; } }; using StructDescriptor = TargetStructDescriptor; template class TargetEnumDescriptor final : public TargetValueTypeDescriptor, public TrailingGenericContextObjects, TargetTypeGenericContextDescriptorHeader> { private: using TrailingGenericContextObjects = TrailingGenericContextObjects, TargetTypeGenericContextDescriptorHeader>; using TrailingObjects = typename TrailingGenericContextObjects::TrailingObjects; friend TrailingObjects; public: using TrailingGenericContextObjects::getGenericContext; using TrailingGenericContextObjects::getGenericContextHeader; using TrailingGenericContextObjects::getFullGenericContextHeader; /// The number of non-empty cases in the enum are in the low 24 bits; /// the offset of the payload size in the metadata record in words, /// if any, is stored in the high 8 bits. uint32_t NumPayloadCasesAndPayloadSizeOffset; /// The number of empty cases in the enum. uint32_t NumEmptyCases; /// Indicates if the type represented by this descriptor /// supports reflection (C and Obj-C enums currently don't). /// FIXME: This is temporarily left as 32-bit integer to avoid /// changing layout of context descriptor. uint32_t IsReflectable; uint32_t getNumPayloadCases() const { return NumPayloadCasesAndPayloadSizeOffset & 0x00FFFFFFU; } uint32_t getNumEmptyCases() const { return NumEmptyCases; } uint32_t getNumCases() const { return getNumPayloadCases() + NumEmptyCases; } size_t getPayloadSizeOffset() const { return ((NumPayloadCasesAndPayloadSizeOffset & 0xFF000000U) >> 24); } bool hasPayloadSizeOffset() const { return getPayloadSizeOffset() != 0; } uint32_t getGenericArgumentOffset() const { return getFullGenericContextHeader().ArgumentOffset; } static bool classof(const TargetContextDescriptor *cd) { return cd->getKind() == ContextDescriptorKind::Enum; } }; using EnumDescriptor = TargetEnumDescriptor; template inline const TargetGenericContext * TargetContextDescriptor::getGenericContext() const { if (!isGeneric()) return nullptr; switch (getKind()) { case ContextDescriptorKind::Module: // Never generic. return nullptr; case ContextDescriptorKind::Extension: return llvm::cast>(this) ->getGenericContext(); case ContextDescriptorKind::Anonymous: return llvm::cast>(this) ->getGenericContext(); case ContextDescriptorKind::Class: return llvm::cast>(this) ->getGenericContext(); case ContextDescriptorKind::Enum: return llvm::cast>(this) ->getGenericContext(); case ContextDescriptorKind::Struct: return llvm::cast>(this) ->getGenericContext(); default: // We don't know about this kind of descriptor. return nullptr; } } template uint32_t TargetTypeContextDescriptor::getGenericArgumentOffset( const TargetMetadata *metadata) const { switch (this->getKind()) { case ContextDescriptorKind::Class: return llvm::cast>(this) ->getGenericArgumentOffset(metadata); case ContextDescriptorKind::Enum: return llvm::cast>(this) ->getGenericArgumentOffset(); case ContextDescriptorKind::Struct: return llvm::cast>(this) ->getGenericArgumentOffset(); default: swift_runtime_unreachable("Not a type context descriptor."); } } template const TargetTypeGenericContextDescriptorHeader & TargetTypeContextDescriptor::getFullGenericContextHeader() const { switch (this->getKind()) { case ContextDescriptorKind::Class: return llvm::cast>(this) ->getFullGenericContextHeader(); case ContextDescriptorKind::Enum: return llvm::cast>(this) ->getFullGenericContextHeader(); case ContextDescriptorKind::Struct: return llvm::cast>(this) ->getFullGenericContextHeader(); default: swift_runtime_unreachable("Not a type context descriptor."); } } /// \brief Fetch a uniqued metadata object for a generic nominal type. /// /// The basic algorithm for fetching a metadata object is: /// func swift_getGenericMetadata(header, arguments) { /// if (metadata = getExistingMetadata(&header.PrivateData, /// arguments[0..header.NumArguments])) /// return metadata /// metadata = malloc(superclass.MetadataSize + /// numImmediateMembers * sizeof(void *)) /// memcpy(metadata, header.MetadataTemplate, header.TemplateSize) /// for (i in 0..header.NumFillInstructions) /// metadata[header.FillInstructions[i].ToIndex] /// = arguments[header.FillInstructions[i].FromIndex] /// setExistingMetadata(&header.PrivateData, /// arguments[0..header.NumArguments], /// metadata) /// return metadata /// } SWIFT_RUNTIME_EXPORT const Metadata * swift_getGenericMetadata(const TypeContextDescriptor *description, const void *arguments); // Callback to allocate a generic class metadata object. SWIFT_RUNTIME_EXPORT ClassMetadata * swift_allocateGenericClassMetadata(const ClassDescriptor *description, const void *metadataTemplate, size_t metadataTemplateSize, size_t metadataTemplateAddressPoint, const void *arguments, ClassMetadata *superclass, size_t numImmediateMembers); // Callback to allocate a generic struct/enum metadata object. SWIFT_RUNTIME_EXPORT ValueMetadata * swift_allocateGenericValueMetadata(const ValueTypeDescriptor *description, const void *metadataTemplate, size_t metadataTemplateSize, const void *arguments); /// Instantiate a resilient or generic protocol witness table. /// /// \param genericTable - The witness table template for the /// conformance. It may either have fields that require runtime /// initialization, or be missing requirements at the end for /// which default witnesses are available. /// /// \param type - The conforming type, used to form a uniquing key /// for the conformance. If the witness table is not dependent on /// the substituted type of the conformance, this can be set to /// nullptr, in which case there will only be one instantiated /// witness table per witness table template. /// /// \param instantiationArgs - An opaque pointer that's forwarded to /// the instantiation function, used for conditional conformances. /// This API implicitly embeds an assumption that these arguments /// never form part of the uniquing key for the conformance, which /// is ultimately a statement about the user model of overlapping /// conformances. SWIFT_RUNTIME_EXPORT const WitnessTable * swift_getGenericWitnessTable(GenericWitnessTable *genericTable, const Metadata *type, void * const *instantiationArgs); /// \brief Fetch a uniqued metadata for a function type. SWIFT_RUNTIME_EXPORT const FunctionTypeMetadata * swift_getFunctionTypeMetadata(FunctionTypeFlags flags, const Metadata *const *parameters, const uint32_t *parameterFlags, const Metadata *result); SWIFT_RUNTIME_EXPORT const FunctionTypeMetadata * swift_getFunctionTypeMetadata0(FunctionTypeFlags flags, const Metadata *result); SWIFT_RUNTIME_EXPORT const FunctionTypeMetadata * swift_getFunctionTypeMetadata1(FunctionTypeFlags flags, const Metadata *arg0, const Metadata *result); SWIFT_RUNTIME_EXPORT const FunctionTypeMetadata * swift_getFunctionTypeMetadata2(FunctionTypeFlags flags, const Metadata *arg0, const Metadata *arg1, const Metadata *result); SWIFT_RUNTIME_EXPORT const FunctionTypeMetadata *swift_getFunctionTypeMetadata3( FunctionTypeFlags flags, const Metadata *arg0, const Metadata *arg1, const Metadata *arg2, const Metadata *result); #if SWIFT_OBJC_INTEROP SWIFT_RUNTIME_EXPORT void swift_instantiateObjCClass(const ClassMetadata *theClass); SWIFT_RUNTIME_EXPORT Class swift_getInitializedObjCClass(Class c); /// \brief Fetch a uniqued type metadata for an ObjC class. SWIFT_RUNTIME_EXPORT const Metadata * swift_getObjCClassMetadata(const ClassMetadata *theClass); /// \brief Get the ObjC class object from class type metadata. SWIFT_RUNTIME_EXPORT const ClassMetadata * swift_getObjCClassFromMetadata(const Metadata *theClass); #endif /// \brief Fetch a unique type metadata object for a foreign type. SWIFT_RUNTIME_EXPORT const ForeignTypeMetadata * swift_getForeignTypeMetadata(ForeignTypeMetadata *nonUnique); /// \brief Fetch a uniqued metadata for a tuple type. /// /// The labels argument is null if and only if there are no element /// labels in the tuple. Otherwise, it is a null-terminated /// concatenation of space-terminated NFC-normalized UTF-8 strings, /// assumed to point to constant global memory. /// /// That is, for the tuple type (a : Int, Int, c : Int), this /// argument should be: /// "a c \0" /// /// This representation allows label strings to be efficiently /// (1) uniqued within a linkage unit and (2) compared with strcmp. /// In other words, it's optimized for code size and uniquing /// efficiency, not for the convenience of actually consuming /// these strings. /// /// \param elements - potentially invalid if numElements is zero; /// otherwise, an array of metadata pointers. /// \param labels - the labels string /// \param proposedWitnesses - an optional proposed set of value witnesses. /// This is useful when working with a non-dependent tuple type /// where the entrypoint is just being used to unique the metadata. SWIFT_RUNTIME_EXPORT const TupleTypeMetadata * swift_getTupleTypeMetadata(TupleTypeFlags flags, const Metadata * const *elements, const char *labels, const ValueWitnessTable *proposedWitnesses); SWIFT_RUNTIME_EXPORT const TupleTypeMetadata * swift_getTupleTypeMetadata2(const Metadata *elt0, const Metadata *elt1, const char *labels, const ValueWitnessTable *proposedWitnesses); SWIFT_RUNTIME_EXPORT const TupleTypeMetadata * swift_getTupleTypeMetadata3(const Metadata *elt0, const Metadata *elt1, const Metadata *elt2, const char *labels, const ValueWitnessTable *proposedWitnesses); /// Initialize the value witness table and struct field offset vector for a /// struct, using the "Universal" layout strategy. SWIFT_RUNTIME_EXPORT void swift_initStructMetadata(StructMetadata *self, StructLayoutFlags flags, size_t numFields, const TypeLayout * const *fieldTypes, size_t *fieldOffsets); /// Relocate the metadata for a class and copy fields from the given template. /// The final size of the metadata is calculated at runtime from the size of /// the superclass metadata together with the given number of immediate /// members. SWIFT_RUNTIME_EXPORT ClassMetadata * swift_relocateClassMetadata(ClassMetadata *self, size_t templateSize, size_t numImmediateMembers); /// Initialize the field offset vector for a dependent-layout class, using the /// "Universal" layout strategy. SWIFT_RUNTIME_EXPORT void swift_initClassMetadata_UniversalStrategy(ClassMetadata *self, size_t numFields, const TypeLayout * const *fieldTypes, size_t *fieldOffsets); /// \brief Fetch a uniqued metadata for a metatype type. SWIFT_RUNTIME_EXPORT const MetatypeMetadata * swift_getMetatypeMetadata(const Metadata *instanceType); /// \brief Fetch a uniqued metadata for an existential metatype type. SWIFT_RUNTIME_EXPORT const ExistentialMetatypeMetadata * swift_getExistentialMetatypeMetadata(const Metadata *instanceType); /// \brief Fetch a uniqued metadata for an existential type. The array /// referenced by \c protocols will be sorted in-place. SWIFT_RUNTIME_EXPORT const ExistentialTypeMetadata * swift_getExistentialTypeMetadata(ProtocolClassConstraint classConstraint, const Metadata *superclassConstraint, size_t numProtocols, const ProtocolDescriptor * const *protocols); /// \brief Perform a copy-assignment from one existential container to another. /// Both containers must be of the same existential type representable with the /// same number of witness tables. SWIFT_RUNTIME_EXPORT OpaqueValue *swift_assignExistentialWithCopy(OpaqueValue *dest, const OpaqueValue *src, const Metadata *type); /// \brief Perform a copy-assignment from one existential container to another. /// Both containers must be of the same existential type representable with no /// witness tables. OpaqueValue *swift_assignExistentialWithCopy0(OpaqueValue *dest, const OpaqueValue *src, const Metadata *type); /// \brief Perform a copy-assignment from one existential container to another. /// Both containers must be of the same existential type representable with one /// witness table. OpaqueValue *swift_assignExistentialWithCopy1(OpaqueValue *dest, const OpaqueValue *src, const Metadata *type); /// Calculate the numeric index of an extra inhabitant of a heap object /// pointer in memory. inline int swift_getHeapObjectExtraInhabitantIndex(HeapObject * const* src) { // This must be consistent with the getHeapObjectExtraInhabitantIndex // implementation in IRGen's ExtraInhabitants.cpp. using namespace heap_object_abi; uintptr_t value = reinterpret_cast(*src); if (value >= LeastValidPointerValue) return -1; // Check for tagged pointers on appropriate platforms. Knowing that // value < LeastValidPointerValue tells us a lot. #if SWIFT_OBJC_INTEROP if (value & ((uintptr_t(1) << ObjCReservedLowBits) - 1)) return -1; #endif return (int) (value >> ObjCReservedLowBits); } /// Store an extra inhabitant of a heap object pointer to memory, /// in the style of a value witness. inline void swift_storeHeapObjectExtraInhabitant(HeapObject **dest, int index) { // This must be consistent with the storeHeapObjectExtraInhabitant // implementation in IRGen's ExtraInhabitants.cpp. auto value = uintptr_t(index) << heap_object_abi::ObjCReservedLowBits; *dest = reinterpret_cast(value); } /// Return the number of extra inhabitants in a heap object pointer. inline constexpr unsigned swift_getHeapObjectExtraInhabitantCount() { // This must be consistent with the getHeapObjectExtraInhabitantCount // implementation in IRGen's ExtraInhabitants.cpp. using namespace heap_object_abi; // The runtime needs no more than INT_MAX inhabitants. return (LeastValidPointerValue >> ObjCReservedLowBits) > INT_MAX ? (unsigned)INT_MAX : (unsigned)(LeastValidPointerValue >> ObjCReservedLowBits); } /// Calculate the numeric index of an extra inhabitant of a function /// pointer in memory. inline int swift_getFunctionPointerExtraInhabitantIndex(void * const* src) { // This must be consistent with the getFunctionPointerExtraInhabitantIndex // implementation in IRGen's ExtraInhabitants.cpp. uintptr_t value = reinterpret_cast(*src); return (value < heap_object_abi::LeastValidPointerValue ? (int) value : -1); } /// Store an extra inhabitant of a function pointer to memory, in the /// style of a value witness. inline void swift_storeFunctionPointerExtraInhabitant(void **dest, int index) { // This must be consistent with the storeFunctionPointerExtraInhabitantIndex // implementation in IRGen's ExtraInhabitants.cpp. *dest = reinterpret_cast(static_cast(index)); } /// Return the number of extra inhabitants in a function pointer. inline constexpr unsigned swift_getFunctionPointerExtraInhabitantCount() { // This must be consistent with the getFunctionPointerExtraInhabitantCount // implementation in IRGen's ExtraInhabitants.cpp. using namespace heap_object_abi; // The runtime needs no more than INT_MAX inhabitants. return (LeastValidPointerValue) > INT_MAX ? (unsigned)INT_MAX : (unsigned)(LeastValidPointerValue); } /// Return the type name for a given type metadata. std::string nameForMetadata(const Metadata *type, bool qualified = true); /// Register a block of protocol records for dynamic lookup. SWIFT_RUNTIME_EXPORT void swift_registerProtocols(const ProtocolRecord *begin, const ProtocolRecord *end); /// Register a block of protocol conformance records for dynamic lookup. SWIFT_RUNTIME_EXPORT void swift_registerProtocolConformances(const ProtocolConformanceRecord *begin, const ProtocolConformanceRecord *end); /// Register a block of type context descriptors for dynamic lookup. SWIFT_RUNTIME_EXPORT void swift_registerTypeMetadataRecords(const TypeMetadataRecord *begin, const TypeMetadataRecord *end); /// Register a block of type field records for dynamic lookup. SWIFT_RUNTIME_EXPORT void swift_registerFieldDescriptors(const reflection::FieldDescriptor **records, size_t size); /// Return the superclass, if any. The result is nullptr for root /// classes and class protocol types. SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_INTERFACE const Metadata *_swift_class_getSuperclass(const Metadata *theClass); SWIFT_RUNTIME_STDLIB_INTERFACE void swift_getFieldAt( const Metadata *type, unsigned index, std::function callback); } // end namespace swift #pragma clang diagnostic pop #endif /* SWIFT_RUNTIME_METADATA_H */