diff --git a/CHANGELOG.md b/CHANGELOG.md index 5ae2e3983d2ae..bb87a9a928f2e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,17 @@ _**Note:** This is in reverse chronological order, so newer entries are added to ## Swift 5.7 +* [SE-0340][]: + + It is now possible to make declarations unavailable from use in asynchronous + contexts with the `@available(*, noasync)` attribute. + + This is to protect the consumers of an API against undefined behavior that can + occur when the API uses thread-local storage, or encourages using thread-local + storage, across suspension points, or protect developers against holding locks + across suspension points which may lead to undefined behavior, priority + inversions, or deadlocks. + * [SE-0343][]: Top-level scripts support asynchronous calls. @@ -9083,6 +9094,7 @@ Swift 1.0 [SE-0341]: [SE-0336]: [SE-0343]: +[SE-0340]: [SR-75]: [SR-106]: diff --git a/SwiftCompilerSources/Sources/SIL/Instruction.swift b/SwiftCompilerSources/Sources/SIL/Instruction.swift index a1cc3b265e92d..f3b6d56d3805b 100644 --- a/SwiftCompilerSources/Sources/SIL/Instruction.swift +++ b/SwiftCompilerSources/Sources/SIL/Instruction.swift @@ -408,12 +408,6 @@ class UnconditionalCheckedCastInst : SingleValueInstruction, UnaryInstruction { public override var mayTrap: Bool { true } } -final public -class UnconditionalCheckedCastValueInst : SingleValueInstruction, - UnaryInstruction { - public override var mayTrap: Bool { true } -} - final public class ConvertFunctionInst : SingleValueInstruction, UnaryInstruction {} @@ -624,7 +618,3 @@ final public class CheckedCastBranchInst : TermInst, UnaryInstruction { final public class CheckedCastAddrBranchInst : TermInst, UnaryInstruction { } - -final public class CheckedCastValueBranchInst : TermInst, UnaryInstruction { -} - diff --git a/SwiftCompilerSources/Sources/SIL/Registration.swift b/SwiftCompilerSources/Sources/SIL/Registration.swift index c61148cfb5f17..a07f2d0027b66 100644 --- a/SwiftCompilerSources/Sources/SIL/Registration.swift +++ b/SwiftCompilerSources/Sources/SIL/Registration.swift @@ -92,7 +92,6 @@ public func registerSILClasses() { register(RefElementAddrInst.self) register(RefTailAddrInst.self) register(UnconditionalCheckedCastInst.self) - register(UnconditionalCheckedCastValueInst.self) register(ConvertFunctionInst.self) register(ThinToThickFunctionInst.self) register(ObjCExistentialMetatypeToObjectInst.self) @@ -140,5 +139,4 @@ public func registerSILClasses() { register(AwaitAsyncContinuationInst.self) register(CheckedCastBranchInst.self) register(CheckedCastAddrBranchInst.self) - register(CheckedCastValueBranchInst.self) } diff --git a/docs/Diagnostics.md b/docs/Diagnostics.md index 87137fdcf5680..9f8f0439e3d93 100644 --- a/docs/Diagnostics.md +++ b/docs/Diagnostics.md @@ -141,6 +141,8 @@ If you run into any issues or have questions while following the steps above, fe (This section is specific to the Swift compiler's diagnostic engine.) If the `-verify` frontend flag is used, the Swift compiler will check emitted diagnostics against specially formatted comments in the source. This feature is used extensively throughout the test suite to ensure diagnostics are emitted with the correct message and source location. + +`-verify` parses all ordinary source files passed as inputs to the compiler to look for expectation comments. If you'd like to check for diagnostics in additional files, like swiftinterfaces or even Objective-C headers, specify them with `-verify-additional-file `. By default, `-verify` considers any diagnostic at `:0` (that is, any diagnostic emitted with an invalid source location) to be unexpected; you can disable this by passing `-verify-ignore-unknown`. An expected diagnostic is denoted by a comment which begins with `expected-error`, `expected-warning`, `expected-note`, or `expected-remark`. It is followed by: @@ -150,6 +152,14 @@ An expected diagnostic is denoted by a comment which begins with `expected-error - (Required) The expected error message. The message should be enclosed in double curly braces and should not include the `error:`/`warning:`/`note:`/`remark:` prefix. For example, `// expected-error {{invalid redeclaration of 'y'}}` would match an error with that message on the same line. The expected message does not need to match the emitted message verbatim. As long as the expected message is a substring of the original message, they will match. -- (Optional) Expected fix-its. These are each enclosed in double curly braces and appear after the expected message. An expected fix-it consists of a column range followed by the text it's expected to be replaced with. For example, `let r : Int i = j // expected-error{{consecutive statements}} {{12-12=;}}` will match a fix-it attached to the consecutive statements error which inserts a semicolon at column 12, just after the 't' in 'Int'. The special {{none}} specifier is also supported, which will cause the diagnostic match to fail if unexpected fix-its are produced. +- (Optional) Expected fix-its. These are each enclosed in double curly braces and appear after the expected message. An expected fix-it consists of a column range followed by the text it's expected to be replaced with. For example, `let r : Int i = j // expected-error{{consecutive statements}} {{12-12=;}}` will match a fix-it attached to the consecutive statements error which inserts a semicolon at column 12, just after the 't' in 'Int'. + + * Insertions are represented by identical start and end locations: `{{3-3=@objc }}`. Deletions are represented by empty replacement text: `{{3-9=}}`. + + * Line offsets are also permitted; for instance, `{{-1:12-+1:42=}}` would specify a fix-it that deleted everything between column 12 on the previous line and column 42 on the next line. (If the sign is omitted, it specifies an absolute line number, not an offset.) + + * By default, the verifier ignores any fix-its that are *not* expected; the special `{{none}}` specifier tells it to verify that the diagnostic it's attached to has *only* the fix-its specified and no others. + + * If two (or more) expected fix-its are juxtaposed with nothing (or whitespace) between them, then both must be present for the verifier to match. If two (or more) expected fix-its have `||` between them, then one of them must be present for the verifier to match. `||` binds more tightly than juxtaposition: `{{1-1=a}} {{2-2=b}} || {{2-2=c}} {{3-3=d}} {{none}}` will only match if there is either a set of three fix-its that insert `a`, `b`, and `d`, or a set of three fix-its that insert `a`, `c`, and `d`. (Without the `{{none}}`, it would also permit all four fix-its, but only because one of the four would be unmatched and ignored.) - (Optional) Expected educational notes. These appear as a comma separated list after the expected message, enclosed in double curly braces and prefixed by 'educational-notes='. For example, `{{educational-notes=some-note,some-other-note}}` will verify the educational notes with filenames `some-note` and `some-other-note` appear. Do not include the file extension when specifying note names. diff --git a/docs/SIL.rst b/docs/SIL.rst index abc26102a908c..722dbc63ea7ce 100644 --- a/docs/SIL.rst +++ b/docs/SIL.rst @@ -2193,6 +2193,26 @@ parts:: return %1 : $Klass } +Forwarding Address-Only Values +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Address-only values are potentially unmovable when borrowed. This +means that they cannot be forwarded with guaranteed ownership unless +the forwarded value has the same representation as in the original +value and can reuse the same storage. Non-destructive projection is +allowed, such as `struct_extract`. Aggregation, such as `struct`, and +destructive disaggregation, such as `switch_enum` is not allowed. This +is an invariant for OSSA with opaque SIL values for these reasons: + +1. To avoid implicit semantic copies. For move-only values, this allows +complete diagnostics. And in general, it makes it impossible for SIL +passes to "accidentally" create copies. + +2. To reuse borrowed storage. This allows the optimizer to share the same +storage for multiple exclusive reads of the same variable, avoiding +copies. It may also be necessary to support native Swift atomics, which +will be unmovable-when-borrowed. + Borrowed Object based Safe Interior Pointers ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/include/swift/ABI/GenericContext.h b/include/swift/ABI/GenericContext.h new file mode 100644 index 0000000000000..2d64e1e3e415a --- /dev/null +++ b/include/swift/ABI/GenericContext.h @@ -0,0 +1,380 @@ +//===--- 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/TrailingObjects.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 unified + /// unified with a different parameter or an associated 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 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 + /// 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 + /// order as the requirements, for those requirements which satisfy + /// hasKeyArgument()). + uint16_t NumKeyArguments; + + /// In principle, 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, this section is + /// unused, and this field is always zero. It can be repurposed + /// as long as it remains zero in code which must be compatible + /// with existing Swift runtimes. + uint16_t NumExtraArguments; + + uint32_t getNumArguments() const { + return NumKeyArguments + NumExtraArguments; + } + + /// 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; + } +}; +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; + }; + + 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; + } + + /// Retrieve the right-hand type for a SameType or BaseClass requirement. + llvm::StringRef getMangledTypeName() const { + assert(getKind() == GenericRequirementKind::SameType || + getKind() == GenericRequirementKind::BaseClass); + return swift::Demangle::makeSymbolicMangledNameStringRef(Type.get()); + } + + /// Retrieve the protocol conformance record for a SameConformance + /// requirement. + const TargetProtocolConformanceDescriptor *getConformance() const { + assert(getKind() == GenericRequirementKind::SameConformance); + return Conformance; + } + + /// Retrieve the layout constraint. + GenericRequirementLayoutKind getLayout() const { + assert(getKind() == GenericRequirementKind::Layout); + return Layout; + } + + /// Determine whether this generic requirement has a known kind. + /// + /// \returns \c false for any future generic requirement kinds. + bool hasKnownKind() const { + switch (getKind()) { + case GenericRequirementKind::BaseClass: + case GenericRequirementKind::Layout: + case GenericRequirementKind::Protocol: + case GenericRequirementKind::SameConformance: + case GenericRequirementKind::SameType: + return true; + } + + return false; + } +}; +using GenericRequirementDescriptor = + TargetGenericRequirementDescriptor; + +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::makeArrayRef(this->template getTrailingObjects(), + Flags.getNumGenericParameterLevels()); + } + + /// Retrieve the generic parameters descriptors. + llvm::ArrayRef getGenericParameters() const { + return llvm::makeArrayRef( + this->template getTrailingObjects(), + getGenericParameterCounts().back()); + } + + /// Retrieve the generic requirements. + llvm::ArrayRef getGenericRequirements() const { + return llvm::makeArrayRef( + 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, + FollowingTrailingObjects...> +{ +protected: + using Self = TargetSelf; + using GenericContextHeaderType = TargetGenericContextHeaderType; + using GenericRequirementDescriptor = + TargetGenericRequirementDescriptor; + + 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(); + } + + 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}; + } + + /// Return the amount of space that the generic arguments take up in + /// metadata of this type. + StoredSize getGenericArgumentsStorageSize() const { + return StoredSize(getGenericContextHeader().getNumArguments()) + * sizeof(StoredPointer); + } + +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; + } + +#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 diff --git a/include/swift/ABI/Metadata.h b/include/swift/ABI/Metadata.h index 711e2eddac80b..0ff5b80a3810f 100644 --- a/include/swift/ABI/Metadata.h +++ b/include/swift/ABI/Metadata.h @@ -18,10 +18,6 @@ #define SWIFT_ABI_METADATA_H #include -#include -#include -#include -#include #include #include #include @@ -31,9 +27,13 @@ #include "swift/Strings.h" #include "swift/Runtime/Config.h" #include "swift/Runtime/Once.h" +#include "swift/ABI/GenericContext.h" +#include "swift/ABI/MetadataRef.h" #include "swift/ABI/MetadataValues.h" #include "swift/ABI/System.h" +#include "swift/ABI/TargetLayout.h" #include "swift/ABI/TrailingObjects.h" +#include "swift/ABI/ValueWitnessTable.h" #include "swift/Basic/Malloc.h" #include "swift/Basic/FlaggedPointer.h" #include "swift/Basic/RelativePointer.h" @@ -41,9 +41,6 @@ #include "swift/Demangling/ManglingMacros.h" #include "swift/Basic/Unreachable.h" #include "../../../stdlib/public/SwiftShims/HeapObject.h" -#if SWIFT_OBJC_INTEROP -#include -#endif #include "llvm/ADT/STLExtras.h" #include "llvm/Support/Casting.h" @@ -65,186 +62,11 @@ template class TargetValueTypeDescriptor; template class TargetEnumDescriptor; template class TargetStructDescriptor; template struct TargetGenericMetadataPattern; - -template -struct RuntimeTarget; - -template <> -struct RuntimeTarget<4> { - using StoredPointer = uint32_t; - // To avoid implicit conversions from StoredSignedPointer to StoredPointer. - using StoredSignedPointer = struct { - uint32_t SignedValue; - }; - using StoredSize = uint32_t; - using StoredPointerDifference = int32_t; - static constexpr size_t PointerSize = 4; -}; - -template <> -struct RuntimeTarget<8> { - using StoredPointer = uint64_t; - // To avoid implicit conversions from StoredSignedPointer to StoredPointer. - using StoredSignedPointer = struct { - uint64_t SignedValue; - }; - using StoredSize = uint64_t; - using StoredPointerDifference = int64_t; - static constexpr size_t PointerSize = 8; -}; - -namespace reflection { - class FieldDescriptor; -} - -/// In-process native runtime target. -/// -/// For interactions in the runtime, this should be the equivalent of working -/// with a plain old pointer type. -struct InProcess { - static constexpr size_t PointerSize = sizeof(uintptr_t); - using StoredPointer = uintptr_t; - using StoredSignedPointer = uintptr_t; - using StoredSize = size_t; - using StoredPointerDifference = ptrdiff_t; - -#if SWIFT_OBJC_INTEROP - static constexpr bool ObjCInterop = true; - template - using TargetAnyClassMetadata = TargetAnyClassMetadataObjCInterop; -#else - static constexpr bool ObjCInterop = false; - template - using TargetAnyClassMetadata = TargetAnyClassMetadata; -#endif - template - using TargetClassMetadata = TargetClassMetadata>; - - static_assert(sizeof(StoredSize) == sizeof(StoredPointerDifference), - "target uses differently-sized size_t and ptrdiff_t"); - - template - using Pointer = T*; - - template - using SignedPointer = T; - - template - using FarRelativeDirectPointer = FarRelativeDirectPointer; - - template - using RelativeIndirectablePointer = - RelativeIndirectablePointer; - - template - using RelativeDirectPointer = RelativeDirectPointer; -}; - -/// Represents a pointer in another address space. -/// -/// This type should not have * or -> operators -- you must as a memory reader -/// to read the data at the stored address on your behalf. -template -struct ExternalPointer { - using StoredPointer = typename Runtime::StoredPointer; - StoredPointer PointerValue; -}; - -template struct WithObjCInterop { - using StoredPointer = typename Runtime::StoredPointer; - using StoredSignedPointer = typename Runtime::StoredSignedPointer; - using StoredSize = typename Runtime::StoredSize; - using StoredPointerDifference = typename Runtime::StoredPointerDifference; - static constexpr size_t PointerSize = Runtime::PointerSize; - static constexpr bool ObjCInterop = true; - template - using TargetAnyClassMetadata = TargetAnyClassMetadataObjCInterop; -}; - -template struct NoObjCInterop { - using StoredPointer = typename Runtime::StoredPointer; - using StoredSignedPointer = typename Runtime::StoredSignedPointer; - using StoredSize = typename Runtime::StoredSize; - using StoredPointerDifference = typename Runtime::StoredPointerDifference; - static constexpr size_t PointerSize = Runtime::PointerSize; - static constexpr bool ObjCInterop = false; - template - using TargetAnyClassMetadata = TargetAnyClassMetadata; -}; - -/// An external process's runtime target, which may be a different architecture, -/// and may or may not have Objective-C interoperability. -template -struct External { - using StoredPointer = typename Runtime::StoredPointer; - using StoredSignedPointer = typename Runtime::StoredSignedPointer; - using StoredSize = typename Runtime::StoredSize; - using StoredPointerDifference = typename Runtime::StoredPointerDifference; - template - using TargetAnyClassMetadata = - typename Runtime::template TargetAnyClassMetadata; - template - using TargetClassMetadata = TargetClassMetadata>; - - static constexpr size_t PointerSize = Runtime::PointerSize; - static constexpr bool ObjCInterop = Runtime::ObjCInterop; - const StoredPointer PointerValue; - - template - using Pointer = StoredPointer; - - template - using SignedPointer = StoredSignedPointer; - - template - using FarRelativeDirectPointer = StoredPointer; - - template - using RelativeIndirectablePointer = int32_t; - - template - using RelativeDirectPointer = int32_t; -}; - -/// Template for branching on native pointer types versus external ones -template class Pointee> -using TargetMetadataPointer - = typename Runtime::template Pointer>; - -template class Pointee> -using ConstTargetMetadataPointer - = typename Runtime::template Pointer>; - -template -using TargetPointer = typename Runtime::template Pointer; - -template -using TargetSignedPointer = typename Runtime::template SignedPointer; - -template -using ConstTargetPointer = typename Runtime::template Pointer; - - -template class Pointee, - bool Nullable = true> -using ConstTargetFarRelativeDirectPointer - = typename Runtime::template FarRelativeDirectPointer, - Nullable>; - -template -using TargetRelativeDirectPointer - = typename Runtime::template RelativeDirectPointer; - -template -using TargetRelativeIndirectablePointer - = typename Runtime::template RelativeIndirectablePointer; +template struct TargetProtocolConformanceDescriptor; struct HeapObject; class WeakReference; struct UnownedReference; - -template struct TargetMetadata; -using Metadata = TargetMetadata; /// The result of requesting type metadata. Generally the return value of /// a function. @@ -293,203 +115,6 @@ struct MetadataDependency { } }; -template struct TargetProtocolConformanceDescriptor; - -/// Storage for an arbitrary value. In C/C++ terms, this is an -/// 'object', because it is rooted in memory. -/// -/// The context dictates what type is actually stored in this object, -/// and so this type is intentionally incomplete. -/// -/// An object can be in one of two states: -/// - An uninitialized object has a completely unspecified state. -/// - An initialized object holds a valid value of the type. -struct OpaqueValue; - -/// A fixed-size buffer for local values. It is capable of owning -/// (possibly in side-allocated memory) the storage necessary -/// to hold a value of an arbitrary type. Because it is fixed-size, -/// it can be allocated in places that must be agnostic to the -/// actual type: for example, within objects of existential type, -/// or for local variables in generic functions. -/// -/// The context dictates its type, which ultimately means providing -/// access to a value witness table by which the value can be -/// accessed and manipulated. -/// -/// A buffer can directly store three pointers and is pointer-aligned. -/// Three pointers is a sweet spot for Swift, because it means we can -/// store a structure containing a pointer, a size, and an owning -/// object, which is a common pattern in code due to ARC. In a GC -/// environment, this could be reduced to two pointers without much loss. -/// -/// A buffer can be in one of three states: -/// - An unallocated buffer has a completely unspecified state. -/// - An allocated buffer has been initialized so that it -/// owns uninitialized value storage for the stored type. -/// - An initialized buffer is an allocated buffer whose value -/// storage has been initialized. -template -struct TargetValueBuffer { - TargetPointer PrivateData[NumWords_ValueBuffer]; -}; -using ValueBuffer = TargetValueBuffer; - -/// Can a value with the given size and alignment be allocated inline? -constexpr inline bool canBeInline(bool isBitwiseTakable, size_t size, - size_t alignment) { - return isBitwiseTakable && size <= sizeof(ValueBuffer) && - alignment <= alignof(ValueBuffer); -} - -template -constexpr inline bool canBeInline(bool isBitwiseTakable) { - return canBeInline(isBitwiseTakable, sizeof(T), alignof(T)); -} - -template struct TargetValueWitnessTable; -using ValueWitnessTable = TargetValueWitnessTable; - -template class TargetValueWitnessTypes; -using ValueWitnessTypes = TargetValueWitnessTypes; - -template -class TargetValueWitnessTypes { -public: - using StoredPointer = typename Runtime::StoredPointer; - -// Note that, for now, we aren't strict about 'const'. -#define WANT_ALL_VALUE_WITNESSES -#define DATA_VALUE_WITNESS(lowerId, upperId, type) -#define FUNCTION_VALUE_WITNESS(lowerId, upperId, returnType, paramTypes) \ - typedef returnType (*lowerId ## Unsigned) paramTypes; \ - typedef TargetSignedPointer lowerId; -#define MUTABLE_VALUE_TYPE TargetPointer -#define IMMUTABLE_VALUE_TYPE ConstTargetPointer -#define MUTABLE_BUFFER_TYPE TargetPointer -#define IMMUTABLE_BUFFER_TYPE ConstTargetPointer -#define TYPE_TYPE ConstTargetPointer -#define SIZE_TYPE StoredSize -#define INT_TYPE int -#define UINT_TYPE unsigned -#define VOID_TYPE void -#include "swift/ABI/ValueWitness.def" - - // Handle the data witnesses explicitly so we can use more specific - // types for the flags enums. - typedef size_t size; - typedef size_t stride; - typedef ValueWitnessFlags flags; - typedef uint32_t extraInhabitantCount; -}; - -struct TypeLayout; - -/// A value-witness table. A value witness table is built around -/// the requirements of some specific type. The information in -/// a value-witness table is intended to be sufficient to lay out -/// and manipulate values of an arbitrary type. -template struct TargetValueWitnessTable { - // For the meaning of all of these witnesses, consult the comments - // on their associated typedefs, above. - -#define WANT_ONLY_REQUIRED_VALUE_WITNESSES -#define VALUE_WITNESS(LOWER_ID, UPPER_ID) \ - typename TargetValueWitnessTypes::LOWER_ID LOWER_ID; -#define FUNCTION_VALUE_WITNESS(LOWER_ID, UPPER_ID, RET, PARAMS) \ - typename TargetValueWitnessTypes::LOWER_ID LOWER_ID; - -#include "swift/ABI/ValueWitness.def" - - using StoredSize = typename Runtime::StoredSize; - - /// Is the external type layout of this type incomplete? - bool isIncomplete() const { - return flags.isIncomplete(); - } - - /// Would values of a type with the given layout requirements be - /// allocated inline? - static bool isValueInline(bool isBitwiseTakable, StoredSize size, - StoredSize alignment) { - return (isBitwiseTakable && size <= sizeof(TargetValueBuffer) && - alignment <= alignof(TargetValueBuffer)); - } - - /// Are values of this type allocated inline? - bool isValueInline() const { - return flags.isInlineStorage(); - } - - /// Is this type POD? - bool isPOD() const { - return flags.isPOD(); - } - - /// Is this type bitwise-takable? - bool isBitwiseTakable() const { - return flags.isBitwiseTakable(); - } - - /// Return the size of this type. Unlike in C, this has not been - /// padded up to the alignment; that value is maintained as - /// 'stride'. - StoredSize getSize() const { - return size; - } - - /// Return the stride of this type. This is the size rounded up to - /// be a multiple of the alignment. - StoredSize getStride() const { - return stride; - } - - /// Return the alignment required by this type, in bytes. - StoredSize getAlignment() const { - return flags.getAlignment(); - } - - /// The alignment mask of this type. An offset may be rounded up to - /// the required alignment by adding this mask and masking by its - /// bit-negation. - /// - /// For example, if the type needs to be 8-byte aligned, the value - /// of this witness is 0x7. - StoredSize getAlignmentMask() const { - return flags.getAlignmentMask(); - } - - /// The number of extra inhabitants, that is, bit patterns that do not form - /// valid values of the type, in this type's binary representation. - unsigned getNumExtraInhabitants() const { - return extraInhabitantCount; - } - - /// Assert that this value witness table is an enum value witness table - /// and return it as such. - /// - /// This has an awful name because it's supposed to be internal to - /// this file. Code outside this file should use LLVM's cast/dyn_cast. - /// We don't want to use those here because we need to avoid accidentally - /// introducing ABI dependencies on LLVM structures. - const struct EnumValueWitnessTable *_asEVWT() const; - - /// Get the type layout record within this value witness table. - const TypeLayout *getTypeLayout() const { - return reinterpret_cast(&size); - } - - /// Check whether this metadata is complete. - bool checkIsComplete() const; - - /// "Publish" the layout of this type to other threads. All other stores - /// to the value witness table (including its extended header) should have - /// happened before this is called. - void publishLayout(const TypeLayout &layout); -}; - /// The header before a metadata object which appears on all type /// metadata. Note that heap metadata are not necessarily type /// metadata, even for objects of a heap type: for example, objects of @@ -730,23 +355,13 @@ struct TargetMetadata { getTypeContextDescriptor() const { switch (getKind()) { case MetadataKind::Class: { - if (Runtime::ObjCInterop) { - const auto cls = static_cast> *>(this); - if (!cls->isTypeMetadata()) - return nullptr; - if (cls->isArtificialSubclass()) - return nullptr; - return cls->getDescription(); - } else { - const auto cls = static_cast> *>(this); - if (!cls->isTypeMetadata()) - return nullptr; - if (cls->isArtificialSubclass()) - return nullptr; - return cls->getDescription(); - } + const auto cls = + static_cast *>(this); + if (!cls->isTypeMetadata()) + return nullptr; + if (cls->isArtificialSubclass()) + return nullptr; + return cls->getDescription(); } case MetadataKind::Struct: case MetadataKind::Enum: @@ -763,7 +378,7 @@ struct TargetMetadata { /// Get the class object for this type if it has one, or return null if the /// type is not a class (or not a class with a class object). - const typename Runtime::template TargetClassMetadata * + const TargetClassMetadataType * getClassObject() const; /// Retrieve the generic arguments of this type, if it has any. @@ -928,29 +543,6 @@ struct TargetVTableDescriptorHeader { } }; -template struct TargetContextDescriptor; - -template class Context = TargetContextDescriptor> -using TargetSignedContextPointer = TargetSignedPointer * __ptrauth_swift_type_descriptor>; - -template class Context = TargetContextDescriptor> -using TargetRelativeContextPointer = - RelativeIndirectablePointer, - /*nullable*/ true, int32_t, - TargetSignedContextPointer>; - -using RelativeContextPointer = TargetRelativeContextPointer; - -template class Context = TargetContextDescriptor> -using RelativeContextPointerIntPair = - RelativeIndirectablePointerIntPair, IntTy, - /*nullable*/ true, int32_t, - TargetSignedContextPointer>; - template struct TargetMethodDescriptor; template @@ -1008,8 +600,7 @@ struct TargetClassMetadataBounds : TargetMetadataBounds { using TargetMetadataBounds::NegativeSizeInWords; using TargetMetadataBounds::PositiveSizeInWords; - using TargetClassMetadata = - typename Runtime::template TargetClassMetadata; + using TargetClassMetadata = TargetClassMetadataType; /// The offset from the address point of the metadata to the immediate /// members. @@ -1022,13 +613,10 @@ struct TargetClassMetadataBounds : TargetMetadataBounds { : TargetMetadataBounds{negativeSizeInWords, positiveSizeInWords}, ImmediateMembersOffset(immediateMembersOffset) {} - template - using TargetClassMetadataT = typename Runtime::template TargetClassMetadata; - /// Return the basic bounds of all Swift class metadata. /// The immediate members offset will not be meaningful. static constexpr TargetClassMetadataBounds forSwiftRootClass() { - using Metadata = FullMetadata>; + using Metadata = FullMetadata>; return forAddressPointAndSize(sizeof(typename Metadata::HeaderType), sizeof(Metadata)); } @@ -1071,8 +659,7 @@ template struct TargetAnyClassMetadata : public TargetHeapMetadata { using StoredPointer = typename Runtime::StoredPointer; using StoredSize = typename Runtime::StoredSize; - using TargetClassMetadata = - typename Runtime::template TargetClassMetadata; + using TargetClassMetadata = TargetClassMetadataType; protected: constexpr TargetAnyClassMetadata( @@ -1109,9 +696,9 @@ struct TargetAnyClassMetadataObjCInterop : public TargetAnyClassMetadata { using StoredPointer = typename Runtime::StoredPointer; using StoredSize = typename Runtime::StoredSize; - using TargetClassMetadataObjCInterop = - swift::TargetClassMetadata>; + // swift:: qualifier works around an MSVC quirk + swift::TargetClassMetadata>; constexpr TargetAnyClassMetadataObjCInterop( TargetAnyClassMetadataObjCInterop *isa, @@ -1156,11 +743,7 @@ struct TargetAnyClassMetadataObjCInterop } }; -#if SWIFT_OBJC_INTEROP -using AnyClassMetadata = TargetAnyClassMetadataObjCInterop; -#else -using AnyClassMetadata = TargetAnyClassMetadata; -#endif +using AnyClassMetadata = TargetAnyClassMetadataType; using ClassIVarDestroyer = SWIFT_CC(swift) void(SWIFT_CONTEXT HeapObject *); @@ -1444,18 +1027,7 @@ struct TargetClassMetadata : public TargetAnyClassMetadataVariant { return metadata->getKind() == MetadataKind::Class; } }; -#if SWIFT_OBJC_INTEROP -using ClassMetadata = - TargetClassMetadata>; -#else -using ClassMetadata = - TargetClassMetadata>; -#endif - -template -using TargetClassMetadataObjCInterop = - TargetClassMetadata>; +using ClassMetadata = TargetClassMetadataType; /// The structure of class metadata that's compatible with dispatch objects. /// This includes Swift heap metadata, followed by the vtable entries that @@ -1937,161 +1509,6 @@ TargetTupleTypeMetadata::getOffsetToNumElements() -> StoredSize { template struct TargetProtocolDescriptor; -/// 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 protocol requirement descriptor. This describes a single protocol /// requirement in a protocol descriptor. The index of the requirement in /// the descriptor determines the offset of the witness in a witness table @@ -2541,116 +1958,6 @@ using ProtocolRecord = TargetProtocolRecord; template class TargetGenericRequirementDescriptor; -/// 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())); - } - - operator TargetProtocolDescriptorRef() const { - return getProtocol(); - } -}; - -/// A reference to a type. -template -struct TargetTypeReference { - template - using TargetClassMetadata = typename T::template TargetClassMetadata; - - 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; - /// Header containing information about the resilient witnesses in a /// protocol conformance descriptor. template @@ -2863,9 +2170,6 @@ using ExternalProtocolConformanceDescriptor = TargetProtocolConformanceDescripto template