Skip to content

Commit a54a6d8

Browse files
committed
[ABI] Rework protocol descriptor metadata.
Reimplement protocol descriptors for Swift protocols as a kind of context descriptor, dropping the Objective-C protocol compatibility layout. The new protocol descriptors have several advantages over the current implementation: * They drop all of the unused fields required for layout-compatibility with Objective-C protocols. * They encode the full requirement signature of the protocol. This maintains more information about the protocol itself, including (e.g.) correctly encoding superclass requirements. * They fit within the general scheme of context descriptors, rather than being their own thing, which allows us to share more code with nominal type descriptors. * They only use relative pointers, so they’re smaller and can be placed in read-only memory Implements rdar://problem/38815359.
1 parent c56879d commit a54a6d8

21 files changed

+528
-550
lines changed

Diff for: docs/ABI/TypeMetadata.rst

+28-64
Original file line numberDiff line numberDiff line change
@@ -410,72 +410,36 @@ See the `protocol descriptor`_ description below.
410410
Protocol Descriptor
411411
~~~~~~~~~~~~~~~~~~~
412412

413-
`Protocol metadata` contains references to zero, one, or more **protocol
414-
descriptors** that describe the protocols values of the type are required to
415-
conform to. The protocol descriptor is laid out to be compatible with
416-
Objective-C ``Protocol`` objects. The layout is as follows:
417-
418-
- An **isa** placeholder is stored at **offset 0**. This field is populated by
419-
the Objective-C runtime.
420-
- The mangled **name** is referenced as a null-terminated C string at
421-
**offset 1**.
422-
- If the protocol inherits one or more other protocols, a pointer to the
423-
**inherited protocols list** is stored at **offset 2**. The list starts with
424-
the number of inherited protocols as a pointer-sized integer, and is followed
425-
by that many protocol descriptor pointers. If the protocol inherits no other
426-
protocols, this pointer is null.
427-
- For an ObjC-compatible protocol, its **required instance methods** are stored
428-
at **offset 3** as an ObjC-compatible method list. This is null for native
429-
Swift protocols.
430-
- For an ObjC-compatible protocol, its **required class methods** are stored
431-
at **offset 4** as an ObjC-compatible method list. This is null for native
432-
Swift protocols.
433-
- For an ObjC-compatible protocol, its **optional instance methods** are stored
434-
at **offset 5** as an ObjC-compatible method list. This is null for native
435-
Swift protocols.
436-
- For an ObjC-compatible protocol, its **optional class methods** are stored
437-
at **offset 6** as an ObjC-compatible method list. This is null for native
438-
Swift protocols.
439-
- For an ObjC-compatible protocol, its **instance properties** are stored
440-
at **offset 7** as an ObjC-compatible property list. This is null for native
441-
Swift protocols.
442-
- The **size** of the protocol descriptor record is stored as a 32-bit integer
443-
at **offset 8**. This is currently 72 on 64-bit platforms and 40 on 32-bit
444-
platforms.
445-
- **Flags** are stored as a 32-bit integer after the size. The following bits
446-
are currently used (counting from least significant bit zero):
447-
448-
* **Bit 0** is the **Swift bit**. It is set for all protocols defined in
449-
Swift and unset for protocols defined in Objective-C.
450-
* **Bit 1** is the **class constraint bit**. It is set if the protocol is
413+
Protocol descriptors describe the requirements of a protocol, and act as a
414+
handle for the protocol itself. The are referenced by `Protocol metadata`_, as
415+
well as `Protocol Conformance Records`_ and generic requirements. Protocol
416+
descriptors are only created for non-`@objc` Swift protocols: `@objc` protocols
417+
are emitted as Objective-C metadata. The layout of Swift protocol descriptors is
418+
as follows:
419+
420+
- Protocol descriptors are context descriptors, so they are prefixed by context
421+
descriptor metadata. (FIXME: these are not yet documented)
422+
- The 16-bit kind-specific flags of a protocol are defined as follows:
423+
* **Bit 0** is the **class constraint bit**. It is set if the protocol is
451424
**not** class-constrained, meaning that any struct, enum, or class type
452425
may conform to the protocol. It is unset if only classes can conform to
453-
the protocol. (The inverted meaning is for compatibility with Objective-C
454-
protocol records, in which the bit is never set. Objective-C protocols can
455-
only be conformed to by classes.)
456-
* **Bit 2** is the **witness table bit**. It is set if dispatch to the
457-
protocol's methods is done through a witness table, which is either passed
458-
as an extra parameter to generic functions or included in the existential
459-
container layout of protocol types. It is unset if dispatch is done
460-
through ``objc_msgSend`` and requires no additional information to accompany
461-
a value of conforming type.
462-
* **Bit 31** is set by the Objective-C runtime when it has done its
463-
initialization of the protocol record. It is unused by the Swift runtime.
464-
- **Number of mandatory requirements** is stored as a 16-bit integer after
465-
the flags. It specifies the number of requirements that do not have default
466-
implementations.
467-
- **Number of requirements** is stored as a 16-bit integer after the flags. It
468-
specifies the total number of requirements for the protocol.
469-
- **Requirements pointer** stored as a 32-bit relative pointer to an array
470-
of protocol requirements. The number of elements in the array is specified
471-
by the preceding 16-bit integer.
472-
- **Superclass pointer** stored as a 32-bit relative pointer to class metadata,
473-
describing the superclass bound of the protocol.
474-
- **Associated type names** stored as a 32-bit relative pointer to a
475-
null-terminated string. The string contains the names of the associated
476-
types, in the order they apparent in the requirements list, separated by
477-
spaces.
478-
426+
the protocol.
427+
* **Bit 1** indicates that the protocol is **resilient**.
428+
* **Bits 2-7** indicate specify the **special protocol kind**. Only one
429+
special protocol kind is defined: the `Error` protocol has value 1.
430+
- A pointer to the **name** of the protocol. FIXME: The name is currently
431+
mangles, but will change to the (unmangled) name.
432+
- The number of generic requirements within the **requirement signature** of
433+
the protocol. The generic requirements themselves follow the fixed part
434+
of the protocol descriptor.
435+
- The number of **protocol requirements** in the protocol. The protocol
436+
requirements follow the generic reuqirements that form the **requirement
437+
signature**.
438+
- A string containing the **associated type names**, a C string comprising the
439+
names of all of the associated types in this protocol, separated by spaces,
440+
and in the same order as they appear in the protocol requirements.
441+
- The **generic requirements** that form the **requirement signature**.
442+
- The **protocol requirements** of the protocol.
479443

480444
Protocol Conformance Records
481445
~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Diff for: include/swift/ABI/Metadata.h

+99-74
Original file line numberDiff line numberDiff line change
@@ -1623,8 +1623,6 @@ class TargetProtocolDescriptorRef {
16231623
ProtocolDescriptorPointer protocol,
16241624
ProtocolDispatchStrategy dispatchStrategy) {
16251625
#if SWIFT_OBJC_INTEROP
1626-
assert(!protocol ||
1627-
protocol->Flags.getDispatchStrategy() == dispatchStrategy);
16281626
storage = reinterpret_cast<StoredPointer>(protocol)
16291627
| (dispatchStrategy == ProtocolDispatchStrategy::ObjC ? IsObjCBit : 0);
16301628
#else
@@ -1681,7 +1679,8 @@ class TargetProtocolDescriptorRef {
16811679
}
16821680
#endif
16831681

1684-
return getSwiftProtocol()->Flags.getClassConstraint();
1682+
return getSwiftProtocol()->getProtocolContextDescriptorFlags()
1683+
.getClassConstraint();
16851684
}
16861685

16871686
/// Determine whether this protocol needs a witness table.
@@ -1702,7 +1701,8 @@ class TargetProtocolDescriptorRef {
17021701
}
17031702
#endif
17041703

1705-
return getSwiftProtocol()->Flags.getSpecialProtocol();
1704+
return getSwiftProtocol()->getProtocolContextDescriptorFlags()
1705+
.getSpecialProtocol();
17061706
}
17071707

17081708
/// Retrieve the Swift protocol descriptor.
@@ -1816,76 +1816,7 @@ struct TargetProtocolRequirement {
18161816

18171817
using ProtocolRequirement = TargetProtocolRequirement<InProcess>;
18181818

1819-
/// A protocol descriptor. This is not type metadata, but is referenced by
1820-
/// existential type metadata records to describe a protocol constraint.
1821-
/// Its layout is compatible with the Objective-C runtime's 'protocol_t' record
1822-
/// layout.
1823-
template <typename Runtime>
1824-
struct TargetProtocolDescriptor {
1825-
using StoredPointer = typename Runtime::StoredPointer;
1826-
/// Unused by the Swift runtime.
1827-
TargetPointer<Runtime, const void> _ObjC_Isa;
1828-
1829-
/// The mangled name of the protocol.
1830-
TargetPointer<Runtime, const char> Name;
1831-
1832-
/// The list of protocols this protocol refines.
1833-
ConstTargetMetadataPointer<Runtime, TargetProtocolDescriptorList>
1834-
InheritedProtocols;
1835-
1836-
/// Unused by the Swift runtime.
1837-
TargetPointer<Runtime, const void>
1838-
_ObjC_InstanceMethods,
1839-
_ObjC_ClassMethods,
1840-
_ObjC_OptionalInstanceMethods,
1841-
_ObjC_OptionalClassMethods,
1842-
_ObjC_InstanceProperties;
1843-
1844-
/// Size of the descriptor record.
1845-
uint32_t DescriptorSize;
1846-
1847-
/// Additional flags.
1848-
ProtocolDescriptorFlags Flags;
1849-
1850-
/// The number of requirements described by the Requirements array.
1851-
/// If any requirements beyond MinimumWitnessTableSizeInWords are present
1852-
/// in the witness table template, they will be not be overwritten with
1853-
/// defaults.
1854-
uint32_t NumRequirements;
1855-
1856-
/// Requirement descriptions.
1857-
RelativeDirectPointer<TargetProtocolRequirement<Runtime>> Requirements;
1858-
1859-
/// The superclass of which all conforming types must be a subclass.
1860-
RelativeDirectPointer<const TargetClassMetadata<Runtime>, /*Nullable=*/true>
1861-
Superclass;
1862-
1863-
/// Associated type names, as a space-separated list in the same order
1864-
/// as the requirements.
1865-
RelativeDirectPointer<const char, /*Nullable=*/true> AssociatedTypeNames;
1866-
1867-
// This is only used in unittests/Metadata.cpp.
1868-
constexpr TargetProtocolDescriptor<Runtime>(const char *Name,
1869-
const TargetProtocolDescriptorList<Runtime> *Inherited,
1870-
ProtocolDescriptorFlags Flags)
1871-
: _ObjC_Isa(nullptr), Name(Name), InheritedProtocols(Inherited),
1872-
_ObjC_InstanceMethods(nullptr), _ObjC_ClassMethods(nullptr),
1873-
_ObjC_OptionalInstanceMethods(nullptr),
1874-
_ObjC_OptionalClassMethods(nullptr),
1875-
_ObjC_InstanceProperties(nullptr),
1876-
DescriptorSize(sizeof(TargetProtocolDescriptor<Runtime>)),
1877-
Flags(Flags),
1878-
NumRequirements(0),
1879-
Requirements(nullptr),
1880-
Superclass(nullptr),
1881-
AssociatedTypeNames(nullptr)
1882-
{}
1883-
1884-
#ifndef NDEBUG
1885-
LLVM_ATTRIBUTE_DEPRECATED(void dump() const LLVM_ATTRIBUTE_USED,
1886-
"only for use in the debugger");
1887-
#endif
1888-
};
1819+
template<typename Runtime> struct TargetProtocolDescriptor;
18891820
using ProtocolDescriptor = TargetProtocolDescriptor<InProcess>;
18901821

18911822
/// A witness table for a protocol.
@@ -3001,6 +2932,100 @@ struct TargetAnonymousContextDescriptor final
30012932
}
30022933
};
30032934

2935+
/// A protocol descriptor.
2936+
///
2937+
/// Protocol descriptors contain information about the contents of a protocol:
2938+
/// it's name, requirements, requirement signature, context, and so on. They
2939+
/// are used both to identify a protocol and to reason about its contents.
2940+
///
2941+
/// Only Swift protocols are defined by a protocol descriptor, whereas
2942+
/// Objective-C (including protocols defined in Swift as @objc) use the
2943+
/// Objective-C protocol layout.
2944+
template<typename Runtime>
2945+
struct TargetProtocolDescriptor final
2946+
: TargetContextDescriptor<Runtime>,
2947+
TrailingGenericContextObjects<
2948+
TargetProtocolDescriptor<Runtime>,
2949+
TargetGenericContextDescriptorHeader,
2950+
TargetGenericRequirementDescriptor<Runtime>,
2951+
TargetProtocolRequirement<Runtime>>
2952+
{
2953+
private:
2954+
using TrailingObjects
2955+
= TrailingGenericContextObjects<
2956+
TargetProtocolDescriptor<Runtime>,
2957+
TargetGenericContextDescriptorHeader,
2958+
TargetGenericRequirementDescriptor<Runtime>,
2959+
TargetProtocolRequirement<Runtime>>;
2960+
2961+
friend TrailingObjects;
2962+
2963+
template<typename T>
2964+
using OverloadToken = typename TrailingObjects::template OverloadToken<T>;
2965+
2966+
public:
2967+
using TrailingObjects::getGenericContext;
2968+
using TrailingObjects::numTrailingObjects;
2969+
2970+
size_t numTrailingObjects(
2971+
OverloadToken<TargetGenericRequirementDescriptor<Runtime>>) const {
2972+
return NumRequirementsInSignature;
2973+
}
2974+
2975+
size_t numTrailingObjects(
2976+
OverloadToken<TargetProtocolRequirement<Runtime>>) const {
2977+
return NumRequirements;
2978+
}
2979+
2980+
2981+
/// The name of the protocol.
2982+
TargetRelativeDirectPointer<Runtime, const char, /*nullable*/ false> Name;
2983+
2984+
/// The number of generic requirements in the requirement signature of the
2985+
/// protocol.
2986+
uint32_t NumRequirementsInSignature;
2987+
2988+
/// The number of requirements in the protocol.
2989+
/// If any requirements beyond MinimumWitnessTableSizeInWords are present
2990+
/// in the witness table template, they will be not be overwritten with
2991+
/// defaults.
2992+
uint32_t NumRequirements;
2993+
2994+
/// Associated type names, as a space-separated list in the same order
2995+
/// as the requirements.
2996+
RelativeDirectPointer<const char, /*Nullable=*/true> AssociatedTypeNames;
2997+
2998+
ProtocolContextDescriptorFlags getProtocolContextDescriptorFlags() const {
2999+
return ProtocolContextDescriptorFlags(this->Flags.getKindSpecificFlags());
3000+
}
3001+
3002+
/// Retrieve the requirements that make up the requirement signature of
3003+
/// this protocol.
3004+
llvm::ArrayRef<TargetGenericRequirementDescriptor<Runtime>>
3005+
getRequirementSignature() const {
3006+
return {this->template getTrailingObjects<
3007+
TargetGenericRequirementDescriptor<Runtime>>(),
3008+
NumRequirementsInSignature};
3009+
}
3010+
3011+
/// Retrieve the requirements of this protocol.
3012+
llvm::ArrayRef<TargetProtocolRequirement<Runtime>>
3013+
getRequirements() const {
3014+
return {this->template getTrailingObjects<
3015+
TargetProtocolRequirement<Runtime>>(),
3016+
NumRequirements};
3017+
}
3018+
3019+
#ifndef NDEBUG
3020+
LLVM_ATTRIBUTE_DEPRECATED(void dump() const LLVM_ATTRIBUTE_USED,
3021+
"only for use in the debugger");
3022+
#endif
3023+
3024+
static bool classof(const TargetContextDescriptor<Runtime> *cd) {
3025+
return cd->getKind() == ContextDescriptorKind::Protocol;
3026+
}
3027+
};
3028+
30043029
/// The instantiation cache for generic metadata. This must be guaranteed
30053030
/// to zero-initialized before it is first accessed. Its contents are private
30063031
/// to the runtime.

Diff for: include/swift/ABI/MetadataValues.h

+39-1
Original file line numberDiff line numberDiff line change
@@ -1074,7 +1074,10 @@ enum class ContextDescriptorKind : uint8_t {
10741074
/// This context descriptor represents an anonymous possibly-generic context
10751075
/// such as a function body.
10761076
Anonymous = 2,
1077-
1077+
1078+
/// This context descriptor represents a protocol context.
1079+
Protocol = 3,
1080+
10781081
/// First kind that represents a type of any sort.
10791082
Type_First = 16,
10801083

@@ -1251,6 +1254,41 @@ class TypeContextDescriptorFlags : public FlagSet<uint16_t> {
12511254
class_setSuperclassReferenceKind)
12521255
};
12531256

1257+
/// Flags for protocol context descriptors. These values are used as the
1258+
/// kindSpecificFlags of the ContextDescriptorFlags for the protocol.
1259+
class ProtocolContextDescriptorFlags : public FlagSet<uint16_t> {
1260+
enum {
1261+
/// Whether this protocol is class-constrained.
1262+
HasClassConstraint = 0,
1263+
HasClassConstraint_width = 1,
1264+
1265+
/// Whether this protocol is resilient.
1266+
IsResilient = 1,
1267+
1268+
/// Special protocol value.
1269+
SpecialProtocolKind = 2,
1270+
SpecialProtocolKind_width = 6,
1271+
};
1272+
1273+
public:
1274+
explicit ProtocolContextDescriptorFlags(uint16_t bits) : FlagSet(bits) {}
1275+
constexpr ProtocolContextDescriptorFlags() {}
1276+
1277+
FLAGSET_DEFINE_FLAG_ACCESSORS(IsResilient, isResilient, setIsResilient)
1278+
1279+
FLAGSET_DEFINE_FIELD_ACCESSORS(HasClassConstraint,
1280+
HasClassConstraint_width,
1281+
ProtocolClassConstraint,
1282+
getClassConstraint,
1283+
setClassConstraint)
1284+
1285+
FLAGSET_DEFINE_FIELD_ACCESSORS(SpecialProtocolKind,
1286+
SpecialProtocolKind_width,
1287+
SpecialProtocol,
1288+
getSpecialProtocol,
1289+
setSpecialProtocol)
1290+
};
1291+
12541292
enum class GenericParamKind : uint8_t {
12551293
/// A type parameter.
12561294
Type = 0,

0 commit comments

Comments
 (0)