Skip to content

Commit 2173db0

Browse files
authored
Merge pull request #63961 from slavapestov/variadic-generic-types-plumbing
Start working on runtime support for variadic generic types
2 parents dd160ce + 5215406 commit 2173db0

File tree

10 files changed

+420
-27
lines changed

10 files changed

+420
-27
lines changed

include/swift/ABI/GenericContext.h

Lines changed: 121 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,38 @@ struct TargetProtocolConformanceDescriptor;
3030
template <typename Runtime>
3131
struct TargetGenericContext;
3232

33+
class GenericContextDescriptorFlags {
34+
uint16_t Value;
35+
36+
public:
37+
constexpr GenericContextDescriptorFlags() : Value(0) {}
38+
39+
explicit constexpr GenericContextDescriptorFlags(uint16_t value)
40+
: Value(value) {}
41+
42+
constexpr GenericContextDescriptorFlags(bool hasTypePacks)
43+
: GenericContextDescriptorFlags(
44+
GenericContextDescriptorFlags((uint16_t)0)
45+
.withHasTypePacks(hasTypePacks)) {}
46+
47+
/// Whether this generic context has at least one type parameter
48+
/// pack, in which case the generic context will have a trailing
49+
/// GenericParamPackShapeHeader.
50+
constexpr bool hasTypePacks() const {
51+
return (Value & 0x1) != 0;
52+
}
53+
54+
constexpr GenericContextDescriptorFlags
55+
withHasTypePacks(bool hasTypePacks) const {
56+
return GenericContextDescriptorFlags((uint16_t)(
57+
(Value & ~0x1) | (hasTypePacks ? 0x1 : 0)));
58+
}
59+
60+
constexpr uint16_t getIntValue() const {
61+
return Value;
62+
}
63+
};
64+
3365
template <typename Runtime>
3466
struct TargetGenericContextDescriptorHeader {
3567
/// The number of (source-written) generic parameters, and thus
@@ -39,8 +71,8 @@ struct TargetGenericContextDescriptorHeader {
3971
///
4072
/// A GenericParamDescriptor corresponds to a type metadata pointer
4173
/// in the arguments layout when isKeyArgument() is true.
42-
/// isKeyArgument() will be false if the parameter has been unified
43-
/// unified with a different parameter or an associated type.
74+
/// isKeyArgument() will be false if the parameter has been made
75+
/// equivalent to a different parameter or a concrete type.
4476
uint16_t NumParams;
4577

4678
/// The number of GenericRequirementDescriptors in this generic
@@ -66,18 +98,22 @@ struct TargetGenericContextDescriptorHeader {
6698
/// hasKeyArgument()).
6799
uint16_t NumKeyArguments;
68100

69-
/// In principle, the size of the "extra" area of the argument
101+
/// Originally this was the size of the "extra" area of the argument
70102
/// layout, in words. The idea was that extra arguments would
71103
/// include generic parameters and conformances that are not part
72104
/// of the identity of the context; however, it's unclear why we
73-
/// would ever want such a thing. As a result, this section is
74-
/// unused, and this field is always zero. It can be repurposed
75-
/// as long as it remains zero in code which must be compatible
76-
/// with existing Swift runtimes.
77-
uint16_t NumExtraArguments;
105+
/// would ever want such a thing. As a result, in pre-5.8 runtimes
106+
/// this field is always zero. New flags can only be added as long
107+
/// as they remains zero in code which must be compatible with
108+
/// older Swift runtimes.
109+
GenericContextDescriptorFlags Flags;
78110

79111
uint32_t getNumArguments() const {
80-
return NumKeyArguments + NumExtraArguments;
112+
// Note: this used to be NumKeyArguments + NumExtraArguments,
113+
// and flags was named NumExtraArguments, which is why Flags
114+
// must remain zero when backward deploying to Swift 5.7 or
115+
// earlier.
116+
return NumKeyArguments;
81117
}
82118

83119
/// Return the total size of the argument layout, in words.
@@ -163,7 +199,7 @@ class TargetGenericRequirementDescriptor {
163199
return offsetof(typename std::remove_reference<decltype(*this)>::type, Type);
164200
}
165201

166-
/// Retreive the offset to the Type field
202+
/// Retreive the offset to the Param field
167203
constexpr inline auto
168204
getParamOffset() const -> typename Runtime::StoredSize {
169205
return offsetof(typename std::remove_reference<decltype(*this)>::type, Param);
@@ -199,6 +235,7 @@ class TargetGenericRequirementDescriptor {
199235
case GenericRequirementKind::Protocol:
200236
case GenericRequirementKind::SameConformance:
201237
case GenericRequirementKind::SameType:
238+
case GenericRequirementKind::SameShape:
202239
return true;
203240
}
204241

@@ -208,6 +245,25 @@ class TargetGenericRequirementDescriptor {
208245
using GenericRequirementDescriptor =
209246
TargetGenericRequirementDescriptor<InProcess>;
210247

248+
struct GenericParamPackShapeHeader {
249+
/// The number of generic parameters which are packs.
250+
///
251+
/// Must equal the number of GenericParamDescriptors whose kind is
252+
/// GenericParamKind::TypePack.
253+
uint16_t NumTypePacks;
254+
255+
/// The number of equivalence classes in the same-shape relation.
256+
uint16_t NumShapeClasses;
257+
};
258+
259+
struct GenericParamPackShapeDescriptor {
260+
/// The equivalence class of this generic parameter pack under
261+
/// the same-shape relation.
262+
///
263+
/// Must be less than GenericParamPackShapeHeader::NumShapeClasses.
264+
uint16_t ShapeClass;
265+
};
266+
211267
/// An array of generic parameter descriptors, all
212268
/// GenericParamDescriptor::implicit(), which is by far
213269
/// the most common case. Some generic context storage can
@@ -243,14 +299,21 @@ class RuntimeGenericSignature {
243299
TargetGenericContextDescriptorHeader<Runtime> Header;
244300
const GenericParamDescriptor *Params;
245301
const TargetGenericRequirementDescriptor<Runtime> *Requirements;
302+
GenericParamPackShapeHeader PackShapeHeader;
303+
const GenericParamPackShapeDescriptor *PackShapeDescriptors;
304+
246305
public:
247306
RuntimeGenericSignature()
248-
: Header{0, 0, 0, 0}, Params(nullptr), Requirements(nullptr) {}
307+
: Header{0, 0, 0, 0}, Params(nullptr), Requirements(nullptr),
308+
PackShapeHeader{0, 0}, PackShapeDescriptors(nullptr) {}
249309

250310
RuntimeGenericSignature(const TargetGenericContextDescriptorHeader<Runtime> &header,
251311
const GenericParamDescriptor *params,
252-
const TargetGenericRequirementDescriptor<Runtime> *requirements)
253-
: Header(header), Params(params), Requirements(requirements) {}
312+
const TargetGenericRequirementDescriptor<Runtime> *requirements,
313+
const GenericParamPackShapeHeader &packShapeHeader,
314+
const GenericParamPackShapeDescriptor *packShapeDescriptors)
315+
: Header(header), Params(params), Requirements(requirements),
316+
PackShapeHeader(packShapeHeader), PackShapeDescriptors(packShapeDescriptors) {}
254317

255318
llvm::ArrayRef<GenericParamDescriptor> getParams() const {
256319
return llvm::makeArrayRef(Params, Header.NumParams);
@@ -260,6 +323,10 @@ class RuntimeGenericSignature {
260323
return llvm::makeArrayRef(Requirements, Header.NumRequirements);
261324
}
262325

326+
llvm::ArrayRef<GenericParamPackShapeDescriptor> getPackShapeDescriptors() const {
327+
return llvm::makeArrayRef(PackShapeDescriptors, PackShapeHeader.NumTypePacks);
328+
}
329+
263330
size_t getArgumentLayoutSizeInWords() const {
264331
return Header.getArgumentLayoutSizeInWords();
265332
}
@@ -350,6 +417,8 @@ class TrailingGenericContextObjects<TargetSelf<Runtime>,
350417
TargetGenericContextHeaderType<Runtime>,
351418
GenericParamDescriptor,
352419
TargetGenericRequirementDescriptor<Runtime>,
420+
GenericParamPackShapeHeader,
421+
GenericParamPackShapeDescriptor,
353422
FollowingTrailingObjects...>
354423
{
355424
protected:
@@ -362,6 +431,8 @@ class TrailingGenericContextObjects<TargetSelf<Runtime>,
362431
GenericContextHeaderType,
363432
GenericParamDescriptor,
364433
GenericRequirementDescriptor,
434+
GenericParamPackShapeHeader,
435+
GenericParamPackShapeDescriptor,
365436
FollowingTrailingObjects...>;
366437
friend TrailingObjects;
367438

@@ -415,6 +486,23 @@ class TrailingGenericContextObjects<TargetSelf<Runtime>,
415486
return {this->template getTrailingObjects<GenericRequirementDescriptor>(),
416487
getGenericContextHeader().NumRequirements};
417488
}
489+
490+
GenericParamPackShapeHeader getGenericParamPackShapeHeader() const {
491+
if (!asSelf()->isGeneric())
492+
return {0, 0};
493+
if (!getGenericContextHeader().Flags.hasTypePacks())
494+
return {0, 0};
495+
return *this->template getTrailingObjects<GenericParamPackShapeHeader>();
496+
}
497+
498+
llvm::ArrayRef<GenericParamPackShapeDescriptor> getGenericParamPackShapeDescriptors() const {
499+
auto header = getGenericParamPackShapeHeader();
500+
if (header.NumTypePacks == 0)
501+
return {};
502+
503+
return {this->template getTrailingObjects<GenericParamPackShapeDescriptor>(),
504+
header.NumTypePacks};
505+
}
418506

419507
/// Return the amount of space that the generic arguments take up in
420508
/// metadata of this type.
@@ -427,7 +515,9 @@ class TrailingGenericContextObjects<TargetSelf<Runtime>,
427515
if (!asSelf()->isGeneric()) return RuntimeGenericSignature<Runtime>();
428516
return {getGenericContextHeader(),
429517
getGenericParams().data(),
430-
getGenericRequirements().data()};
518+
getGenericRequirements().data(),
519+
getGenericParamPackShapeHeader(),
520+
getGenericParamPackShapeDescriptors().data()};
431521
}
432522

433523
protected:
@@ -443,6 +533,23 @@ class TrailingGenericContextObjects<TargetSelf<Runtime>,
443533
return asSelf()->isGeneric() ? getGenericContextHeader().NumRequirements : 0;
444534
}
445535

536+
size_t numTrailingObjects(OverloadToken<GenericParamPackShapeHeader>) const {
537+
if (!asSelf()->isGeneric())
538+
return 0;
539+
540+
return getGenericContextHeader().Flags.hasTypePacks() ? 1 : 0;
541+
}
542+
543+
size_t numTrailingObjects(OverloadToken<GenericParamPackShapeDescriptor>) const {
544+
if (!asSelf()->isGeneric())
545+
return 0;
546+
547+
if (!getGenericContextHeader().Flags.hasTypePacks())
548+
return 0;
549+
550+
return getGenericParamPackShapeHeader().NumTypePacks;
551+
}
552+
446553
#if defined(_MSC_VER) && _MSC_VER < 1920
447554
#undef OverloadToken
448555
#endif

include/swift/ABI/Metadata.h

Lines changed: 91 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1929,7 +1929,13 @@ struct TargetExtendedExistentialTypeShape
19291929
GenericParamDescriptor,
19301930
// Requirements for requirement signature, followed by requirements
19311931
// for generalization signature
1932-
TargetGenericRequirementDescriptor<Runtime>> {
1932+
TargetGenericRequirementDescriptor<Runtime>,
1933+
// Optional header describing any type packs in the generalization
1934+
// signature.
1935+
GenericParamPackShapeHeader,
1936+
// For each type pack in the generalization signature, a descriptor
1937+
// storing the shape class.
1938+
GenericParamPackShapeDescriptor> {
19331939
private:
19341940
using RelativeValueWitnessTablePointer =
19351941
TargetRelativeIndirectablePointer<Runtime,
@@ -1942,7 +1948,9 @@ struct TargetExtendedExistentialTypeShape
19421948
TargetExistentialTypeExpression<Runtime>,
19431949
RelativeValueWitnessTablePointer,
19441950
GenericParamDescriptor,
1945-
TargetGenericRequirementDescriptor<Runtime>>;
1951+
TargetGenericRequirementDescriptor<Runtime>,
1952+
GenericParamPackShapeHeader,
1953+
GenericParamPackShapeDescriptor>;
19461954
friend TrailingObjects;
19471955

19481956
template<typename T>
@@ -1965,10 +1973,21 @@ struct TargetExtendedExistentialTypeShape
19651973
+ (Flags.hasImplicitGenSigParams() ? 0 : getNumGenSigParams());
19661974
}
19671975

1968-
size_t numTrailingObjects(OverloadToken<GenericRequirementDescriptor>) const {
1976+
size_t numTrailingObjects(OverloadToken<TargetGenericRequirementDescriptor<Runtime>>) const {
19691977
return getNumGenSigRequirements() + getNumReqSigRequirements();
19701978
}
19711979

1980+
size_t numTrailingObjects(OverloadToken<GenericParamPackShapeHeader>) const {
1981+
return (Flags.hasTypePacks() ? 1 : 0);
1982+
}
1983+
1984+
size_t numTrailingObjects(OverloadToken<GenericParamPackShapeDescriptor>) const {
1985+
if (!Flags.hasTypePacks())
1986+
return 0;
1987+
1988+
return getGenSigPackShapeHeader().NumTypePacks;
1989+
}
1990+
19721991
const TargetGenericContextDescriptorHeader<Runtime> *
19731992
getGenSigHeader() const {
19741993
assert(hasGeneralizationSignature());
@@ -2013,7 +2032,8 @@ struct TargetExtendedExistentialTypeShape
20132032
TargetGenericContextDescriptorHeader<Runtime> ReqSigHeader;
20142033

20152034
RuntimeGenericSignature<Runtime> getRequirementSignature() const {
2016-
return {ReqSigHeader, getReqSigParams(), getReqSigRequirements()};
2035+
return {ReqSigHeader, getReqSigParams(), getReqSigRequirements(),
2036+
{0, 0}, nullptr};
20172037
}
20182038

20192039
unsigned getNumReqSigParams() const {
@@ -2092,7 +2112,8 @@ struct TargetExtendedExistentialTypeShape
20922112

20932113
RuntimeGenericSignature<Runtime> getGeneralizationSignature() const {
20942114
if (!hasGeneralizationSignature()) return RuntimeGenericSignature<Runtime>();
2095-
return {*getGenSigHeader(), getGenSigParams(), getGenSigRequirements()};
2115+
return {*getGenSigHeader(), getGenSigParams(), getGenSigRequirements(),
2116+
getGenSigPackShapeHeader(), getGenSigPackShapeDescriptors()};
20962117
}
20972118

20982119
unsigned getNumGenSigParams() const {
@@ -2121,6 +2142,20 @@ struct TargetExtendedExistentialTypeShape
21212142
return getReqSigRequirements() + ReqSigHeader.NumRequirements;
21222143
}
21232144

2145+
GenericParamPackShapeHeader getGenSigPackShapeHeader() const {
2146+
assert(hasGeneralizationSignature());
2147+
if (!Flags.hasTypePacks())
2148+
return {0, 0};
2149+
return *this->template getTrailingObjects<GenericParamPackShapeHeader>();
2150+
}
2151+
2152+
const GenericParamPackShapeDescriptor *getGenSigPackShapeDescriptors() const {
2153+
assert(hasGeneralizationSignature());
2154+
if (!Flags.hasTypePacks())
2155+
return nullptr;
2156+
return this->template getTrailingObjects<GenericParamPackShapeDescriptor>();
2157+
}
2158+
21242159
/// Return the amount of space used in ExtendedExistentialTypeMetadata
21252160
/// for this shape to store the generalization arguments.
21262161
unsigned getGenSigArgumentLayoutSizeInWords() const {
@@ -4863,6 +4898,57 @@ class RuntimeDiscoverableAttributeRecord
48634898
}
48644899
};
48654900

4901+
enum class PackLifetime : uint8_t {
4902+
OnStack = 0,
4903+
OnHeap = 1
4904+
};
4905+
4906+
/// A pointer to a metadata or witness table pack. If the LSB is set,
4907+
/// the pack is allocated on the heap; otherwise, it is allocated on
4908+
/// the stack.
4909+
template<typename Runtime, template <typename> class Pointee>
4910+
class TargetPackPointer {
4911+
typename Runtime::StoredSize Ptr;
4912+
4913+
using PointerType = typename Runtime::template Pointer<const Pointee<Runtime>>;
4914+
4915+
public:
4916+
explicit TargetPackPointer(typename Runtime::StoredSize rawPtr) : Ptr(rawPtr) {}
4917+
4918+
explicit TargetPackPointer(PointerType const *ptr, PackLifetime lifetime)
4919+
: Ptr(reinterpret_cast<typename Runtime::StoredSize>(ptr) |
4920+
(lifetime == PackLifetime::OnHeap ? 1 : 0)) {}
4921+
4922+
const PointerType *getElements() const {
4923+
return reinterpret_cast<const PointerType *>(Ptr & ~1);
4924+
}
4925+
4926+
PointerType *getElements() {
4927+
return reinterpret_cast<PointerType *>(Ptr & ~1);
4928+
}
4929+
4930+
const PointerType *getPointer() const {
4931+
return reinterpret_cast<const PointerType *>(Ptr);
4932+
}
4933+
4934+
4935+
PackLifetime getLifetime() const {
4936+
return (bool)(Ptr & 1) ? PackLifetime::OnHeap : PackLifetime::OnStack;
4937+
}
4938+
};
4939+
4940+
/// A pointer to a metadata pack.
4941+
template<typename Runtime>
4942+
using TargetMetadataPackPointer = TargetPackPointer<Runtime, TargetMetadata>;
4943+
4944+
using MetadataPackPointer = TargetMetadataPackPointer<InProcess>;
4945+
4946+
/// A pointer to a witness table pack.
4947+
template<typename Runtime>
4948+
using TargetWitnessTablePackPointer = TargetPackPointer<Runtime, TargetWitnessTable>;
4949+
4950+
using WitnessTablePackPointer = TargetWitnessTablePackPointer<InProcess>;
4951+
48664952
} // end namespace swift
48674953

48684954
#pragma clang diagnostic pop

0 commit comments

Comments
 (0)