//===--- GenericContext.h - ABI for generic signatures ----------*- 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 representing // generic signatures. // //===----------------------------------------------------------------------===// #ifndef SWIFT_ABI_GENERICCONTEXT_H #define SWIFT_ABI_GENERICCONTEXT_H #include "swift/ABI/TargetLayout.h" #include "swift/ABI/MetadataValues.h" #include "swift/ABI/MetadataRef.h" #include "swift/ABI/InvertibleProtocols.h" #include "swift/ABI/TrailingObjects.h" #include "swift/Basic/MathUtils.h" #include "swift/Demangling/Demangle.h" namespace swift { template struct TargetProtocolConformanceDescriptor; template struct TargetGenericContext; template struct TargetGenericContextDescriptorHeader { /// The number of (source-written) generic parameters, and thus /// the number of GenericParamDescriptors associated with this /// context. The parameter descriptors appear in the order in /// which they were given in the source. /// /// A GenericParamDescriptor corresponds to a type metadata pointer /// in the arguments layout when isKeyArgument() is true. /// isKeyArgument() will be false if the parameter has been made /// equivalent to a different parameter or a concrete type. uint16_t NumParams; /// The number of GenericRequirementDescriptors in this generic /// signature. /// /// A GenericRequirementDescriptor of kind Protocol corresponds /// to a witness table pointer in the arguments layout when /// isKeyArgument() is true. isKeyArgument() will be false if /// the protocol is an Objective-C protocol. (Unlike generic /// parameters, redundant conformance requirements can simply be /// eliminated, and so that case is not impossible.) uint16_t NumRequirements; /// The size of the "key" area of the argument layout, in words. /// Key arguments include shape classes, generic parameters and /// conformance requirements which are part of the identity of /// the context. /// /// The key area of the argument layout consists of: /// /// - a sequence of pack lengths, in the same order as the parameter /// descriptors which satisfy getKind() == GenericParamKind::TypePack /// and hasKeyArgument(); /// /// - a sequence of metadata or metadata pack pointers, in the same /// order as the parameter descriptors which satisfy hasKeyArgument(); /// /// - a sequence of witness table or witness table pack pointers, in the /// same order as the requirement descriptors which satisfy /// hasKeyArgument(). /// /// a sequence of values, in the same order as the parameter descriptors /// which satisify getKind() == GenericParamKind::Value and /// hasKeyArgument(); /// /// The elements above which are packs are precisely those appearing /// in the sequence of trailing GenericPackShapeDescriptors. uint16_t NumKeyArguments; /// Originally this was the size of the "extra" area of the argument /// layout, in words. The idea was that extra arguments would /// include generic parameters and conformances that are not part /// of the identity of the context; however, it's unclear why we /// would ever want such a thing. As a result, in pre-5.8 runtimes /// this field is always zero. New flags can only be added as long /// as they remains zero in code which must be compatible with /// older Swift runtimes. GenericContextDescriptorFlags Flags; uint32_t getNumArguments() const { // Note: this used to be NumKeyArguments + NumExtraArguments, // and flags was named NumExtraArguments, which is why Flags // must remain zero when backward deploying to Swift 5.7 or // earlier. return NumKeyArguments; } /// Return the total size of the argument layout, in words. /// The alignment of the argument layout is the word alignment. uint32_t getArgumentLayoutSizeInWords() const { return getNumArguments(); } bool hasArguments() const { return getNumArguments() > 0; } bool hasConditionalInvertedProtocols() const { return Flags.hasConditionalInvertedProtocols(); } }; using GenericContextDescriptorHeader = TargetGenericContextDescriptorHeader; template class TargetGenericRequirementDescriptor { public: GenericRequirementFlags Flags; /// The type that's constrained, described as a mangled name. RelativeDirectPointer Param; 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. RelativeTargetProtocolDescriptorPointer 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; /// The set of invertible protocols whose check is disabled, along /// with the index of the generic parameter to which this applies. /// /// The index is technically redundant with the subject type, but its /// storage is effectively free because this union is 32 bits anyway. The /// index 0xFFFF is reserved for "not a generic parameter", in which case /// the constraints are on the subject type. /// /// Only valid if the requirement has InvertedProtocols kind. struct { uint16_t GenericParamIndex; InvertibleProtocolSet Protocols; } InvertedProtocols; }; constexpr GenericRequirementFlags getFlags() const { return Flags; } constexpr GenericRequirementKind getKind() const { return getFlags().getKind(); } /// Retrieve the generic parameter that is the subject of this requirement, /// as a mangled type name. llvm::StringRef getParam() const { return swift::Demangle::makeSymbolicMangledNameStringRef(Param.get()); } /// Retrieve the protocol for a Protocol requirement. TargetProtocolDescriptorRef getProtocol() const { assert(getKind() == GenericRequirementKind::Protocol); return Protocol; } /// Retreive the raw value of the Protocol requirement pointer. int32_t getUnresolvedProtocolAddress() const { assert(getKind() == GenericRequirementKind::Protocol); return Protocol.getUnresolvedProtocolAddress(); } /// Retreive the offset to the Protocol field constexpr inline auto getProtocolOffset() const -> typename Runtime::StoredSize { return offsetof(typename std::remove_reference::type, Protocol); } /// Retreive the offset to the Type field constexpr inline auto getSameTypeNameOffset() const -> typename Runtime::StoredSize { return offsetof(typename std::remove_reference::type, Type); } /// Retreive the offset to the Param field constexpr inline auto getParamOffset() const -> typename Runtime::StoredSize { return offsetof(typename std::remove_reference::type, Param); } /// Retrieve the right-hand type for a SameType, BaseClass or SameShape requirement. llvm::StringRef getMangledTypeName() const { assert(getKind() == GenericRequirementKind::SameType || getKind() == GenericRequirementKind::BaseClass || getKind() == GenericRequirementKind::SameShape); return swift::Demangle::makeSymbolicMangledNameStringRef(Type.get()); } /// Retrieve the protocol conformance record for a SameConformance /// requirement. const TargetProtocolConformanceDescriptor *getConformance() const { assert(getKind() == GenericRequirementKind::SameConformance); return Conformance; } /// Retrieve the layout constraint. GenericRequirementLayoutKind getLayout() const { assert(getKind() == GenericRequirementKind::Layout); return Layout; } /// Retrieve the set of inverted protocols. InvertibleProtocolSet getInvertedProtocols() const { assert(getKind() == GenericRequirementKind::InvertedProtocols); return InvertedProtocols.Protocols; } /// Retrieve the invertible protocol kind. uint16_t getInvertedProtocolsGenericParamIndex() const { assert(getKind() == GenericRequirementKind::InvertedProtocols); return InvertedProtocols.GenericParamIndex; } /// 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: case GenericRequirementKind::SameShape: case GenericRequirementKind::InvertedProtocols: return true; } return false; } }; using GenericRequirementDescriptor = TargetGenericRequirementDescriptor; struct GenericPackShapeHeader { /// The number of generic parameters and conformance requirements /// which are packs. /// /// Must equal the sum of: /// - the number of GenericParamDescriptors whose kind is /// GenericParamKind::TypePack and isKeyArgument bits set; /// - the number of GenericRequirementDescriptors with the /// isPackRequirement and isKeyArgument bits set uint16_t NumPacks; /// The number of equivalence classes in the same-shape relation. uint16_t NumShapeClasses; }; /// The GenericPackShapeHeader is followed by an array of these descriptors, /// whose length is given by the header's NumPacks field. /// /// The invariant is that all pack descriptors with GenericPackKind::Metadata /// must precede those with GenericPackKind::WitnessTable, and for each kind, /// the pack descriptors are ordered by their Index. /// /// This allows us to iterate over the generic arguments array in parallel /// with the array of pack shape descriptors. We know we have a metadata /// or witness table when we reach the generic argument whose index is /// stored in the next descriptor; we increment the descriptor pointer in /// this case. struct GenericPackShapeDescriptor { GenericPackKind Kind; /// The index of this metadata pack or witness table pack in the /// generic arguments array. uint16_t Index; /// The equivalence class of this pack under the same-shape relation. /// /// Must be less than GenericPackShapeHeader::NumShapeClasses. uint16_t ShapeClass; uint16_t Unused; }; /// A count for the number of requirements for the number of requirements /// for a given conditional conformance to a invertible protocols. struct ConditionalInvertibleProtocolsRequirementCount { uint16_t count; }; /// A invertible protocol set used for the conditional conformances in a /// generic context. struct ConditionalInvertibleProtocolSet: InvertibleProtocolSet { using InvertibleProtocolSet::InvertibleProtocolSet; }; /// A generic requirement for describing a conditional conformance to a /// invertible protocol. /// /// This type is equivalent to a `TargetGenericRequirementDescriptor`, and /// differs only because it needs to occur alongside template struct TargetConditionalInvertibleProtocolRequirement: TargetGenericRequirementDescriptor { }; struct GenericValueHeader { /// The total number of generic parameters in this signature where /// getKind() == GenericParamKind::Value. uint32_t NumValues; }; /// The GenericValueHeader is followed by an array of these descriptors, /// whose length is given by the header's NumValues field. struct GenericValueDescriptor { GenericValueType Type; }; /// An array of generic parameter descriptors, all /// GenericParamDescriptor::implicit(), which is by far /// the most common case. Some generic context storage can /// avoid storing descriptors when they all match this pattern. extern const GenericParamDescriptor ImplicitGenericParamDescriptors[MaxNumImplicitGenericParamDescriptors]; inline const GenericParamDescriptor * externalTargetImplicitGenericParamDescriptors() { static const GenericParamDescriptor buffer[MaxNumImplicitGenericParamDescriptors] = { #define D GenericParamDescriptor::implicit() D, D, D, D, D, D, D, D, D, D, D, D, D, D, D, D, D, D, D, D, D, D, D, D, D, D, D, D, D, D, D, D, D, D, D, D, D, D, D, D, D, D, D, D, D, D, D, D, D, D, D, D, D, D, D, D, D, D, D, D, D, D, D, D #undef D }; return buffer; } template const GenericParamDescriptor *targetImplicitGenericParamDescriptors() { return externalTargetImplicitGenericParamDescriptors(); } template <> inline const GenericParamDescriptor *targetImplicitGenericParamDescriptors() { return ImplicitGenericParamDescriptors; } /// A runtime description of a generic signature. template class RuntimeGenericSignature { TargetGenericContextDescriptorHeader Header; const GenericParamDescriptor *Params; const TargetGenericRequirementDescriptor *Requirements; GenericPackShapeHeader PackShapeHeader; const GenericPackShapeDescriptor *PackShapeDescriptors; GenericValueHeader ValueHeader; const GenericValueDescriptor *ValueDescriptors; public: RuntimeGenericSignature() : Header{0, 0, 0, GenericContextDescriptorFlags(false, false, false)}, Params(nullptr), Requirements(nullptr), PackShapeHeader{0, 0}, PackShapeDescriptors(nullptr), ValueHeader{0}, ValueDescriptors(nullptr) {} RuntimeGenericSignature(const TargetGenericContextDescriptorHeader &header, const GenericParamDescriptor *params, const TargetGenericRequirementDescriptor *requirements, const GenericPackShapeHeader &packShapeHeader, const GenericPackShapeDescriptor *packShapeDescriptors, const GenericValueHeader &valueHeader, const GenericValueDescriptor *valueDescriptors) : Header(header), Params(params), Requirements(requirements), PackShapeHeader(packShapeHeader), PackShapeDescriptors(packShapeDescriptors), ValueHeader(valueHeader), ValueDescriptors(valueDescriptors) {} llvm::ArrayRef getParams() const { return llvm::ArrayRef(Params, Header.NumParams); } llvm::ArrayRef> getRequirements() const { return llvm::ArrayRef(Requirements, Header.NumRequirements); } const GenericPackShapeHeader &getGenericPackShapeHeader() const { return PackShapeHeader; } llvm::ArrayRef getGenericPackShapeDescriptors() const { return llvm::ArrayRef(PackShapeDescriptors, PackShapeHeader.NumPacks); } const GenericValueHeader &getGenericValueHeader() const { return ValueHeader; } llvm::ArrayRef getGenericValueDescriptors() const { return llvm::ArrayRef(ValueDescriptors, ValueHeader.NumValues); } size_t getArgumentLayoutSizeInWords() const { return Header.getArgumentLayoutSizeInWords(); } }; template class TargetGenericEnvironment : public swift::ABI::TrailingObjects, uint16_t, GenericParamDescriptor, TargetGenericRequirementDescriptor> { using GenericRequirementDescriptor = TargetGenericRequirementDescriptor; using TrailingObjects = swift::ABI::TrailingObjects, uint16_t, GenericParamDescriptor, GenericRequirementDescriptor>; friend TrailingObjects; #if !defined(_MSC_VER) || _MSC_VER >= 1920 template using OverloadToken = typename TrailingObjects::template OverloadToken; #else // MSVC 2017 trips parsing an using of an using, of a variadic template #define OverloadToken typename TrailingObjects::template OverloadToken #endif size_t numTrailingObjects(OverloadToken) const { return Flags.getNumGenericParameterLevels(); } size_t numTrailingObjects(OverloadToken) const { return getGenericParameterCounts().back(); } size_t numTrailingObjects(OverloadToken) const { return Flags.getNumGenericRequirements(); } #if defined(_MSC_VER) && _MSC_VER < 1920 #undef OverloadToken #endif GenericEnvironmentFlags Flags; public: /// Retrieve the cumulative generic parameter counts at each level of genericity. llvm::ArrayRef getGenericParameterCounts() const { return llvm::ArrayRef(this->template getTrailingObjects(), Flags.getNumGenericParameterLevels()); } /// Retrieve the generic parameters descriptors. llvm::ArrayRef getGenericParameters() const { return llvm::ArrayRef( this->template getTrailingObjects(), getGenericParameterCounts().back()); } /// Retrieve the generic requirements. llvm::ArrayRef getGenericRequirements() const { return llvm::ArrayRef( this->template getTrailingObjects(), Flags.getNumGenericRequirements()); } }; using GenericEnvironmentDescriptor = TargetGenericEnvironment; /// CRTP class for a context descriptor that includes trailing generic /// context description. template class TargetGenericContextHeaderType = TargetGenericContextDescriptorHeader, typename... FollowingTrailingObjects> class TrailingGenericContextObjects; // This oddity with partial specialization is necessary to get // reasonable-looking code while also working around various kinds of // compiler bad behavior with injected class names. template class TargetSelf, template class TargetGenericContextHeaderType, typename... FollowingTrailingObjects> class TrailingGenericContextObjects, TargetGenericContextHeaderType, FollowingTrailingObjects...> : protected swift::ABI::TrailingObjects, TargetGenericContextHeaderType, GenericParamDescriptor, TargetGenericRequirementDescriptor, GenericPackShapeHeader, GenericPackShapeDescriptor, ConditionalInvertibleProtocolSet, ConditionalInvertibleProtocolsRequirementCount, TargetConditionalInvertibleProtocolRequirement, GenericValueHeader, GenericValueDescriptor, FollowingTrailingObjects...> { protected: using Self = TargetSelf; using GenericContextHeaderType = TargetGenericContextHeaderType; using GenericRequirementDescriptor = TargetGenericRequirementDescriptor; using GenericConditionalInvertibleProtocolRequirement = TargetConditionalInvertibleProtocolRequirement; using TrailingObjects = swift::ABI::TrailingObjects; friend TrailingObjects; #if !defined(_MSC_VER) || _MSC_VER >= 1920 template using OverloadToken = typename TrailingObjects::template OverloadToken; #else // MSVC 2017 trips parsing an using of an using, of a variadic template #define OverloadToken typename TrailingObjects::template OverloadToken #endif const Self *asSelf() const { return static_cast(this); } public: using StoredSize = typename Runtime::StoredSize; using StoredPointer = typename Runtime::StoredPointer; const GenericContextHeaderType &getFullGenericContextHeader() const { assert(asSelf()->isGeneric()); return *this->template getTrailingObjects(); } const TargetGenericContextDescriptorHeader & getGenericContextHeader() const { /// HeaderType ought to be convertible to GenericContextDescriptorHeader. return getFullGenericContextHeader(); } bool hasConditionalInvertedProtocols() const { if (!asSelf()->isGeneric()) return false; return getGenericContextHeader().hasConditionalInvertedProtocols(); } const InvertibleProtocolSet & getConditionalInvertedProtocols() const { assert(hasConditionalInvertedProtocols()); return *this->template getTrailingObjects(); } /// Retrieve the counts for # of conditional invertible protocols for each /// conditional conformance to a invertible protocol. /// /// The counts are cumulative, so the first entry in the array is the /// number of requirements for the first conditional conformance. The /// second entry in the array is the number of requirements in the first /// and second conditional conformances. The last entry is, therefore, the /// total count of requirements in the structure. llvm::ArrayRef getConditionalInvertibleProtocolRequirementCounts() const { if (!asSelf()->hasConditionalInvertedProtocols()) return {}; return { this->template getTrailingObjects(), getNumConditionalInvertibleProtocolsRequirementCounts() }; } /// Retrieve the array of requirements for conditional conformances to /// the ith conditional conformance to a invertible protocol. llvm::ArrayRef getConditionalInvertibleProtocolRequirementsAt(unsigned i) const { auto counts = getConditionalInvertibleProtocolRequirementCounts(); assert(i < counts.size()); unsigned startIndex = (i == 0) ? 0 : counts[i-1].count; unsigned endIndex = counts[i].count; auto basePtr = this->template getTrailingObjects(); return { basePtr + startIndex, basePtr + endIndex }; } /// Retrieve the array of requirements for conditional conformances to /// the ith conditional conformance to a invertible protocol. llvm::ArrayRef getConditionalInvertibleProtocolRequirementsFor( InvertibleProtocolKind kind ) const { if (!asSelf()->hasConditionalInvertedProtocols()) return { }; auto conditionallyInverted = getConditionalInvertedProtocols(); if (!conditionallyInverted.contains(kind)) return { }; // Count the number of "set" bits up to (but not including) the // bit we're looking at. unsigned targetBit = static_cast(kind); auto invertedBits = conditionallyInverted.rawBits(); unsigned priorBits = 0; for (unsigned i = 0; i != targetBit; ++i) { if (invertedBits & 0x01) ++priorBits; invertedBits = invertedBits >> 1; } return getConditionalInvertibleProtocolRequirementsAt(priorBits); } 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}; } GenericPackShapeHeader getGenericPackShapeHeader() const { if (!asSelf()->isGeneric()) return {0, 0}; if (!getGenericContextHeader().Flags.hasTypePacks()) return {0, 0}; return *this->template getTrailingObjects(); } llvm::ArrayRef getGenericPackShapeDescriptors() const { auto header = getGenericPackShapeHeader(); if (header.NumPacks == 0) return {}; return {this->template getTrailingObjects(), header.NumPacks}; } GenericValueHeader getGenericValueHeader() const { if (!asSelf()->isGeneric()) return {0}; if (!getGenericContextHeader().Flags.hasValues()) return {0}; return *this->template getTrailingObjects(); } llvm::ArrayRef getGenericValueDescriptors() const { auto header = getGenericValueHeader(); if (header.NumValues == 0) return {}; return {this->template getTrailingObjects(), header.NumValues}; } RuntimeGenericSignature getGenericSignature() const { if (!asSelf()->isGeneric()) return RuntimeGenericSignature(); return {getGenericContextHeader(), getGenericParams().data(), getGenericRequirements().data(), getGenericPackShapeHeader(), getGenericPackShapeDescriptors().data(), getGenericValueHeader(), getGenericValueDescriptors().data()}; } static size_t trailingTypeCount() { return TrailingObjects::trailingTypeCount(); } size_t sizeWithTrailingTypeCount(size_t n) const { return TrailingObjects::sizeWithTrailingTypeCount(n); } 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; } size_t numTrailingObjects(OverloadToken) const { if (!asSelf()->isGeneric()) return 0; return getGenericContextHeader().Flags.hasTypePacks() ? 1 : 0; } size_t numTrailingObjects(OverloadToken) const { if (!asSelf()->isGeneric()) return 0; if (!getGenericContextHeader().Flags.hasTypePacks()) return 0; return getGenericPackShapeHeader().NumPacks; } size_t numTrailingObjects( OverloadToken ) const { return asSelf()->hasConditionalInvertedProtocols() ? 1 : 0; } unsigned getNumConditionalInvertibleProtocolsRequirementCounts() const { if (!asSelf()->hasConditionalInvertedProtocols()) return 0; return popcount(getConditionalInvertedProtocols().rawBits()); } size_t numTrailingObjects( OverloadToken ) const { return getNumConditionalInvertibleProtocolsRequirementCounts(); } size_t numTrailingObjects( OverloadToken ) const { auto counts = getConditionalInvertibleProtocolRequirementCounts(); return counts.empty() ? 0 : counts.back().count; } size_t numTrailingObjects(OverloadToken) const { if (!asSelf()->isGeneric()) return 0; return getGenericContextHeader().Flags.hasValues() ? 1 : 0; } size_t numTrailingObjects(OverloadToken) const { if (!asSelf()->isGeneric()) return 0; if (!getGenericContextHeader().Flags.hasValues()) return 0; return getGenericValueHeader().NumValues; } #if defined(_MSC_VER) && _MSC_VER < 1920 #undef OverloadToken #endif }; /// Description of a generic context. template struct TargetGenericContext final : TrailingGenericContextObjects, TargetGenericContextDescriptorHeader> { // 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; } }; } // end namespace swift #endif