//===--- MetadataRef.h - ABI for references to metadata ---------*- C++ -*-===// // // This source file is part of the Swift.org open source project // // Copyright (c) 2014 - 2022 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // //===----------------------------------------------------------------------===// // // This file describes runtime metadata structures for references to // other metadata. // //===----------------------------------------------------------------------===// #ifndef SWIFT_ABI_METADATAREF_H #define SWIFT_ABI_METADATAREF_H #include "swift/ABI/TargetLayout.h" #include "swift/ABI/MetadataValues.h" #if SWIFT_OBJC_INTEROP #include #endif namespace swift { template struct TargetAnyClassMetadata; template struct TargetAnyClassMetadataObjCInterop; template struct TargetClassMetadata; template struct swift_ptrauth_struct_context_descriptor(ContextDescriptor) TargetContextDescriptor; template struct swift_ptrauth_struct_context_descriptor(ProtocolDescriptor) TargetProtocolDescriptor; namespace detail { template struct TargetAnyClassMetadataTypeImpl; template struct TargetAnyClassMetadataTypeImpl { using type = TargetAnyClassMetadataObjCInterop; }; template struct TargetAnyClassMetadataTypeImpl { using type = TargetAnyClassMetadata; }; } /// A convenience typedef for the correct target-parameterized /// AnyClassMetadata class. template using TargetAnyClassMetadataType = typename detail::TargetAnyClassMetadataTypeImpl::type; /// A convenience typedef for the correct target-parameterized /// ClassMetadata class. template using TargetClassMetadataType = TargetClassMetadata>; /// A convenience typedef for a ClassMetadata class that's forced to /// support ObjC interop even if that's not the default for the target. template using TargetClassMetadataObjCInterop = TargetClassMetadata>; /// A convenience typedef for a target-parameterized pointer to a /// target-parameterized type. template class Pointee> using TargetMetadataPointer = typename Runtime::template Pointer>; /// A convenience typedef for a target-parameterized const pointer /// to a target-parameterized type. template class Pointee> using ConstTargetMetadataPointer = typename Runtime::template Pointer>; /// A signed pointer to a type context descriptor, using the standard /// signing schema. template class Context = TargetContextDescriptor> using TargetSignedContextPointer = TargetSignedPointer * __ptrauth_swift_type_descriptor>; /// A relative pointer to a type context descriptor. template class Context = TargetContextDescriptor> using TargetRelativeContextPointer = RelativeIndirectablePointer, /*nullable*/ true, int32_t, TargetSignedContextPointer>; using RelativeContextPointer = TargetRelativeContextPointer; /// A relative-indirectable pointer to a type context descriptor, with /// the low bits used to store a small additional discriminator. template class Context = TargetContextDescriptor> using RelativeContextPointerIntPair = RelativeIndirectablePointerIntPair, IntTy, /*nullable*/ true, int32_t, TargetSignedContextPointer>; /// Layout of a small prefix of an Objective-C protocol, used only to /// directly extract the name of the protocol. template struct TargetObjCProtocolPrefix { /// Unused by the Swift runtime. TargetPointer _ObjC_Isa; /// The mangled name of the protocol. TargetPointer Name; }; /// A reference to a protocol within the runtime, which may be either /// a Swift protocol or (when Objective-C interoperability is enabled) an /// Objective-C protocol. /// /// This type always contains a single target pointer, whose lowest bit is /// used to distinguish between a Swift protocol referent and an Objective-C /// protocol referent. template class TargetProtocolDescriptorRef { using StoredPointer = typename Runtime::StoredPointer; using ProtocolDescriptorPointer = ConstTargetMetadataPointer; enum : StoredPointer { // The bit used to indicate whether this is an Objective-C protocol. IsObjCBit = 0x1U, }; /// A direct pointer to a protocol descriptor for either an Objective-C /// protocol (if the low bit is set) or a Swift protocol (if the low bit /// is clear). StoredPointer storage; public: constexpr TargetProtocolDescriptorRef(StoredPointer storage) : storage(storage) { } constexpr TargetProtocolDescriptorRef() : storage() { } TargetProtocolDescriptorRef( ProtocolDescriptorPointer protocol, ProtocolDispatchStrategy dispatchStrategy) { if (Runtime::ObjCInterop) { storage = reinterpret_cast(protocol) | (dispatchStrategy == ProtocolDispatchStrategy::ObjC ? IsObjCBit : 0); } else { assert(dispatchStrategy == ProtocolDispatchStrategy::Swift); storage = reinterpret_cast(protocol); } } const static TargetProtocolDescriptorRef forSwift( ProtocolDescriptorPointer protocol) { return TargetProtocolDescriptorRef{ reinterpret_cast(protocol)}; } #if SWIFT_OBJC_INTEROP constexpr static TargetProtocolDescriptorRef forObjC(Protocol *objcProtocol) { return TargetProtocolDescriptorRef{ reinterpret_cast(objcProtocol) | IsObjCBit}; } #endif explicit constexpr operator bool() const { return storage != 0; } /// The name of the protocol. TargetPointer getName() const { #if SWIFT_OBJC_INTEROP if (isObjC()) { return reinterpret_cast *>( getObjCProtocol())->Name; } #endif return getSwiftProtocol()->Name; } /// Determine what kind of protocol this is, Swift or Objective-C. ProtocolDispatchStrategy getDispatchStrategy() const { if (isObjC()) { return ProtocolDispatchStrategy::ObjC; } return ProtocolDispatchStrategy::Swift; } /// Determine whether this protocol has a 'class' constraint. ProtocolClassConstraint getClassConstraint() const { if (isObjC()) { return ProtocolClassConstraint::Class; } return getSwiftProtocol()->getProtocolContextDescriptorFlags() .getClassConstraint(); } /// Determine whether this protocol needs a witness table. bool needsWitnessTable() const { if (isObjC()) { return false; } return true; } SpecialProtocol getSpecialProtocol() const { if (isObjC()) { return SpecialProtocol::None; } return getSwiftProtocol()->getProtocolContextDescriptorFlags() .getSpecialProtocol(); } /// Retrieve the Swift protocol descriptor. ProtocolDescriptorPointer getSwiftProtocol() const { assert(!isObjC()); // NOTE: we explicitly use a C-style cast here because cl objects to the // reinterpret_cast from a uintptr_t type to an unsigned type which the // Pointer type may be depending on the instantiation. Using the C-style // cast gives us a single path irrespective of the template type parameters. return (ProtocolDescriptorPointer)(storage & ~IsObjCBit); } /// Retrieve the raw stored pointer and discriminator bit. constexpr StoredPointer getRawData() const { return storage; } /// Whether this references an Objective-C protocol. bool isObjC() const { if (Runtime::ObjCInterop) return (storage & IsObjCBit) != 0; else return false; } #if SWIFT_OBJC_INTEROP /// Retrieve the Objective-C protocol. TargetPointer getObjCProtocol() const { assert(isObjC()); return reinterpret_cast >( storage & ~IsObjCBit); } #endif }; using ProtocolDescriptorRef = TargetProtocolDescriptorRef; /// A relative pointer to a protocol descriptor, which provides the relative- /// pointer equivalent to \c TargetProtocolDescriptorRef. template class RelativeTargetProtocolDescriptorPointer { union { /// Relative pointer to a Swift protocol descriptor. /// The \c bool value will be false to indicate that the protocol /// is a Swift protocol, or true to indicate that this references /// an Objective-C protocol. RelativeContextPointerIntPair swiftPointer; #if SWIFT_OBJC_INTEROP /// Relative pointer to an ObjC protocol descriptor. /// The \c bool value will be false to indicate that the protocol /// is a Swift protocol, or true to indicate that this references /// an Objective-C protocol. RelativeIndirectablePointerIntPair objcPointer; #endif }; bool isObjC() const { #if SWIFT_OBJC_INTEROP if (Runtime::ObjCInterop) return objcPointer.getInt(); #endif return false; } public: /// Retrieve a reference to the protocol. TargetProtocolDescriptorRef getProtocol() const { #if SWIFT_OBJC_INTEROP if (isObjC()) { return TargetProtocolDescriptorRef::forObjC( const_cast(objcPointer.getPointer())); } #endif return TargetProtocolDescriptorRef::forSwift( reinterpret_cast< ConstTargetMetadataPointer>( swiftPointer.getPointer())); } /// Retrieve a reference to the protocol. int32_t getUnresolvedProtocolAddress() const { #if SWIFT_OBJC_INTEROP if (isObjC()) { return objcPointer.getUnresolvedOffset(); } #endif return swiftPointer.getUnresolvedOffset(); } operator TargetProtocolDescriptorRef() const { return getProtocol(); } }; /// A reference to a type. template struct TargetTypeReference { union { /// A direct reference to a TypeContextDescriptor or ProtocolDescriptor. RelativeDirectPointer> DirectTypeDescriptor; /// An indirect reference to a TypeContextDescriptor or ProtocolDescriptor. RelativeDirectPointer< TargetSignedPointer * __ptrauth_swift_type_descriptor>> IndirectTypeDescriptor; /// An indirect reference to an Objective-C class. RelativeDirectPointer< ConstTargetMetadataPointer> IndirectObjCClass; /// A direct reference to an Objective-C class name. RelativeDirectPointer DirectObjCClassName; }; const TargetContextDescriptor * getTypeDescriptor(TypeReferenceKind kind) const { switch (kind) { case TypeReferenceKind::DirectTypeDescriptor: return DirectTypeDescriptor; case TypeReferenceKind::IndirectTypeDescriptor: return *IndirectTypeDescriptor; case TypeReferenceKind::DirectObjCClassName: case TypeReferenceKind::IndirectObjCClass: return nullptr; } return nullptr; } /// If this type reference is one of the kinds that supports ObjC /// references, const TargetClassMetadataObjCInterop * getObjCClass(TypeReferenceKind kind) const; const TargetClassMetadataObjCInterop * const * getIndirectObjCClass(TypeReferenceKind kind) const { assert(kind == TypeReferenceKind::IndirectObjCClass); return IndirectObjCClass.get(); } const char *getDirectObjCClassName(TypeReferenceKind kind) const { assert(kind == TypeReferenceKind::DirectObjCClassName); return DirectObjCClassName.get(); } }; using TypeReference = TargetTypeReference; } // end namespace swift #endif