Skip to content

Commit 3ce1ba3

Browse files
committed
Only store the minimal requirements in generic metadata, where
"minimal" is defined as the set of requirements that would be passed to a function with the type's generic signature that takes the thick metadata of the parent type as its only argument.
1 parent 66b0b57 commit 3ce1ba3

26 files changed

+1121
-737
lines changed

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

+57
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,63 @@ enum class ProtocolDispatchStrategy: uint8_t {
237237
Empty = 2,
238238
};
239239

240+
/// Flags in a generic nominal type descriptor.
241+
class GenericParameterDescriptorFlags {
242+
typedef uint32_t int_type;
243+
enum : int_type {
244+
HasParent = 0x01,
245+
HasGenericParent = 0x02,
246+
};
247+
int_type Data;
248+
249+
constexpr GenericParameterDescriptorFlags(int_type data) : Data(data) {}
250+
public:
251+
constexpr GenericParameterDescriptorFlags() : Data(0) {}
252+
253+
constexpr GenericParameterDescriptorFlags withHasParent(bool b) const {
254+
return GenericParameterDescriptorFlags(b ? (Data | HasParent)
255+
: (Data & ~HasParent));
256+
}
257+
258+
constexpr GenericParameterDescriptorFlags withHasGenericParent(bool b) const {
259+
return GenericParameterDescriptorFlags(b ? (Data | HasGenericParent)
260+
: (Data & ~HasGenericParent));
261+
}
262+
263+
/// Does this type have a lexical parent type?
264+
///
265+
/// For class metadata, if this is true, the storage for the parent type
266+
/// appears immediately prior to the first generic argument. Other
267+
/// metadata always have a slot for their parent type.
268+
bool hasParent() const {
269+
return Data & HasParent;
270+
}
271+
272+
/// Given that this type has a parent type, is that type generic? If so,
273+
/// it forms part of the key distinguishing this metadata from other
274+
/// metadata, and the parent metadata will be the first argument to
275+
/// the generic metadata access function.
276+
bool hasGenericParent() const {
277+
return Data & HasGenericParent;
278+
}
279+
280+
int_type getIntValue() const {
281+
return Data;
282+
}
283+
284+
static GenericParameterDescriptorFlags fromIntValue(int_type Data) {
285+
return GenericParameterDescriptorFlags(Data);
286+
}
287+
288+
bool operator==(GenericParameterDescriptorFlags other) const {
289+
return Data == other.Data;
290+
}
291+
bool operator!=(GenericParameterDescriptorFlags other) const {
292+
return Data != other.Data;
293+
}
294+
};
295+
296+
240297
/// Flags for protocol descriptors.
241298
class ProtocolDescriptorFlags {
242299
typedef uint32_t int_type;

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

+40-28
Original file line numberDiff line numberDiff line change
@@ -1208,34 +1208,37 @@ struct HeapMetadata : Metadata {
12081208
/// structure that describes how to find and parse a generic parameter vector
12091209
/// within the type metadata for an instance of a nominal type.
12101210
struct GenericParameterDescriptor {
1211-
/// The offset of the descriptor in the metadata record. If NumParams is zero,
1212-
/// this value is meaningless.
1211+
/// The offset of the descriptor in the metadata record. This is
1212+
/// meaningful if either NumGenericRequirements is nonzero or
1213+
/// (for classes) if Flags.hasParent() is true.
12131214
uint32_t Offset;
1214-
/// The number of type parameters. A value of zero means there is no generic
1215-
/// parameter vector. This includes associated types of the primary type
1216-
/// parameters.
1217-
uint32_t NumParams;
1215+
1216+
/// The amount of generic requirement data in the metadata record, in
1217+
/// words, excluding the lexical parent type. A value of zero means
1218+
/// there is no generic requirement data.
1219+
///
1220+
/// This may include protocol witness tables for type parameters or
1221+
/// their associated types.
1222+
uint32_t NumGenericRequirements;
1223+
12181224
/// The number of primary type parameters. This is always less than or equal
1219-
/// to NumParams; it counts only the primary type parameters and not their
1220-
/// associated types.
1225+
/// to NumGenericRequirements; it counts only the type parameters
1226+
/// and not any required witness tables.
12211227
uint32_t NumPrimaryParams;
1222-
1223-
/// True if the nominal type has generic parameters.
1224-
bool hasGenericParams() const { return NumParams > 0; }
1225-
1226-
/// A type parameter.
1227-
struct Parameter {
1228-
/// The number of protocol witness tables required by this type parameter.
1229-
uint32_t NumWitnessTables;
1230-
1231-
// TODO: This is the bare minimum to be able to parse an opaque generic
1232-
// parameter vector. Should we include additional info, such as the
1233-
// required protocols?
1234-
};
12351228

1236-
/// The parameter descriptors are in a tail-emplaced array of NumParams
1237-
/// elements.
1238-
Parameter Parameters[1];
1229+
/// Flags for this generic parameter descriptor.
1230+
GenericParameterDescriptorFlags Flags;
1231+
1232+
/// True if the nominal type has generic requirements other than its
1233+
/// parent metadata.
1234+
bool hasGenericRequirements() const { return NumGenericRequirements > 0; }
1235+
1236+
/// True if the nominal type is generic in any way.
1237+
bool isGeneric() const {
1238+
return hasGenericRequirements() || Flags.hasGenericParent();
1239+
}
1240+
1241+
// TODO: add meaningful descriptions of the generic requirements.
12391242
};
12401243

12411244
struct ClassTypeDescriptor;
@@ -1566,6 +1569,16 @@ struct ClassMetadata : public HeapMetadata {
15661569
return getter(this);
15671570
}
15681571

1572+
/// Return the parent type for a given level in the class hierarchy, or
1573+
/// null if that level does not have a parent type.
1574+
const Metadata *getParentType(const NominalTypeDescriptor *theClass) const {
1575+
if (!theClass->GenericParams.Flags.hasParent())
1576+
return nullptr;
1577+
1578+
auto metadataAsWords = reinterpret_cast<const Metadata * const *>(this);
1579+
return metadataAsWords[theClass->GenericParams.Offset - 1];
1580+
}
1581+
15691582
static bool classof(const Metadata *metadata) {
15701583
return metadata->getKind() == MetadataKind::Class;
15711584
}
@@ -1739,12 +1752,11 @@ struct ValueMetadata : public Metadata {
17391752

17401753
/// Retrieve the generic arguments of this type.
17411754
const Metadata * const *getGenericArgs() const {
1742-
if (Description->GenericParams.NumParams == 0)
1755+
if (!Description->GenericParams.hasGenericRequirements())
17431756
return nullptr;
17441757

1745-
const void* const *asWords = reinterpret_cast<const void * const *>(this);
1746-
asWords += Description->GenericParams.Offset;
1747-
return reinterpret_cast<const Metadata * const *>(asWords);
1758+
auto asWords = reinterpret_cast<const Metadata * const *>(this);
1759+
return (asWords + Description->GenericParams.Offset);
17481760
}
17491761
};
17501762

Diff for: lib/IRGen/ClassMetadataLayout.h

+7-19
Original file line numberDiff line numberDiff line change
@@ -73,23 +73,23 @@ template <class Impl> class ClassMetadataLayout : public MetadataLayout<Impl> {
7373
asImpl().addIVarDestroyer();
7474

7575
// Class members.
76-
addClassMembers(Target);
76+
addClassMembers(Target, Target->getDeclaredTypeInContext());
7777
}
7878

7979
private:
8080
/// Add fields associated with the given class and its bases.
81-
void addClassMembers(ClassDecl *theClass) {
81+
void addClassMembers(ClassDecl *theClass, Type type) {
8282
// Add any fields associated with the superclass.
8383
// NB: We don't apply superclass substitutions to members because we want
8484
// consistent metadata layout between generic superclasses and concrete
8585
// subclasses.
86-
if (Type superclass = theClass->getSuperclass()) {
86+
if (Type superclass = type->getSuperclass(nullptr)) {
8787
ClassDecl *superclassDecl = superclass->getClassOrBoundGenericClass();
8888
// Skip superclass fields if superclass is resilient.
8989
// FIXME: Needs runtime support to ensure the field offset vector is
9090
// populated correctly.
9191
if (!IGM.isResilient(superclassDecl, ResilienceExpansion::Maximal)) {
92-
addClassMembers(superclass->getClassOrBoundGenericClass());
92+
addClassMembers(superclassDecl, superclass);
9393
}
9494
}
9595

@@ -101,9 +101,7 @@ template <class Impl> class ClassMetadataLayout : public MetadataLayout<Impl> {
101101
// Add space for the generic parameters, if applicable.
102102
// Note that we only add references for the immediate parameters;
103103
// parameters for the parent context are handled by the parent.
104-
if (auto generics = theClass->getGenericParams()) {
105-
addGenericClassFields(theClass, *generics);
106-
}
104+
asImpl().addGenericFields(theClass, type, theClass);
107105

108106
// Add entries for the methods.
109107
for (auto member : theClass->getMembers()) {
@@ -177,15 +175,6 @@ template <class Impl> class ClassMetadataLayout : public MetadataLayout<Impl> {
177175
void noteEndOfFieldOffsets(ClassDecl *whichClass) {}
178176

179177
private:
180-
/// Add fields related to the generics of this class declaration.
181-
/// TODO: don't add new fields that are implied by the superclass.
182-
/// fields. e.g., if B<T> extends A<T>, the witness for T in A's
183-
/// section should be enough.
184-
void addGenericClassFields(ClassDecl *theClass,
185-
const GenericParamList &generics) {
186-
asImpl().addGenericFields(generics, theClass);
187-
}
188-
189178
void addFieldEntries(VarDecl *field) {
190179
asImpl().addFieldOffset(field);
191180
}
@@ -258,11 +247,10 @@ class ClassMetadataScanner : public ClassMetadataLayout<Impl> {
258247
addPointer();
259248
}
260249
void addFieldOffset(VarDecl *var) { addPointer(); }
261-
void addGenericArgument(ArchetypeType *argument, ClassDecl *forClass) {
250+
void addGenericArgument(CanType argument, ClassDecl *forClass) {
262251
addPointer();
263252
}
264-
void addGenericWitnessTable(ArchetypeType *argument,
265-
ProtocolDecl *protocol,
253+
void addGenericWitnessTable(CanType argument, ProtocolConformanceRef conf,
266254
ClassDecl *forClass) {
267255
addPointer();
268256
}

Diff for: lib/IRGen/EnumMetadataLayout.h

+3-5
Original file line numberDiff line numberDiff line change
@@ -60,8 +60,7 @@ template <class Impl> class EnumMetadataLayout : public MetadataLayout<Impl> {
6060
asImpl().addPayloadSize();
6161

6262
// Add fields for generic cases.
63-
if (auto generics = Target->getGenericParamsOfContext())
64-
asImpl().addGenericFields(*generics);
63+
asImpl().addGenericFields(Target, Target->getDeclaredTypeInContext());
6564
}
6665
};
6766

@@ -82,9 +81,8 @@ class EnumMetadataScanner : public EnumMetadataLayout<Impl> {
8281
void addValueWitnessTable() { addPointer(); }
8382
void addNominalTypeDescriptor() { addPointer(); }
8483
void addParentMetadataRef() { addPointer(); }
85-
void addGenericArgument(ArchetypeType *argument) { addPointer(); }
86-
void addGenericWitnessTable(ArchetypeType *argument,
87-
ProtocolDecl *protocol) {
84+
void addGenericArgument(CanType argument) { addPointer(); }
85+
void addGenericWitnessTable(CanType argument, ProtocolConformanceRef conf) {
8886
addPointer();
8987
}
9088
void addPayloadSize() { addPointer(); }

0 commit comments

Comments
 (0)