From b8cbd4f2269bf7454f091e15c47c396e8ff0a096 Mon Sep 17 00:00:00 2001 From: Karoy Lorentey Date: Mon, 25 Apr 2022 15:06:53 -0700 Subject: [PATCH 01/13] [stdlib][docs] Clarify BidirectionalCollection requirements MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As discussed on the forum, `BidirectionalCollection` requirements as currently stated can be interpreted to forbid conforming types from accepting indices that lie between valid (i.e., reachable) indices in the collection. Among other undesirable effects, this interpretation would render SE-0180 (String.Index overhaul) incompatible with these requirements. Update the wording to clarify that the requirements only apply to valid indices. (Collection protocols do not constrain the behavior of invalid indices — it’s up to individual collection types to implement them as they wish.) https://forums.swift.org/t/string-index-unification-vs-bidirectionalcollection-requirements/55946 rdar://92297280 --- stdlib/public/core/BidirectionalCollection.swift | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/stdlib/public/core/BidirectionalCollection.swift b/stdlib/public/core/BidirectionalCollection.swift index a3d82293c0296..6342bf90ebe7d 100644 --- a/stdlib/public/core/BidirectionalCollection.swift +++ b/stdlib/public/core/BidirectionalCollection.swift @@ -28,13 +28,17 @@ /// `Collection` protocol. /// /// Indices that are moved forward and backward in a bidirectional collection -/// move by the same amount in each direction. That is, for any index `i` into -/// a bidirectional collection `c`: +/// move by the same amount in each direction. That is, for any valid index `i` +/// into a bidirectional collection `c`: /// /// - If `i >= c.startIndex && i < c.endIndex`, then /// `c.index(before: c.index(after: i)) == i`. /// - If `i > c.startIndex && i <= c.endIndex`, then /// `c.index(after: c.index(before: i)) == i`. +/// +/// Valid indices are exactly those indices that are reachable from the +/// collection's `startIndex` by repeated applications of `index(after:)`, up +/// to, and including, the `endIndex`. public protocol BidirectionalCollection: Collection where SubSequence: BidirectionalCollection, Indices: BidirectionalCollection { // FIXME: Only needed for associated type inference. From e15ca515266c7a52caa3fc9b62a7038dd6057983 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Mon, 25 Apr 2022 16:43:51 -0700 Subject: [PATCH 02/13] Update Runtime Generalized Existential Metadata Tidy up the metadata definitions. * Generalize a number of metadata kinds for out-of-process clients * Introduce conveniences to make runtime lookups easier * Introduce TargetExistentialTypeExpression to TrailingObjects stops complaining about OverloadTokens being ambiguous Note that there is no impact on the layout of the metadata - the changes here are all ABI-compatible. --- include/swift/ABI/GenericContext.h | 20 ++++---- include/swift/ABI/Metadata.h | 48 ++++++++++++------- lib/RemoteAST/RemoteAST.cpp | 13 +++++ .../SwiftRemoteMirror/SwiftRemoteMirror.cpp | 13 +++++ stdlib/public/runtime/Metadata.cpp | 13 +++-- stdlib/public/runtime/MetadataCache.h | 37 +++++++------- 6 files changed, 97 insertions(+), 47 deletions(-) diff --git a/include/swift/ABI/GenericContext.h b/include/swift/ABI/GenericContext.h index 8e382ac93d0ba..82f4870641099 100644 --- a/include/swift/ABI/GenericContext.h +++ b/include/swift/ABI/GenericContext.h @@ -58,7 +58,7 @@ struct TargetGenericContextDescriptorHeader { /// Key arguments include generic parameters and conformance /// requirements which are part of the identity of the context. /// - /// The key area of the argument layout considers of a sequence + /// The key area of the argument layout consists of a sequence /// of type metadata pointers (in the same order as the parameter /// descriptors, for those parameters which satisfy hasKeyArgument()) /// followed by a sequence of witness table pointers (in the same @@ -191,25 +191,29 @@ using GenericRequirementDescriptor = extern const GenericParamDescriptor ImplicitGenericParamDescriptors[MaxNumImplicitGenericParamDescriptors]; +template +const GenericParamDescriptor *targetImplicitGenericParamDescriptors(); + /// A runtime description of a generic signature. +template class RuntimeGenericSignature { - GenericContextDescriptorHeader Header; + TargetGenericContextDescriptorHeader Header; const GenericParamDescriptor *Params; - const GenericRequirementDescriptor *Requirements; + const TargetGenericRequirementDescriptor *Requirements; public: RuntimeGenericSignature() : Header{0, 0, 0, 0}, Params(nullptr), Requirements(nullptr) {} - RuntimeGenericSignature(const GenericContextDescriptorHeader &header, + RuntimeGenericSignature(const TargetGenericContextDescriptorHeader &header, const GenericParamDescriptor *params, - const GenericRequirementDescriptor *requirements) + const TargetGenericRequirementDescriptor *requirements) : Header(header), Params(params), Requirements(requirements) {} llvm::ArrayRef getParams() const { return llvm::makeArrayRef(Params, Header.NumParams); } - llvm::ArrayRef getRequirements() const { + llvm::ArrayRef> getRequirements() const { return llvm::makeArrayRef(Requirements, Header.NumRequirements); } @@ -375,8 +379,8 @@ class TrailingGenericContextObjects, * sizeof(StoredPointer); } - RuntimeGenericSignature getGenericSignature() const { - if (!asSelf()->isGeneric()) return RuntimeGenericSignature(); + RuntimeGenericSignature getGenericSignature() const { + if (!asSelf()->isGeneric()) return RuntimeGenericSignature(); return {getGenericContextHeader(), getGenericParams().data(), getGenericRequirements().data()}; diff --git a/include/swift/ABI/Metadata.h b/include/swift/ABI/Metadata.h index 059bc05c95c85..17173cdc57c1e 100644 --- a/include/swift/ABI/Metadata.h +++ b/include/swift/ABI/Metadata.h @@ -1735,6 +1735,12 @@ struct TargetExistentialTypeMetadata using ExistentialTypeMetadata = TargetExistentialTypeMetadata; +template +struct TargetExistentialTypeExpression { + /// The type expression. + TargetRelativeDirectPointer name; +}; + /// A description of the shape of an existential type. /// /// An existential type has the general form: @@ -1791,7 +1797,7 @@ struct TargetExtendedExistentialTypeShape // Optional generalization signature header TargetGenericContextDescriptorHeader, // Optional type subexpression - TargetRelativeDirectPointer, + TargetExistentialTypeExpression, // Optional suggested value witnesses TargetRelativeIndirectablePointer, /*nullable*/ false>, @@ -1802,8 +1808,6 @@ struct TargetExtendedExistentialTypeShape // for generalization signature TargetGenericRequirementDescriptor> { private: - using RelativeStringPointer = - TargetRelativeDirectPointer; using RelativeValueWitnessTablePointer = TargetRelativeIndirectablePointer, @@ -1812,7 +1816,7 @@ struct TargetExtendedExistentialTypeShape swift::ABI::TrailingObjects< TargetExtendedExistentialTypeShape, TargetGenericContextDescriptorHeader, - RelativeStringPointer, + TargetExistentialTypeExpression, RelativeValueWitnessTablePointer, GenericParamDescriptor, TargetGenericRequirementDescriptor>; @@ -1825,7 +1829,7 @@ struct TargetExtendedExistentialTypeShape return Flags.hasGeneralizationSignature(); } - size_t numTrailingObjects(OverloadToken) const { + size_t numTrailingObjects(OverloadToken>) const { return Flags.hasTypeExpression(); } @@ -1879,12 +1883,13 @@ struct TargetExtendedExistentialTypeShape /// we nonetheless distinguish at compile time. Storing this also /// allows us to far more easily produce a formal type from this /// shape reflectively. - RelativeStringPointer ExistentialType; + TargetRelativeDirectPointer + ExistentialType; /// The header describing the requirement signature of the existential. TargetGenericContextDescriptorHeader ReqSigHeader; - RuntimeGenericSignature getRequirementSignature() const { + RuntimeGenericSignature getRequirementSignature() const { return {ReqSigHeader, getReqSigParams(), getReqSigRequirements()}; } @@ -1894,8 +1899,8 @@ struct TargetExtendedExistentialTypeShape const GenericParamDescriptor *getReqSigParams() const { return Flags.hasImplicitReqSigParams() - ? ImplicitGenericParamDescriptors - : this->template getTrailingObjects(); + ? swift::targetImplicitGenericParamDescriptors() + : this->template getTrailingObjects(); } unsigned getNumReqSigRequirements() const { @@ -1911,10 +1916,11 @@ struct TargetExtendedExistentialTypeShape /// The type expression of the existential, as a symbolic mangled type /// string. Must be null if the header is just the (single) /// requirement type parameter. - TargetPointer getTypeExpression() const { + const TargetExistentialTypeExpression *getTypeExpression() const { return Flags.hasTypeExpression() - ? this->template getTrailingObjects()->get() - : nullptr; + ? this->template getTrailingObjects< + TargetExistentialTypeExpression>() + : nullptr; } bool isTypeExpressionOpaque() const { @@ -1961,8 +1967,8 @@ struct TargetExtendedExistentialTypeShape return Flags.hasGeneralizationSignature(); } - RuntimeGenericSignature getGeneralizationSignature() const { - if (!hasGeneralizationSignature()) return RuntimeGenericSignature(); + RuntimeGenericSignature getGeneralizationSignature() const { + if (!hasGeneralizationSignature()) return RuntimeGenericSignature(); return {*getGenSigHeader(), getGenSigParams(), getGenSigRequirements()}; } @@ -1974,7 +1980,7 @@ struct TargetExtendedExistentialTypeShape const GenericParamDescriptor *getGenSigParams() const { assert(hasGeneralizationSignature()); if (Flags.hasImplicitGenSigParams()) - return ImplicitGenericParamDescriptors; + return swift::targetImplicitGenericParamDescriptors(); auto base = this->template getTrailingObjects(); if (!Flags.hasImplicitReqSigParams()) base += getNumReqSigParams(); @@ -2086,6 +2092,8 @@ struct TargetExtendedExistentialTypeMetadata swift::ABI::TrailingObjects< TargetExtendedExistentialTypeMetadata, ConstTargetPointer> { + using StoredSize = typename Runtime::StoredSize; + private: using TrailingObjects = swift::ABI::TrailingObjects< @@ -2097,9 +2105,12 @@ struct TargetExtendedExistentialTypeMetadata using OverloadToken = typename TrailingObjects::template OverloadToken; size_t numTrailingObjects(OverloadToken>) const { - return Shape->getGenSigLayoutSizeInWords(); + return Shape->getGenSigArgumentLayoutSizeInWords(); } +public: + static constexpr StoredSize OffsetToArguments = sizeof(TargetMetadata); + public: explicit constexpr TargetExtendedExistentialTypeMetadata(const ExtendedExistentialTypeShape *shape) @@ -2113,6 +2124,11 @@ struct TargetExtendedExistentialTypeMetadata ConstTargetPointer const *getGeneralizationArguments() const { return this->template getTrailingObjects>(); } + +public: + static bool classof(const TargetMetadata *metadata) { + return metadata->getKind() == MetadataKind::ExtendedExistential; + } }; using ExtendedExistentialTypeMetadata = TargetExtendedExistentialTypeMetadata; diff --git a/lib/RemoteAST/RemoteAST.cpp b/lib/RemoteAST/RemoteAST.cpp index cd8c2c301920f..bd6cca2d9e79d 100644 --- a/lib/RemoteAST/RemoteAST.cpp +++ b/lib/RemoteAST/RemoteAST.cpp @@ -51,6 +51,19 @@ using namespace swift::remoteAST; using irgen::Alignment; using irgen::Size; +template +const GenericParamDescriptor *swift::targetImplicitGenericParamDescriptors() { + 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; +} + static inline RemoteAddress operator+(RemoteAddress address, Size offset) { return RemoteAddress(address.getAddressData() + offset.getValue()); } diff --git a/stdlib/public/SwiftRemoteMirror/SwiftRemoteMirror.cpp b/stdlib/public/SwiftRemoteMirror/SwiftRemoteMirror.cpp index df305be8cc488..c8a294a35c892 100644 --- a/stdlib/public/SwiftRemoteMirror/SwiftRemoteMirror.cpp +++ b/stdlib/public/SwiftRemoteMirror/SwiftRemoteMirror.cpp @@ -43,6 +43,19 @@ using Runtime = External>>; #endif using NativeReflectionContext = swift::reflection::ReflectionContext; +template +const GenericParamDescriptor *swift::targetImplicitGenericParamDescriptors() { + 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; +} + struct SwiftReflectionContext { NativeReflectionContext *nativeContext; std::vector> freeFuncs; diff --git a/stdlib/public/runtime/Metadata.cpp b/stdlib/public/runtime/Metadata.cpp index 83ce05df50d97..60a8fe3d09802 100644 --- a/stdlib/public/runtime/Metadata.cpp +++ b/stdlib/public/runtime/Metadata.cpp @@ -77,7 +77,7 @@ using namespace metadataimpl; // GenericParamDescriptor is a single byte, so while it's difficult to // imagine needing even a quarter this many generic params, there's very // little harm in doing it. -constexpr GenericParamDescriptor +const GenericParamDescriptor swift::ImplicitGenericParamDescriptors[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, @@ -86,6 +86,12 @@ swift::ImplicitGenericParamDescriptors[MaxNumImplicitGenericParamDescriptors] = }; static_assert(MaxNumImplicitGenericParamDescriptors == 64, "length mismatch"); +template <> +const GenericParamDescriptor * +swift::targetImplicitGenericParamDescriptors() { + return ImplicitGenericParamDescriptors; +} + static ClassMetadata * _swift_relocateClassMetadata(const ClassDescriptor *description, const ResilientClassMetadataPattern *pattern); @@ -378,7 +384,7 @@ namespace { class GenericMetadataCache : public MetadataCache { public: - GenericSignatureLayout SigLayout; + GenericSignatureLayout SigLayout; GenericMetadataCache(const TargetGenericContext &genericContext) : SigLayout(genericContext.getGenericSignature()) { @@ -4364,7 +4370,8 @@ ExtendedExistentialTypeCacheEntry::getOrCreateVWT(Key key) { auto sigSizeInWords = shape->ReqSigHeader.getArgumentLayoutSizeInWords(); #ifndef NDEBUG - auto layout = GenericSignatureLayout(shape->getRequirementSignature()); + auto layout = + GenericSignatureLayout(shape->getRequirementSignature()); assert(layout.NumKeyParameters == shape->ReqSigHeader.NumParams && "requirement signature for existential includes a " "redundant parameter?"); diff --git a/stdlib/public/runtime/MetadataCache.h b/stdlib/public/runtime/MetadataCache.h index 1614deff55899..754084aef53c0 100644 --- a/stdlib/public/runtime/MetadataCache.h +++ b/stdlib/public/runtime/MetadataCache.h @@ -401,11 +401,12 @@ class SimpleLockingCacheEntryBase { /// A summary of the information from a generic signature that's /// sufficient to compare arguments. +template struct GenericSignatureLayout { uint16_t NumKeyParameters = 0; uint16_t NumWitnessTables = 0; - GenericSignatureLayout(const RuntimeGenericSignature &sig) { + GenericSignatureLayout(const RuntimeGenericSignature &sig) { for (const auto &gp : sig.getParams()) { if (gp.hasKeyArgument()) ++NumKeyParameters; @@ -421,13 +422,13 @@ struct GenericSignatureLayout { return NumKeyParameters + NumWitnessTables; } - friend bool operator==(const GenericSignatureLayout &lhs, - const GenericSignatureLayout &rhs) { + friend bool operator==(const GenericSignatureLayout &lhs, + const GenericSignatureLayout &rhs) { return lhs.NumKeyParameters == rhs.NumKeyParameters && lhs.NumWitnessTables == rhs.NumWitnessTables; } - friend bool operator!=(const GenericSignatureLayout &lhs, - const GenericSignatureLayout &rhs) { + friend bool operator!=(const GenericSignatureLayout &lhs, + const GenericSignatureLayout &rhs) { return !(lhs == rhs); } }; @@ -435,7 +436,7 @@ struct GenericSignatureLayout { /// A key value as provided to the concurrent map. class MetadataCacheKey { const void * const *Data; - GenericSignatureLayout Layout; + GenericSignatureLayout Layout; uint32_t Hash; /// Compare two witness tables, which may involving checking the @@ -476,9 +477,8 @@ class MetadataCacheKey { private: /// Compare the content from two keys. - static int compareContent(const void * const *adata, - const void * const *bdata, - const GenericSignatureLayout &layout) { + static int compareContent(const void *const *adata, const void *const *bdata, + const GenericSignatureLayout &layout) { // Compare generic arguments for key parameters. for (unsigned i = 0; i != layout.NumKeyParameters; ++i) { if (auto result = comparePointers(*adata++, *bdata++)) @@ -497,14 +497,13 @@ class MetadataCacheKey { } public: - MetadataCacheKey(const GenericSignatureLayout &layout, - const void * const *data) - : Data(data), Layout(layout), Hash(computeHash()) { } + MetadataCacheKey(const GenericSignatureLayout &layout, + const void *const *data) + : Data(data), Layout(layout), Hash(computeHash()) {} - MetadataCacheKey(const GenericSignatureLayout &layout, - const void * const *data, - uint32_t hash) - : Data(data), Layout(layout), Hash(hash) {} + MetadataCacheKey(const GenericSignatureLayout &layout, + const void *const *data, uint32_t hash) + : Data(data), Layout(layout), Hash(hash) {} bool operator==(MetadataCacheKey rhs) const { // Compare the hashes. @@ -545,9 +544,7 @@ class MetadataCacheKey { return Hash; } - const GenericSignatureLayout &layout() const { - return Layout; - } + const GenericSignatureLayout &layout() const { return Layout; } friend llvm::hash_code hash_value(const MetadataCacheKey &key) { return key.Hash; @@ -1378,7 +1375,7 @@ class VariadicMetadataCacheEntryBase : private: /// These are set during construction and never changed. - const GenericSignatureLayout Layout; + const GenericSignatureLayout Layout; const uint32_t Hash; /// Valid if TrackingInfo.getState() >= PrivateMetadataState::Abstract. From a410d1a6bee5a3eee8986217ec3faead5d0e6b9b Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Mon, 25 Apr 2022 16:49:34 -0700 Subject: [PATCH 03/13] [NFC] Consolidate Builder Result Types --- include/swift/AST/ASTDemangler.h | 3 ++- include/swift/Demangling/TypeDecoder.h | 1 + include/swift/Reflection/TypeRefBuilder.h | 7 ++++--- include/swift/Remote/MetadataReader.h | 2 ++ stdlib/public/runtime/MetadataLookup.cpp | 2 ++ 5 files changed, 11 insertions(+), 4 deletions(-) diff --git a/include/swift/AST/ASTDemangler.h b/include/swift/AST/ASTDemangler.h index b425e745e6876..901e689a2584a 100644 --- a/include/swift/AST/ASTDemangler.h +++ b/include/swift/AST/ASTDemangler.h @@ -59,6 +59,8 @@ class ASTBuilder { using BuiltType = swift::Type; using BuiltTypeDecl = swift::GenericTypeDecl *; // nominal or type alias using BuiltProtocolDecl = swift::ProtocolDecl *; + using BuiltGenericTypeParam = swift::GenericTypeParamType *; + using BuiltRequirement = swift::Requirement; explicit ASTBuilder(ASTContext &ctx) : Ctx(ctx) {} ASTContext &getASTContext() { return Ctx; } @@ -134,7 +136,6 @@ class ASTBuilder { Type createSILBoxType(Type base); using BuiltSILBoxField = llvm::PointerIntPair; using BuiltSubstitution = std::pair; - using BuiltRequirement = swift::Requirement; using BuiltLayoutConstraint = swift::LayoutConstraint; Type createSILBoxTypeWithLayout(ArrayRef Fields, ArrayRef Substitutions, diff --git a/include/swift/Demangling/TypeDecoder.h b/include/swift/Demangling/TypeDecoder.h index 7361e0147b5b3..0ae270bcbd2e7 100644 --- a/include/swift/Demangling/TypeDecoder.h +++ b/include/swift/Demangling/TypeDecoder.h @@ -464,6 +464,7 @@ class TypeDecoder { using BuiltSubstitution = typename BuilderType::BuiltSubstitution; using BuiltRequirement = typename BuilderType::BuiltRequirement; using BuiltLayoutConstraint = typename BuilderType::BuiltLayoutConstraint; + using BuiltGenericTypeParam = typename BuilderType::BuiltGenericTypeParam; using NodeKind = Demangle::Node::Kind; BuilderType &Builder; diff --git a/include/swift/Reflection/TypeRefBuilder.h b/include/swift/Reflection/TypeRefBuilder.h index dc962a9bd6a98..5b69aa8d6f5f6 100644 --- a/include/swift/Reflection/TypeRefBuilder.h +++ b/include/swift/Reflection/TypeRefBuilder.h @@ -356,6 +356,10 @@ class TypeRefBuilder { using BuiltTypeDecl = llvm::Optional; using BuiltProtocolDecl = llvm::Optional>; + using BuiltSubstitution = std::pair; + using BuiltRequirement = TypeRefRequirement; + using BuiltLayoutConstraint = TypeRefLayoutConstraint; + using BuiltGenericTypeParam = const GenericTypeParameterTypeRef *; TypeRefBuilder(const TypeRefBuilder &other) = delete; TypeRefBuilder &operator=(const TypeRefBuilder &other) = delete; @@ -670,9 +674,6 @@ class TypeRefBuilder { } using BuiltSILBoxField = typename SILBoxTypeWithLayoutTypeRef::Field; - using BuiltSubstitution = std::pair; - using BuiltRequirement = TypeRefRequirement; - using BuiltLayoutConstraint = TypeRefLayoutConstraint; BuiltLayoutConstraint getLayoutConstraint(LayoutConstraintKind kind) { // FIXME: Implement this. return {}; diff --git a/include/swift/Remote/MetadataReader.h b/include/swift/Remote/MetadataReader.h index a34aaf50a5864..c75f48a6e8392 100644 --- a/include/swift/Remote/MetadataReader.h +++ b/include/swift/Remote/MetadataReader.h @@ -165,6 +165,8 @@ class MetadataReader { using BuiltTypeDecl = typename BuilderType::BuiltTypeDecl; using BuiltProtocolDecl = typename BuilderType::BuiltProtocolDecl; using BuiltRequirement = typename BuilderType::BuiltRequirement; + using BuiltSubstitution = typename BuilderType::BuiltSubstitution; + using BuiltGenericTypeParam = typename BuilderType::BuiltGenericTypeParam; using StoredPointer = typename Runtime::StoredPointer; using StoredSignedPointer = typename Runtime::StoredSignedPointer; using StoredSize = typename Runtime::StoredSize; diff --git a/stdlib/public/runtime/MetadataLookup.cpp b/stdlib/public/runtime/MetadataLookup.cpp index fb6564d20ec9d..9ce0b82b4de5a 100644 --- a/stdlib/public/runtime/MetadataLookup.cpp +++ b/stdlib/public/runtime/MetadataLookup.cpp @@ -1334,6 +1334,8 @@ class DecodedMetadataBuilder { using BuiltType = const Metadata *; using BuiltTypeDecl = const ContextDescriptor *; using BuiltProtocolDecl = ProtocolDescriptorRef; + using BuiltSubstitution = std::pair; + using BuiltGenericTypeParam = const Metadata *; BuiltType decodeMangledType(NodePointer node, bool forRequirement = true) { From d710b52b66fc2dc04f5cedb93f69badc67a94a38 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Mon, 25 Apr 2022 16:59:56 -0700 Subject: [PATCH 04/13] Add Substitution Machinery to Builders Add requirements to the Builder concept to construct generic signatures and substitution maps. Then introduce a `subst` requirement that uses the substitution map to call through to the builder's notion of type (ref) substitution. This infrastructure is sufficient to model the notion of a RuntimeGenericSignature. --- include/swift/AST/ASTDemangler.h | 14 +++++ include/swift/Demangling/TypeDecoder.h | 2 + include/swift/Reflection/TypeRef.h | 31 +++++++++++ include/swift/Reflection/TypeRefBuilder.h | 65 ++++++++++++++++++++--- include/swift/Remote/MetadataReader.h | 2 + lib/AST/ASTDemangler.cpp | 27 ++++++++++ stdlib/public/runtime/MetadataLookup.cpp | 3 +- 7 files changed, 137 insertions(+), 7 deletions(-) diff --git a/include/swift/AST/ASTDemangler.h b/include/swift/AST/ASTDemangler.h index 901e689a2584a..f00299d896dd9 100644 --- a/include/swift/AST/ASTDemangler.h +++ b/include/swift/AST/ASTDemangler.h @@ -59,8 +59,11 @@ class ASTBuilder { using BuiltType = swift::Type; using BuiltTypeDecl = swift::GenericTypeDecl *; // nominal or type alias using BuiltProtocolDecl = swift::ProtocolDecl *; + using BuiltGenericSignature = swift::GenericSignature; using BuiltGenericTypeParam = swift::GenericTypeParamType *; using BuiltRequirement = swift::Requirement; + using BuiltSubstitutionMap = swift::SubstitutionMap; + explicit ASTBuilder(ASTContext &ctx) : Ctx(ctx) {} ASTContext &getASTContext() { return Ctx; } @@ -114,6 +117,8 @@ class ASTBuilder { bool isClassBound, bool forRequirement = true); + Type createProtocolTypeFromDecl(ProtocolDecl *protocol); + Type createParameterizedProtocolType(Type base, ArrayRef args); Type createExistentialMetatypeType(Type instance, @@ -168,6 +173,15 @@ class ASTBuilder { Type createParenType(Type base); + BuiltGenericSignature + createGenericSignature(ArrayRef params, + ArrayRef requirements); + + BuiltSubstitutionMap createSubstitutionMap(BuiltGenericSignature sig, + ArrayRef replacements); + + Type subst(Type subject, const BuiltSubstitutionMap &Subs) const; + LayoutConstraint getLayoutConstraint(LayoutConstraintKind kind); LayoutConstraint getLayoutConstraintWithSizeAlign(LayoutConstraintKind kind, unsigned size, diff --git a/include/swift/Demangling/TypeDecoder.h b/include/swift/Demangling/TypeDecoder.h index 0ae270bcbd2e7..d8ef4b940e5f3 100644 --- a/include/swift/Demangling/TypeDecoder.h +++ b/include/swift/Demangling/TypeDecoder.h @@ -465,6 +465,8 @@ class TypeDecoder { using BuiltRequirement = typename BuilderType::BuiltRequirement; using BuiltLayoutConstraint = typename BuilderType::BuiltLayoutConstraint; using BuiltGenericTypeParam = typename BuilderType::BuiltGenericTypeParam; + using BuiltGenericSignature = typename BuilderType::BuiltGenericSignature; + using BuiltSubstitutionMap = typename BuilderType::BuiltSubstitutionMap; using NodeKind = Demangle::Node::Kind; BuilderType &Builder; diff --git a/include/swift/Reflection/TypeRef.h b/include/swift/Reflection/TypeRef.h index 74c5035c1c512..ef4ce80a0cd64 100644 --- a/include/swift/Reflection/TypeRef.h +++ b/include/swift/Reflection/TypeRef.h @@ -741,6 +741,37 @@ class DependentMemberTypeRef final : public TypeRef { } }; +/// A representation of a dynamically-constructed generic signature. +/// +/// \note This class is not a \c TypeRef. +class GenericSignatureRef final { + std::vector Params; + std::vector Requirements; + +public: + GenericSignatureRef( + llvm::ArrayRef Params, + llvm::ArrayRef Requirements) + : Params(Params.begin(), Params.end()), + Requirements(Requirements.begin(), Requirements.end()) {} + + template + static const GenericSignatureRef * + create(Allocator &A, + llvm::ArrayRef Params, + llvm::ArrayRef Requirements) { + return A.template makeGenericSignatureRef(Params, Requirements); + } + + const llvm::ArrayRef getParams() const { + return Params; + } + + const llvm::ArrayRef getRequirements() const { + return Requirements; + } +}; + class ForeignClassTypeRef final : public TypeRef { std::string Name; diff --git a/include/swift/Reflection/TypeRefBuilder.h b/include/swift/Reflection/TypeRefBuilder.h index 5b69aa8d6f5f6..d0edd6fed7c8b 100644 --- a/include/swift/Reflection/TypeRefBuilder.h +++ b/include/swift/Reflection/TypeRefBuilder.h @@ -360,6 +360,8 @@ class TypeRefBuilder { using BuiltRequirement = TypeRefRequirement; using BuiltLayoutConstraint = TypeRefLayoutConstraint; using BuiltGenericTypeParam = const GenericTypeParameterTypeRef *; + using BuiltGenericSignature = const GenericSignatureRef *; + using BuiltSubstitutionMap = llvm::DenseMap; TypeRefBuilder(const TypeRefBuilder &other) = delete; TypeRefBuilder &operator=(const TypeRefBuilder &other) = delete; @@ -378,6 +380,8 @@ class TypeRefBuilder { /// Cache for field info lookups. std::unordered_map> FieldTypeInfoCache; + std::vector> SignatureRefPool; + TypeConverter TC; MetadataSourceBuilder MSB; @@ -394,6 +398,13 @@ class TypeRefBuilder { return TR; } + template + const GenericSignatureRef *makeGenericSignatureRef(Args... args) { + const auto TR = new GenericSignatureRef(::std::forward(args)...); + SignatureRefPool.push_back(std::unique_ptr(TR)); + return TR; + } + Demangle::NodeFactory &getNodeFactory() { return Dem; } void clearNodeFactory() { Dem.clear(); } @@ -599,6 +610,14 @@ class TypeRefBuilder { *this, {}, result, funcFlags, diffKind, nullptr); } + BuiltType createProtocolTypeFromDecl(BuiltProtocolDecl protocol) { + if (protocol->second) { + return llvm::cast(createObjCProtocolType(protocol->first)); + } else { + return llvm::cast(createNominalType(protocol->first)); + } + } + const ProtocolCompositionTypeRef * createProtocolCompositionType(llvm::ArrayRef protocols, BuiltType superclass, bool isClassBound, @@ -608,10 +627,10 @@ class TypeRefBuilder { if (!protocol) continue; - if (protocol->second) - protocolRefs.push_back(createObjCProtocolType(protocol->first)); - else - protocolRefs.push_back(createNominalType(protocol->first)); + auto protocolType = createProtocolTypeFromDecl(*protocol); + if (!protocolType) + continue; + protocolRefs.push_back(protocolType); } return ProtocolCompositionTypeRef::create(*this, protocolRefs, superclass, @@ -720,8 +739,7 @@ class TypeRefBuilder { return createObjCClassType(name); } - const ObjCProtocolTypeRef * - createObjCProtocolType(const std::string &name) { + const ObjCProtocolTypeRef *createObjCProtocolType(const std::string &name) { return ObjCProtocolTypeRef::create(*this, name); } @@ -739,6 +757,41 @@ class TypeRefBuilder { return OpaqueTypeRef::get(); } + BuiltGenericSignature + createGenericSignature(llvm::ArrayRef builtParams, + llvm::ArrayRef requirements) { + std::vector params; + for (auto &builtParam : builtParams) { + auto *genericRef = + llvm::dyn_cast(builtParam); + if (!genericRef) + return nullptr; + params.push_back(genericRef); + } + return GenericSignatureRef::create(*this, params, requirements); + } + + BuiltSubstitutionMap + createSubstitutionMap(BuiltGenericSignature sig, + llvm::ArrayRef replacements) { + assert(sig->getParams().size() == replacements.size() && + "Not enough replacement parameters!"); + if (sig->getParams().size() != replacements.size()) + return BuiltSubstitutionMap{}; + + BuiltSubstitutionMap map{}; + for (unsigned paramIdx : indices(sig->getParams())) { + const auto *param = sig->getParams()[paramIdx]; + auto replacement = replacements[paramIdx]; + map[{param->getDepth(), param->getIndex()}] = replacement; + } + return map; + } + + BuiltType subst(BuiltType subject, const BuiltSubstitutionMap &Subs) { + return subject->subst(*this, Subs); + } + /// /// Parsing reflection metadata /// diff --git a/include/swift/Remote/MetadataReader.h b/include/swift/Remote/MetadataReader.h index c75f48a6e8392..4b430c2c250d0 100644 --- a/include/swift/Remote/MetadataReader.h +++ b/include/swift/Remote/MetadataReader.h @@ -166,7 +166,9 @@ class MetadataReader { using BuiltProtocolDecl = typename BuilderType::BuiltProtocolDecl; using BuiltRequirement = typename BuilderType::BuiltRequirement; using BuiltSubstitution = typename BuilderType::BuiltSubstitution; + using BuiltSubstitutionMap = typename BuilderType::BuiltSubstitutionMap; using BuiltGenericTypeParam = typename BuilderType::BuiltGenericTypeParam; + using BuiltGenericSignature = typename BuilderType::BuiltGenericSignature; using StoredPointer = typename Runtime::StoredPointer; using StoredSignedPointer = typename Runtime::StoredSignedPointer; using StoredSize = typename Runtime::StoredSize; diff --git a/lib/AST/ASTDemangler.cpp b/lib/AST/ASTDemangler.cpp index 0ae70a080434c..7bef8968705cf 100644 --- a/lib/AST/ASTDemangler.cpp +++ b/lib/AST/ASTDemangler.cpp @@ -595,6 +595,10 @@ Type ASTBuilder::createProtocolCompositionType( return ExistentialType::get(composition); } +Type ASTBuilder::createProtocolTypeFromDecl(ProtocolDecl *protocol) { + return protocol->getDeclaredInterfaceType(); +} + static MetatypeRepresentation getMetatypeRepresentation(ImplMetatypeRepresentation repr) { switch (repr) { @@ -794,6 +798,29 @@ Type ASTBuilder::createParenType(Type base) { return ParenType::get(Ctx, base); } +GenericSignature +ASTBuilder::createGenericSignature(ArrayRef builtParams, + ArrayRef requirements) { + std::vector params; + for (auto ¶m : builtParams) { + auto paramTy = param->getAs(); + if (!paramTy) + return GenericSignature(); + params.push_back(paramTy); + } + return GenericSignature::get(params, requirements); +} + +SubstitutionMap +ASTBuilder::createSubstitutionMap(BuiltGenericSignature sig, + ArrayRef replacements) { + return SubstitutionMap::get(sig, replacements, {}); +} + +Type ASTBuilder::subst(Type subject, const BuiltSubstitutionMap &Subs) const { + return subject.subst(Subs); +} + bool ASTBuilder::validateParentType(TypeDecl *decl, Type parent) { auto parentDecl = decl->getDeclContext()->getSelfNominalTypeDecl(); diff --git a/stdlib/public/runtime/MetadataLookup.cpp b/stdlib/public/runtime/MetadataLookup.cpp index 9ce0b82b4de5a..25b3069502784 100644 --- a/stdlib/public/runtime/MetadataLookup.cpp +++ b/stdlib/public/runtime/MetadataLookup.cpp @@ -1334,7 +1334,9 @@ class DecodedMetadataBuilder { using BuiltType = const Metadata *; using BuiltTypeDecl = const ContextDescriptor *; using BuiltProtocolDecl = ProtocolDescriptorRef; + using BuiltGenericSignature = const Metadata *; using BuiltSubstitution = std::pair; + using BuiltSubstitutionMap = llvm::ArrayRef; using BuiltGenericTypeParam = const Metadata *; BuiltType decodeMangledType(NodePointer node, @@ -1659,7 +1661,6 @@ class DecodedMetadataBuilder { } using BuiltSILBoxField = llvm::PointerIntPair; - using BuiltSubstitution = std::pair; struct BuiltLayoutConstraint { bool operator==(BuiltLayoutConstraint rhs) const { return true; } operator bool() const { return true; } From f76f1a7aea58b49d65b9e0b710e5378a5b08a9af Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Mon, 25 Apr 2022 17:02:43 -0700 Subject: [PATCH 05/13] Add a Hack Reconstitute the ExistentialType wrapper around a (parameterized) protocol type. The AST needs to be remodeled here before we can remove this. --- lib/IRGen/MetadataRequest.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/lib/IRGen/MetadataRequest.cpp b/lib/IRGen/MetadataRequest.cpp index 9deebdfc04492..abcd427bb65e9 100644 --- a/lib/IRGen/MetadataRequest.cpp +++ b/lib/IRGen/MetadataRequest.cpp @@ -280,8 +280,16 @@ usesExtendedExistentialMetadata(CanExistentialMetatypeType type) { // The only existential types that don't currently use ExistentialType // are Any and AnyObject, which don't use extended metadata. - if (usesExtendedExistentialMetadata(cur)) + if (usesExtendedExistentialMetadata(cur)) { + // HACK: The AST for an existential metatype of a (parameterized) protocol + // still directly wraps the existential type as its instance, which means + // we need to reconstitute the enclosing ExistentialType. + assert(cur->isExistentialType()); + if (!cur->is()) { + cur = ExistentialType::get(cur)->getCanonicalType(); + } return std::make_pair(cast(cur), depth); + } return None; } From fe6e280b30cd8aec2d54a08dac52a38dbd3b99bd Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Mon, 25 Apr 2022 17:04:01 -0700 Subject: [PATCH 06/13] Add a Utility to Read Extended Existential Type Shapes --- include/swift/Remote/MetadataReader.h | 66 ++++++++++++++++++++++++++- 1 file changed, 65 insertions(+), 1 deletion(-) diff --git a/include/swift/Remote/MetadataReader.h b/include/swift/Remote/MetadataReader.h index 4b430c2c250d0..d0f686e641b56 100644 --- a/include/swift/Remote/MetadataReader.h +++ b/include/swift/Remote/MetadataReader.h @@ -194,6 +194,10 @@ class MetadataReader { RemoteRef>; using OwnedContextDescriptorRef = MemoryReader::ReadBytesResult; + using ShapeRef = + RemoteRef>; + using OwnedShapeRef = MemoryReader::ReadBytesResult; + /// A reference to a context descriptor that may be in an unloaded image. class ParentContextDescriptorRef { bool IsResolved; @@ -263,6 +267,7 @@ class MetadataReader { return !isResolved() || getResolved(); } }; + /// A cache of read nominal type descriptors, keyed by the address of the /// nominal type descriptor. std::unordered_map @@ -270,6 +275,10 @@ class MetadataReader { using OwnedProtocolDescriptorRef = std::unique_ptr, delete_with_free>; + /// A cache of read extended existential shape metadata, keyed by the + /// address of the shape metadata. + std::unordered_map + ShapeCache; enum class IsaEncodingKind { /// We haven't checked yet. @@ -1011,7 +1020,62 @@ class MetadataReader { return ParentContextDescriptorRef( readContextDescriptor(address.getResolvedAddress().getAddressData())); } - + + ShapeRef + readShape(StoredPointer address) { + if (address == 0) + return nullptr; + + auto cached = ShapeCache.find(address); + if (cached != ShapeCache.end()) + return ShapeRef(address, + reinterpret_cast *>( + cached->second.get())); + + ExtendedExistentialTypeShapeFlags flags; + if (!Reader->readBytes(RemoteAddress(address), (uint8_t*)&flags, + sizeof(flags))) + return nullptr; + + // Read the size of the requirement signature. + uint64_t reqSigGenericSize = 0; + uint64_t genericHeaderSize = sizeof(GenericContextDescriptorHeader); + { + GenericContextDescriptorHeader header; + auto headerAddr = address + sizeof(flags); + + if (!Reader->readBytes(RemoteAddress(headerAddr), + (uint8_t*)&header, sizeof(header))) + return nullptr; + + reqSigGenericSize = reqSigGenericSize + + (header.NumParams + 3u & ~3u) + + header.NumRequirements + * sizeof(TargetGenericRequirementDescriptor); + } + uint64_t typeExprSize = flags.hasTypeExpression() ? sizeof(StoredPointer) : 0; + uint64_t suggestedVWSize = flags.hasSuggestedValueWitnesses() ? sizeof(StoredPointer) : 0; + + uint64_t size = sizeof(ExtendedExistentialTypeShapeFlags) + + sizeof(TargetRelativeDirectPointer) + + genericHeaderSize + typeExprSize + suggestedVWSize + + reqSigGenericSize; + if (size > MaxMetadataSize) + return nullptr; + auto readResult = Reader->readBytes(RemoteAddress(address), size); + if (!readResult) + return nullptr; + + auto descriptor = + reinterpret_cast *>( + readResult.get()); + + ShapeCache.insert( + std::make_pair(address, std::move(readResult))); + return ShapeRef(address, descriptor); + } + /// Given the address of a context descriptor, attempt to read it. ContextDescriptorRef readContextDescriptor(StoredPointer address) { From 61e5eee909b833e0725ba768a1ba485fb5e7eca1 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Mon, 25 Apr 2022 17:04:39 -0700 Subject: [PATCH 07/13] Read Runtime Generic Signatures --- include/swift/Remote/MetadataReader.h | 116 +++++++++++++++++++++++++- 1 file changed, 115 insertions(+), 1 deletion(-) diff --git a/include/swift/Remote/MetadataReader.h b/include/swift/Remote/MetadataReader.h index d0f686e641b56..0bb4cea7736f7 100644 --- a/include/swift/Remote/MetadataReader.h +++ b/include/swift/Remote/MetadataReader.h @@ -996,6 +996,119 @@ class MetadataReader { swift_unreachable("Unhandled MetadataKind in switch"); } + TypeLookupErrorOr + decodeRuntimeGenericSignature(ShapeRef contextRef, + const RuntimeGenericSignature &Sig) { + std::vector params; + for (unsigned sigIdx : indices(Sig.getParams())) { + auto param = + Builder.createGenericTypeParameterType(/*depth*/ 0, /*index*/ sigIdx); + if (!param) + return TypeLookupError("Failed to read generic parameter type in " + "runtime generic signature."); + params.push_back(param); + } + + std::vector reqs; + for (auto &req : Sig.getRequirements()) { + if (!req.hasKnownKind()) { + return TypeLookupError("unknown kind"); + } + + Demangler ldem; + auto lhsTypeNode = ldem.demangleType(req.getParam()); + if (!lhsTypeNode) { + return TypeLookupError("Failed to read subject type in requirement of " + "runtime generic signature."); + } + + BuiltType subjectType = decodeMangledType(lhsTypeNode).getType(); + if (!subjectType) + return TypeLookupError("Failed to read subject type in requirement of " + "runtime generic signature."); + + switch (req.Flags.getKind()) { + case GenericRequirementKind::SameType: { + Demangler rdem; + auto demangledConstraint = + demangle(RemoteRef(req.getMangledTypeName().data(), + req.getMangledTypeName().data()), + MangledNameKind::Type, rdem); + auto constraintType = decodeMangledType(demangledConstraint); + if (auto *error = constraintType.getError()) { + return *error; + } + + reqs.push_back(BuiltRequirement(RequirementKind::SameType, subjectType, + constraintType.getType())); + break; + } + case GenericRequirementKind::Protocol: { + /// Resolver to turn a protocol reference into a protocol declaration. + struct ProtocolReferenceResolver { + using Result = BuiltType; + + BuilderType &builder; + + BuiltType failure() const { return BuiltType(); } + + BuiltType swiftProtocol(Demangle::Node *node) { + auto decl = builder.createProtocolDecl(node); + if (!decl) + return failure(); + return builder.createProtocolTypeFromDecl(decl); + } + +#if SWIFT_OBJC_INTEROP + BuiltType objcProtocol(StringRef name) { + auto decl = builder.createObjCProtocolDecl(name.str()); + if (!decl) + return failure(); + return builder.createProtocolTypeFromDecl(decl); + } +#endif + } resolver{Builder}; + + Demangler dem; + auto protocolAddress = + resolveRelativeIndirectProtocol(contextRef, req.Protocol); + auto protocol = readProtocol(protocolAddress, dem, resolver); + if (!protocol) { + return TypeLookupError("Failed to read protocol type in conformance " + "requirement of runtime generic signature."); + } + + reqs.push_back(BuiltRequirement(RequirementKind::Conformance, + subjectType, protocol)); + break; + } + case GenericRequirementKind::BaseClass: { + Demangler rdem; + auto demangledConstraint = + demangle(RemoteRef(req.getMangledTypeName().data(), + req.getMangledTypeName().data()), + MangledNameKind::Type, rdem); + auto constraintType = decodeMangledType(demangledConstraint); + if (auto *error = constraintType.getError()) { + return *error; + } + + reqs.push_back(BuiltRequirement(RequirementKind::Superclass, + subjectType, constraintType.getType())); + break; + } + case GenericRequirementKind::SameConformance: + return TypeLookupError("Unexpected same conformance requirement in " + "runtime generic signature"); + case GenericRequirementKind::Layout: + return TypeLookupError( + "Unexpected layout requirement in runtime generic signature"); + } + } + + return Builder.createGenericSignature(params, reqs); + } + TypeLookupErrorOr readTypeFromMangledName(const char *MangledTypeName, size_t Length) { Demangle::Demangler Dem; @@ -2201,8 +2314,9 @@ class MetadataReader { /// Resolve a relative target protocol descriptor pointer, which uses /// the lowest bit to indicate an indirect vs. direct relative reference and /// the second lowest bit to indicate whether it is an Objective-C protocol. + template StoredPointer resolveRelativeIndirectProtocol( - ContextDescriptorRef descriptor, + RemoteRef descriptor, const RelativeTargetProtocolDescriptorPointer &protocol) { // Map the offset from within our local buffer to the remote address. auto distance = (intptr_t)&protocol - (intptr_t)descriptor.getLocalBuffer(); From 9918050dface2d455b48a2aac4af7cd347ef1158 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Mon, 25 Apr 2022 17:09:45 -0700 Subject: [PATCH 08/13] [Remote Mirrors] Support Extended Existential Type Metadata Teach Remote Mirrors to read extended existential type metadata. --- include/swift/ABI/GenericContext.h | 21 ++++- include/swift/Remote/MetadataReader.h | 83 ++++++++++++++++++- lib/RemoteAST/RemoteAST.cpp | 13 --- .../SwiftRemoteMirror/SwiftRemoteMirror.cpp | 13 --- stdlib/public/runtime/Metadata.cpp | 6 -- stdlib/public/runtime/ReflectionMirror.cpp | 2 + .../parameterized_existentials.swift | 81 ++++++++++++++++++ 7 files changed, 185 insertions(+), 34 deletions(-) create mode 100644 test/RemoteAST/parameterized_existentials.swift diff --git a/include/swift/ABI/GenericContext.h b/include/swift/ABI/GenericContext.h index 82f4870641099..6e23847ed93b9 100644 --- a/include/swift/ABI/GenericContext.h +++ b/include/swift/ABI/GenericContext.h @@ -191,8 +191,27 @@ using GenericRequirementDescriptor = 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(); +const GenericParamDescriptor *targetImplicitGenericParamDescriptors() { + return externalTargetImplicitGenericParamDescriptors(); +} +template <> +inline const GenericParamDescriptor *targetImplicitGenericParamDescriptors() { + return ImplicitGenericParamDescriptors; +} /// A runtime description of a generic signature. template diff --git a/include/swift/Remote/MetadataReader.h b/include/swift/Remote/MetadataReader.h index 0bb4cea7736f7..f392af0fecfd0 100644 --- a/include/swift/Remote/MetadataReader.h +++ b/include/swift/Remote/MetadataReader.h @@ -929,6 +929,85 @@ class MetadataReader { TypeCache[MetadataAddress] = BuiltExist; return BuiltExist; } + case MetadataKind::ExtendedExistential: { + auto Exist = cast>(Meta); + + // Read the shape for this existential. + StoredPointer shapeAddress = stripSignedPointer(Exist->Shape); + ShapeRef Shape = readShape(shapeAddress); + if (!Shape) + return BuiltType(); + + const unsigned shapeArgumentCount + = Shape->getGenSigArgumentLayoutSizeInWords(); + // Pull out the arguments to the generalization signature. + assert(Shape->hasGeneralizationSignature()); + std::vector builtArgs; + for (unsigned i = 0; i < shapeArgumentCount; ++i) { + auto remoteArg = Exist->getGeneralizationArguments()[i]; + auto builtArg = readTypeFromMetadata(remoteArg); + if (!builtArg) + return BuiltType(); + builtArgs.push_back(builtArg); + } + + // Pull out the existential type from the mangled type name. + Demangler dem; + auto mangledExistentialAddr = + resolveRelativeField(Shape, Shape->ExistentialType); + auto node = readMangledName(RemoteAddress(mangledExistentialAddr), + MangledNameKind::Type, dem); + if (!node) + return BuiltType(); + + BuiltType builtProto = decodeMangledType(node).getType(); + if (!builtProto) + return BuiltType(); + + // Build up a substitution map for the generalized signature. + BuiltGenericSignature sig = + decodeRuntimeGenericSignature(Shape, + Shape->getGeneralizationSignature()) + .getType(); + if (!sig) + return BuiltType(); + + BuiltSubstitutionMap subst = + Builder.createSubstitutionMap(sig, builtArgs); + if (subst.empty()) + return BuiltType(); + + builtProto = Builder.subst(builtProto, subst); + if (!builtProto) + return BuiltType(); + + // Read the type expression to build up any remaining layers of + // existential metatype. + if (Shape->Flags.hasTypeExpression()) { + Demangler dem; + + // Read the mangled name. + auto mangledContextName = Shape->getTypeExpression(); + auto mangledNameAddress = + resolveRelativeField(Shape, mangledContextName->name); + auto node = readMangledName(RemoteAddress(mangledNameAddress), + MangledNameKind::Type, dem); + if (!node) + return BuiltType(); + + while (node->getKind() == Demangle::Node::Kind::Type && + node->getNumChildren() && + node->getChild(0)->getKind() == Demangle::Node::Kind::Metatype && + node->getChild(0)->getNumChildren()) { + builtProto = Builder.createExistentialMetatypeType(builtProto); + node = node->getChild(0)->getChild(0); + } + } + + TypeCache[MetadataAddress] = builtProto; + return builtProto; + } + case MetadataKind::Metatype: { auto Metatype = cast>(Meta); auto Instance = readTypeFromMetadata(Metatype->InstanceType); @@ -1044,7 +1123,7 @@ class MetadataReader { break; } case GenericRequirementKind::Protocol: { - /// Resolver to turn a protocol reference into a protocol declaration. + /// Resolver to turn a protocol reference into an existential type. struct ProtocolReferenceResolver { using Result = BuiltType; @@ -1895,6 +1974,8 @@ class MetadataReader { } case MetadataKind::ExistentialMetatype: return _readMetadata(address); + case MetadataKind::ExtendedExistential: + return _readMetadata(address); case MetadataKind::ForeignClass: return _readMetadata(address); case MetadataKind::Function: { diff --git a/lib/RemoteAST/RemoteAST.cpp b/lib/RemoteAST/RemoteAST.cpp index bd6cca2d9e79d..cd8c2c301920f 100644 --- a/lib/RemoteAST/RemoteAST.cpp +++ b/lib/RemoteAST/RemoteAST.cpp @@ -51,19 +51,6 @@ using namespace swift::remoteAST; using irgen::Alignment; using irgen::Size; -template -const GenericParamDescriptor *swift::targetImplicitGenericParamDescriptors() { - 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; -} - static inline RemoteAddress operator+(RemoteAddress address, Size offset) { return RemoteAddress(address.getAddressData() + offset.getValue()); } diff --git a/stdlib/public/SwiftRemoteMirror/SwiftRemoteMirror.cpp b/stdlib/public/SwiftRemoteMirror/SwiftRemoteMirror.cpp index c8a294a35c892..df305be8cc488 100644 --- a/stdlib/public/SwiftRemoteMirror/SwiftRemoteMirror.cpp +++ b/stdlib/public/SwiftRemoteMirror/SwiftRemoteMirror.cpp @@ -43,19 +43,6 @@ using Runtime = External>>; #endif using NativeReflectionContext = swift::reflection::ReflectionContext; -template -const GenericParamDescriptor *swift::targetImplicitGenericParamDescriptors() { - 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; -} - struct SwiftReflectionContext { NativeReflectionContext *nativeContext; std::vector> freeFuncs; diff --git a/stdlib/public/runtime/Metadata.cpp b/stdlib/public/runtime/Metadata.cpp index 60a8fe3d09802..b6d6d93d34fa6 100644 --- a/stdlib/public/runtime/Metadata.cpp +++ b/stdlib/public/runtime/Metadata.cpp @@ -86,12 +86,6 @@ swift::ImplicitGenericParamDescriptors[MaxNumImplicitGenericParamDescriptors] = }; static_assert(MaxNumImplicitGenericParamDescriptors == 64, "length mismatch"); -template <> -const GenericParamDescriptor * -swift::targetImplicitGenericParamDescriptors() { - return ImplicitGenericParamDescriptors; -} - static ClassMetadata * _swift_relocateClassMetadata(const ClassDescriptor *description, const ResilientClassMetadataPattern *pattern); diff --git a/stdlib/public/runtime/ReflectionMirror.cpp b/stdlib/public/runtime/ReflectionMirror.cpp index c3db12460e431..0ebf4235ef802 100644 --- a/stdlib/public/runtime/ReflectionMirror.cpp +++ b/stdlib/public/runtime/ReflectionMirror.cpp @@ -1076,6 +1076,8 @@ const char *swift_OpaqueSummary(const Metadata *T) { return "(Heap Generic Local Variable)"; case MetadataKind::ErrorObject: return "(ErrorType Object)"; + case MetadataKind::ExtendedExistential: + return "(Extended Existential)"; default: return "(Unknown)"; } diff --git a/test/RemoteAST/parameterized_existentials.swift b/test/RemoteAST/parameterized_existentials.swift new file mode 100644 index 0000000000000..190a7406cc355 --- /dev/null +++ b/test/RemoteAST/parameterized_existentials.swift @@ -0,0 +1,81 @@ +// RUN: %target-swift-remoteast-test -enable-parameterized-existential-types %s | %FileCheck %s + +// REQUIRES: swift-remoteast-test + +@_silgen_name("printDynamicTypeAndAddressForExistential") +func printDynamicTypeAndAddressForExistential(_: T) + +@_silgen_name("stopRemoteAST") +func stopRemoteAST() + +protocol Paddock { + associatedtype Animal +} + +struct Chicken {} +struct Coop: Paddock { + typealias Animal = Chicken +} + +struct Pig {} +struct Pen: Paddock { + typealias Animal = Pig +} + +struct Field: Paddock {} + +protocol SharedYard { + associatedtype Animal1 + associatedtype Animal2 + associatedtype Animal3 + associatedtype Animal4 +} + +class Lea: SharedYard { + typealias Animal1 = Chicken + typealias Animal2 = Pig + typealias Animal3 = Chicken + typealias Animal4 = Pig + + init() {} +} + +let coop = Coop() +// CHECK: Coop +printDynamicTypeAndAddressForExistential(coop as any Paddock) + +// CHECK-NEXT: Coop +printDynamicTypeAndAddressForExistential(coop as any Paddock) + +// CHECK-NEXT: Coop.Type +printDynamicTypeAndAddressForExistential(Coop.self as (any Paddock.Type)) + +// CHECK-NEXT: Coop.Type.Type.Type.Type +printDynamicTypeAndAddressForExistential(Coop.Type.Type.Type.self as (any Paddock.Type.Type.Type.Type)) + +let pen = Pen() +// CHECK-NEXT: Pen +printDynamicTypeAndAddressForExistential(pen as any Paddock) + +// CHECK-NEXT: Pen +printDynamicTypeAndAddressForExistential(pen as any Paddock) + +let lea = Lea() +// CHECK-NEXT: Lea +printDynamicTypeAndAddressForExistential(lea as any SharedYard) + +// CHECK-NEXT: Lea +printDynamicTypeAndAddressForExistential(lea as any SharedYard) + + +func freeRange(_ x: Animal.Type) { + printDynamicTypeAndAddressForExistential(Field() as any Paddock) +} + +// CHECK-NEXT: Field +freeRange(Chicken.self) +// CHECK-NEXT: Field +freeRange(Pig.self) + + +stopRemoteAST() From 368cfa94c0e340257370e8421631ef27a1f86a18 Mon Sep 17 00:00:00 2001 From: Mike Ash Date: Thu, 28 Apr 2022 18:04:38 -0400 Subject: [PATCH 09/13] [RemoteMirror] Add bounds checking to BitMask operations. If we encounter any multi-paylaod enum descriptors with bad data, we can end up writing off the end of the bitmask allocation, causing heap corruption. Add range checks to let us fail gracefully instead. rdar://91423283 --- stdlib/public/Reflection/TypeLowering.cpp | 79 ++++++++++++++++++++--- 1 file changed, 69 insertions(+), 10 deletions(-) diff --git a/stdlib/public/Reflection/TypeLowering.cpp b/stdlib/public/Reflection/TypeLowering.cpp index ba6093a0f0b87..742a398300c39 100644 --- a/stdlib/public/Reflection/TypeLowering.cpp +++ b/stdlib/public/Reflection/TypeLowering.cpp @@ -20,6 +20,7 @@ #if SWIFT_ENABLE_REFLECTION +#include "llvm/Support/MathExtras.h" #include "swift/ABI/Enum.h" #include "swift/ABI/MetadataValues.h" #include "swift/Reflection/TypeLowering.h" @@ -645,6 +646,8 @@ class SimpleMultiPayloadEnumTypeInfo: public EnumTypeInfo { // A variable-length bitmap used to track "spare bits" for general multi-payload // enums. class BitMask { + static constexpr unsigned maxSize = 128 * 1024 * 1024; // 128MB + unsigned size; // Size of mask in bytes uint8_t *mask; public: @@ -654,18 +657,72 @@ class BitMask { // Construct a bitmask of the appropriate number of bytes // initialized to all bits set BitMask(unsigned sizeInBytes): size(sizeInBytes) { - assert(sizeInBytes < std::numeric_limits::max()); + // Gracefully fail by constructing an empty mask if we exceed the size + // limit. + if (size > maxSize) { + size = 0; + mask = nullptr; + return; + } + mask = (uint8_t *)malloc(size); + + if (!mask) { + // Malloc might fail if size is large due to some bad data. Assert in + // asserts builds, and fail gracefully in non-asserts builds by + // constructing an empty BitMask. + assert(false && "Failed to allocate BitMask"); + size = 0; + return; + } + memset(mask, 0xff, size); } // Construct a bitmask of the appropriate number of bytes // initialized with bits from the specified buffer - BitMask(unsigned sizeInBytes, const uint8_t *initialValue, unsigned initialValueBytes, unsigned offset) - : size(sizeInBytes) - { - assert(sizeInBytes < std::numeric_limits::max()); - assert(initialValueBytes + offset <= sizeInBytes); + BitMask(unsigned sizeInBytes, const uint8_t *initialValue, + unsigned initialValueBytes, unsigned offset) + : size(sizeInBytes) { + // Gracefully fail by constructing an empty mask if we exceed the size + // limit. + if (size > maxSize) { + size = 0; + mask = nullptr; + return; + } + + // Bad data could cause the initial value location to be off the end of our + // size. If initialValueBytes + offset is beyond sizeInBytes (or overflows), + // assert in asserts builds, and fail gracefully in non-asserts builds by + // constructing an empty BitMask. + bool overflowed = false; + unsigned initialValueEnd = + llvm::SaturatingAdd(initialValueBytes, offset, &overflowed); + if (overflowed) { + assert(false && "initialValueBytes + offset overflowed"); + size = 0; + mask = nullptr; + return; + } + assert(initialValueEnd <= sizeInBytes); + if (initialValueEnd > size) { + assert(false && "initialValueBytes + offset is greater than size"); + size = 0; + mask = nullptr; + return; + } + mask = (uint8_t *)calloc(1, size); + + if (!mask) { + // Malloc might fail if size is large due to some bad data. Assert in + // asserts builds, and fail gracefully in non-asserts builds by + // constructing an empty BitMask. + assert(false && "Failed to allocate BitMask"); + size = 0; + return; + } + memcpy(mask + offset, initialValue, initialValueBytes); } // Move constructor moves ownership and zeros the src @@ -864,10 +921,12 @@ class BitMask { void andNotMask(void *maskData, unsigned len, unsigned offset) { assert(offset < size); - unsigned common = std::min(len, size - offset); - uint8_t *maskBytes = (uint8_t *)maskData; - for (unsigned i = 0; i < common; ++i) { - mask[i + offset] &= ~maskBytes[i]; + if (offset < size) { + unsigned common = std::min(len, size - offset); + uint8_t *maskBytes = (uint8_t *)maskData; + for (unsigned i = 0; i < common; ++i) { + mask[i + offset] &= ~maskBytes[i]; + } } } }; From f3bb988ea0f5edc5fe4d25d8e4d68702ac08ec1e Mon Sep 17 00:00:00 2001 From: zoecarver Date: Fri, 29 Apr 2022 10:17:59 -0700 Subject: [PATCH 10/13] [nfc] [cxx-interop] Disable `ReadAccessor` benchmark. --- benchmark/utils/main.swift | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/benchmark/utils/main.swift b/benchmark/utils/main.swift index 9f634c3755ea2..9470afc27d258 100644 --- a/benchmark/utils/main.swift +++ b/benchmark/utils/main.swift @@ -152,7 +152,7 @@ import RangeAssignment import RangeIteration import RangeOverlaps import RangeReplaceableCollectionPlusDefault -import ReadAccessor +//import ReadAccessor import RecursiveOwnedParameter import ReduceInto import RemoveWhere @@ -333,7 +333,8 @@ register(RangeAssignment.benchmarks) register(RangeIteration.benchmarks) register(RangeOverlaps.benchmarks) register(RangeReplaceableCollectionPlusDefault.benchmarks) -register(ReadAccessor.benchmarks) +// TODO: rdar://92120528 +//register(ReadAccessor.benchmarks) register(RecursiveOwnedParameter.benchmarks) register(ReduceInto.benchmarks) register(RemoveWhere.benchmarks) From 01e0e0a4ab2bb45abd71ec168467de8ef3657051 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Fri, 29 Apr 2022 10:52:02 -0700 Subject: [PATCH 11/13] Gate Clock Runtime Test on Current Runtimes The back deployment runtime does not contain the symbols necessary to execute this test. Mark it unsupported. --- test/Concurrency/Runtime/clock.swift | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/test/Concurrency/Runtime/clock.swift b/test/Concurrency/Runtime/clock.swift index a2371dec932e7..40428f150606d 100644 --- a/test/Concurrency/Runtime/clock.swift +++ b/test/Concurrency/Runtime/clock.swift @@ -4,6 +4,10 @@ // REQUIRES: executable_test // REQUIRES: concurrency_runtime +// Test requires _swift_task_enterThreadLocalContext which is not available +// in the back deployment runtime. +// UNSUPPORTED: back_deployment_runtime + import _Concurrency import StdlibUnittest @@ -104,4 +108,4 @@ var tests = TestSuite("Time") await runAllTestsAsync() } -} \ No newline at end of file +} From 61a352486e5f0394b5338ef6b3d03ceb8bfdee13 Mon Sep 17 00:00:00 2001 From: Philip Turner Date: Tue, 26 Apr 2022 13:45:27 -0400 Subject: [PATCH 12/13] Create sr15884-generic-signature-builder-keypath-iterable.swift --- ...c-signature-builder-keypath-iterable.swift | 47 +++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 test/AutoDiff/compiler_crashers_fixed/sr15884-generic-signature-builder-keypath-iterable.swift diff --git a/test/AutoDiff/compiler_crashers_fixed/sr15884-generic-signature-builder-keypath-iterable.swift b/test/AutoDiff/compiler_crashers_fixed/sr15884-generic-signature-builder-keypath-iterable.swift new file mode 100644 index 0000000000000..a3e8ba0421819 --- /dev/null +++ b/test/AutoDiff/compiler_crashers_fixed/sr15884-generic-signature-builder-keypath-iterable.swift @@ -0,0 +1,47 @@ +// RUN: %target-swift-frontend -emit-sil -verify %s + +// SR-15884: Crash while compiling Swift for TensorFlow. This was caused by a +// bug in GenericSignatureBuilder, similar to one involving `CaseIterable`. In +// this reproducer, `KeyPathIterabe` is similar enough to `CaseIterable` to +// cause the GSB crash. It was fixed by RequirementMachine abstract signatures. + +import _Differentiation +@_spi(Reflection) import Swift + +struct RNNCellInput: Differentiable {} +struct RNNCellOutput: Differentiable {} + +protocol Layer: Differentiable { + associatedtype Input + associatedtype Output: Differentiable + + @differentiable(reverse) + func callAsFunction(_ input: Input) -> Output +} + +public protocol KeyPathIterable { + associatedtype AllKeyPaths: Sequence + where AllKeyPaths.Element == PartialKeyPath +} + +protocol RecurrentLayerCell: Layer, KeyPathIterable +where + Input == RNNCellInput, + Output == RNNCellOutput +{ + associatedtype TimeStepInput + associatedtype TimeStepOutput: Differentiable +} + +struct RecurrentLayer: Layer { + typealias Input = Cell.TimeStepInput + typealias Output = Cell.TimeStepOutput + + var cell: Cell + + @differentiable(reverse) + func callAsFunction(_ inputs: Cell.TimeStepInput) -> Cell.TimeStepOutput { + // expected-warning @+1 {{function call causes an infinite recursion}} + return self(inputs) + } +} From c30333a220db00fad53416435aed39a5a5207a0c Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Fri, 29 Apr 2022 18:30:59 -0700 Subject: [PATCH 13/13] Remove Needless Template Dependent Access There's no ambiguity here that can be resolved so just drop it. --- include/swift/Reflection/TypeRef.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/swift/Reflection/TypeRef.h b/include/swift/Reflection/TypeRef.h index ef4ce80a0cd64..3227b91ac80ae 100644 --- a/include/swift/Reflection/TypeRef.h +++ b/include/swift/Reflection/TypeRef.h @@ -760,7 +760,7 @@ class GenericSignatureRef final { create(Allocator &A, llvm::ArrayRef Params, llvm::ArrayRef Requirements) { - return A.template makeGenericSignatureRef(Params, Requirements); + return A.makeGenericSignatureRef(Params, Requirements); } const llvm::ArrayRef getParams() const {