Skip to content

Commit 78de2fb

Browse files
committed
[NFC] Move generic contexts and metadata references into separate headers
1 parent 28e6822 commit 78de2fb

File tree

5 files changed

+765
-683
lines changed

5 files changed

+765
-683
lines changed

include/swift/ABI/GenericContext.h

Lines changed: 380 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,380 @@
1+
//===--- GenericContext.h - ABI for generic signatures ----------*- C++ -*-===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2022 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
//
13+
// This file describes runtime metadata structures for representing
14+
// generic signatures.
15+
//
16+
//===----------------------------------------------------------------------===//
17+
18+
#ifndef SWIFT_ABI_GENERICCONTEXT_H
19+
#define SWIFT_ABI_GENERICCONTEXT_H
20+
21+
#include "swift/ABI/TargetLayout.h"
22+
#include "swift/ABI/MetadataValues.h"
23+
#include "swift/ABI/MetadataRef.h"
24+
#include "swift/ABI/TrailingObjects.h"
25+
#include "swift/Demangling/Demangle.h"
26+
27+
namespace swift {
28+
template <typename Runtime>
29+
struct TargetProtocolConformanceDescriptor;
30+
template <typename Runtime>
31+
struct TargetGenericContext;
32+
33+
template <typename Runtime>
34+
struct TargetGenericContextDescriptorHeader {
35+
/// The number of (source-written) generic parameters, and thus
36+
/// the number of GenericParamDescriptors associated with this
37+
/// context. The parameter descriptors appear in the order in
38+
/// which they were given in the source.
39+
///
40+
/// A GenericParamDescriptor corresponds to a type metadata pointer
41+
/// 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.
44+
uint16_t NumParams;
45+
46+
/// The number of GenericRequirementDescriptors in this generic
47+
/// signature.
48+
///
49+
/// A GenericRequirementDescriptor of kind Protocol corresponds
50+
/// to a witness table pointer in the arguments layout when
51+
/// isKeyArgument() is true. isKeyArgument() will be false if
52+
/// the protocol is an Objective-C protocol. (Unlike generic
53+
/// parameters, redundant conformance requirements can simply be
54+
/// eliminated, and so that case is not impossible.)
55+
uint16_t NumRequirements;
56+
57+
/// The size of the "key" area of the argument layout, in words.
58+
/// Key arguments include generic parameters and conformance
59+
/// requirements which are part of the identity of the context.
60+
///
61+
/// The key area of the argument layout considers of a sequence
62+
/// of type metadata pointers (in the same order as the parameter
63+
/// descriptors, for those parameters which satisfy hasKeyArgument())
64+
/// followed by a sequence of witness table pointers (in the same
65+
/// order as the requirements, for those requirements which satisfy
66+
/// hasKeyArgument()).
67+
uint16_t NumKeyArguments;
68+
69+
/// In principle, the size of the "extra" area of the argument
70+
/// layout, in words. The idea was that extra arguments would
71+
/// include generic parameters and conformances that are not part
72+
/// 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;
78+
79+
uint32_t getNumArguments() const {
80+
return NumKeyArguments + NumExtraArguments;
81+
}
82+
83+
/// Return the total size of the argument layout, in words.
84+
/// The alignment of the argument layout is the word alignment.
85+
uint32_t getArgumentLayoutSizeInWords() const {
86+
return getNumArguments();
87+
}
88+
89+
bool hasArguments() const {
90+
return getNumArguments() > 0;
91+
}
92+
};
93+
using GenericContextDescriptorHeader =
94+
TargetGenericContextDescriptorHeader<InProcess>;
95+
96+
template<typename Runtime>
97+
class TargetGenericRequirementDescriptor {
98+
public:
99+
GenericRequirementFlags Flags;
100+
101+
/// The type that's constrained, described as a mangled name.
102+
RelativeDirectPointer<const char, /*nullable*/ false> Param;
103+
104+
union {
105+
/// A mangled representation of the same-type or base class the param is
106+
/// constrained to.
107+
///
108+
/// Only valid if the requirement has SameType or BaseClass kind.
109+
RelativeDirectPointer<const char, /*nullable*/ false> Type;
110+
111+
/// The protocol the param is constrained to.
112+
///
113+
/// Only valid if the requirement has Protocol kind.
114+
RelativeTargetProtocolDescriptorPointer<Runtime> Protocol;
115+
116+
/// The conformance the param is constrained to use.
117+
///
118+
/// Only valid if the requirement has SameConformance kind.
119+
RelativeIndirectablePointer<TargetProtocolConformanceDescriptor<Runtime>,
120+
/*nullable*/ false> Conformance;
121+
122+
/// The kind of layout constraint.
123+
///
124+
/// Only valid if the requirement has Layout kind.
125+
GenericRequirementLayoutKind Layout;
126+
};
127+
128+
constexpr GenericRequirementFlags getFlags() const {
129+
return Flags;
130+
}
131+
132+
constexpr GenericRequirementKind getKind() const {
133+
return getFlags().getKind();
134+
}
135+
136+
/// Retrieve the generic parameter that is the subject of this requirement,
137+
/// as a mangled type name.
138+
llvm::StringRef getParam() const {
139+
return swift::Demangle::makeSymbolicMangledNameStringRef(Param.get());
140+
}
141+
142+
/// Retrieve the protocol for a Protocol requirement.
143+
TargetProtocolDescriptorRef<Runtime> getProtocol() const {
144+
assert(getKind() == GenericRequirementKind::Protocol);
145+
return Protocol;
146+
}
147+
148+
/// Retrieve the right-hand type for a SameType or BaseClass requirement.
149+
llvm::StringRef getMangledTypeName() const {
150+
assert(getKind() == GenericRequirementKind::SameType ||
151+
getKind() == GenericRequirementKind::BaseClass);
152+
return swift::Demangle::makeSymbolicMangledNameStringRef(Type.get());
153+
}
154+
155+
/// Retrieve the protocol conformance record for a SameConformance
156+
/// requirement.
157+
const TargetProtocolConformanceDescriptor<Runtime> *getConformance() const {
158+
assert(getKind() == GenericRequirementKind::SameConformance);
159+
return Conformance;
160+
}
161+
162+
/// Retrieve the layout constraint.
163+
GenericRequirementLayoutKind getLayout() const {
164+
assert(getKind() == GenericRequirementKind::Layout);
165+
return Layout;
166+
}
167+
168+
/// Determine whether this generic requirement has a known kind.
169+
///
170+
/// \returns \c false for any future generic requirement kinds.
171+
bool hasKnownKind() const {
172+
switch (getKind()) {
173+
case GenericRequirementKind::BaseClass:
174+
case GenericRequirementKind::Layout:
175+
case GenericRequirementKind::Protocol:
176+
case GenericRequirementKind::SameConformance:
177+
case GenericRequirementKind::SameType:
178+
return true;
179+
}
180+
181+
return false;
182+
}
183+
};
184+
using GenericRequirementDescriptor =
185+
TargetGenericRequirementDescriptor<InProcess>;
186+
187+
template<typename Runtime>
188+
class TargetGenericEnvironment
189+
: public swift::ABI::TrailingObjects<TargetGenericEnvironment<Runtime>,
190+
uint16_t, GenericParamDescriptor,
191+
TargetGenericRequirementDescriptor<Runtime>> {
192+
using GenericRequirementDescriptor =
193+
TargetGenericRequirementDescriptor<Runtime>;
194+
using TrailingObjects =
195+
swift::ABI::TrailingObjects<TargetGenericEnvironment<Runtime>,
196+
uint16_t, GenericParamDescriptor, GenericRequirementDescriptor>;
197+
friend TrailingObjects;
198+
199+
#if !defined(_MSC_VER) || _MSC_VER >= 1920
200+
template<typename T>
201+
using OverloadToken = typename TrailingObjects::template OverloadToken<T>;
202+
#else
203+
// MSVC 2017 trips parsing an using of an using, of a variadic template
204+
#define OverloadToken typename TrailingObjects::template OverloadToken
205+
#endif
206+
207+
size_t numTrailingObjects(OverloadToken<uint16_t>) const {
208+
return Flags.getNumGenericParameterLevels();
209+
}
210+
211+
size_t numTrailingObjects(OverloadToken<GenericParamDescriptor>) const {
212+
return getGenericParameterCounts().back();
213+
}
214+
215+
size_t numTrailingObjects(OverloadToken<GenericRequirementDescriptor>) const {
216+
return Flags.getNumGenericRequirements();
217+
}
218+
219+
#if defined(_MSC_VER) && _MSC_VER < 1920
220+
#undef OverloadToken
221+
#endif
222+
223+
GenericEnvironmentFlags Flags;
224+
225+
public:
226+
/// Retrieve the cumulative generic parameter counts at each level of genericity.
227+
llvm::ArrayRef<uint16_t> getGenericParameterCounts() const {
228+
return llvm::makeArrayRef(this->template getTrailingObjects<uint16_t>(),
229+
Flags.getNumGenericParameterLevels());
230+
}
231+
232+
/// Retrieve the generic parameters descriptors.
233+
llvm::ArrayRef<GenericParamDescriptor> getGenericParameters() const {
234+
return llvm::makeArrayRef(
235+
this->template getTrailingObjects<GenericParamDescriptor>(),
236+
getGenericParameterCounts().back());
237+
}
238+
239+
/// Retrieve the generic requirements.
240+
llvm::ArrayRef<GenericRequirementDescriptor> getGenericRequirements() const {
241+
return llvm::makeArrayRef(
242+
this->template getTrailingObjects<GenericRequirementDescriptor>(),
243+
Flags.getNumGenericRequirements());
244+
}
245+
};
246+
247+
using GenericEnvironmentDescriptor = TargetGenericEnvironment<InProcess>;
248+
249+
/// CRTP class for a context descriptor that includes trailing generic
250+
/// context description.
251+
template<class Self,
252+
template <typename> class TargetGenericContextHeaderType =
253+
TargetGenericContextDescriptorHeader,
254+
typename... FollowingTrailingObjects>
255+
class TrailingGenericContextObjects;
256+
257+
// This oddity with partial specialization is necessary to get
258+
// reasonable-looking code while also working around various kinds of
259+
// compiler bad behavior with injected class names.
260+
template<class Runtime,
261+
template <typename> class TargetSelf,
262+
template <typename> class TargetGenericContextHeaderType,
263+
typename... FollowingTrailingObjects>
264+
class TrailingGenericContextObjects<TargetSelf<Runtime>,
265+
TargetGenericContextHeaderType,
266+
FollowingTrailingObjects...> :
267+
protected swift::ABI::TrailingObjects<TargetSelf<Runtime>,
268+
TargetGenericContextHeaderType<Runtime>,
269+
GenericParamDescriptor,
270+
TargetGenericRequirementDescriptor<Runtime>,
271+
FollowingTrailingObjects...>
272+
{
273+
protected:
274+
using Self = TargetSelf<Runtime>;
275+
using GenericContextHeaderType = TargetGenericContextHeaderType<Runtime>;
276+
using GenericRequirementDescriptor =
277+
TargetGenericRequirementDescriptor<Runtime>;
278+
279+
using TrailingObjects = swift::ABI::TrailingObjects<Self,
280+
GenericContextHeaderType,
281+
GenericParamDescriptor,
282+
GenericRequirementDescriptor,
283+
FollowingTrailingObjects...>;
284+
friend TrailingObjects;
285+
286+
#if !defined(_MSC_VER) || _MSC_VER >= 1920
287+
template<typename T>
288+
using OverloadToken = typename TrailingObjects::template OverloadToken<T>;
289+
#else
290+
// MSVC 2017 trips parsing an using of an using, of a variadic template
291+
#define OverloadToken typename TrailingObjects::template OverloadToken
292+
#endif
293+
294+
const Self *asSelf() const {
295+
return static_cast<const Self *>(this);
296+
}
297+
public:
298+
using StoredSize = typename Runtime::StoredSize;
299+
using StoredPointer = typename Runtime::StoredPointer;
300+
301+
const GenericContextHeaderType &getFullGenericContextHeader() const {
302+
assert(asSelf()->isGeneric());
303+
return *this->template getTrailingObjects<GenericContextHeaderType>();
304+
}
305+
306+
const TargetGenericContextDescriptorHeader<Runtime> &
307+
getGenericContextHeader() const {
308+
/// HeaderType ought to be convertible to GenericContextDescriptorHeader.
309+
return getFullGenericContextHeader();
310+
}
311+
312+
const TargetGenericContext<Runtime> *getGenericContext() const {
313+
if (!asSelf()->isGeneric())
314+
return nullptr;
315+
// The generic context header should always be immediately followed in
316+
// memory by trailing parameter and requirement descriptors.
317+
auto *header = reinterpret_cast<const char *>(&getGenericContextHeader());
318+
return reinterpret_cast<const TargetGenericContext<Runtime> *>(
319+
header - sizeof(TargetGenericContext<Runtime>));
320+
}
321+
322+
llvm::ArrayRef<GenericParamDescriptor> getGenericParams() const {
323+
if (!asSelf()->isGeneric())
324+
return {};
325+
326+
return {this->template getTrailingObjects<GenericParamDescriptor>(),
327+
getGenericContextHeader().NumParams};
328+
}
329+
330+
llvm::ArrayRef<GenericRequirementDescriptor> getGenericRequirements() const {
331+
if (!asSelf()->isGeneric())
332+
return {};
333+
return {this->template getTrailingObjects<GenericRequirementDescriptor>(),
334+
getGenericContextHeader().NumRequirements};
335+
}
336+
337+
/// Return the amount of space that the generic arguments take up in
338+
/// metadata of this type.
339+
StoredSize getGenericArgumentsStorageSize() const {
340+
return StoredSize(getGenericContextHeader().getNumArguments())
341+
* sizeof(StoredPointer);
342+
}
343+
344+
protected:
345+
size_t numTrailingObjects(OverloadToken<GenericContextHeaderType>) const {
346+
return asSelf()->isGeneric() ? 1 : 0;
347+
}
348+
349+
size_t numTrailingObjects(OverloadToken<GenericParamDescriptor>) const {
350+
return asSelf()->isGeneric() ? getGenericContextHeader().NumParams : 0;
351+
}
352+
353+
size_t numTrailingObjects(OverloadToken<GenericRequirementDescriptor>) const {
354+
return asSelf()->isGeneric() ? getGenericContextHeader().NumRequirements : 0;
355+
}
356+
357+
#if defined(_MSC_VER) && _MSC_VER < 1920
358+
#undef OverloadToken
359+
#endif
360+
361+
};
362+
363+
/// Description of a generic context.
364+
template<typename Runtime>
365+
struct TargetGenericContext final
366+
: TrailingGenericContextObjects<TargetGenericContext<Runtime>,
367+
TargetGenericContextDescriptorHeader>
368+
{
369+
// This struct is supposed to be empty, but TrailingObjects respects the
370+
// unique-address-per-object C++ rule, so even if this type is empty, the
371+
// trailing objects will come after one byte of padding. This dummy field
372+
// takes up space to make the offset of the trailing objects portable.
373+
unsigned _dummy;
374+
375+
bool isGeneric() const { return true; }
376+
};
377+
378+
} // end namespace swift
379+
380+
#endif

0 commit comments

Comments
 (0)