Skip to content

Commit 65dd0e7

Browse files
committed
Protocol conformances can now reference resilient value types
Change conformance records to reference NominalTypeDescriptors instead of metadata patterns for resilient or generic types. For a resilient type, we don't know if the metadata is constant or not, so we can't directly reference either constant metadata or the metadata template. Also, whereas previously NominalTypeDescriptors would point to the metadata pattern, they now point to the metadata accessor function. This allows the recently-added logic for instantiating concrete types by name to continue working. In turn, swift_initClassMetadata_UniversalStrategy() would reach into the NominalTypeDescriptor to get the pattern out, so that its bump allocator could be used to allocate ivar tables. Since the pattern is no longer available this way, we have to pass it in as a parameter. In the future, we will split off the read-write metadata cache entry from the pattern; then swift_initClassMetadata_UniversalStrategy() can just take a pointer to that, since it doesn't actually need anything else from the pattern. Since Clang doesn't guarantee alignment for function pointers, I had to kill the cute trick that packed the NominalTypeKind into the low bits of the relative pointer to the pattern; instead the kind is now stored out of line. We could fix this by packing it with some other field, or keep it this way in case we add new flags later. Now that generic metadata is instantiated by calling accessor functions, this change removes the last remaining place that metadata patterns were referenced from outside the module they were defined in. Now, the layout of the metadata pattern and the behavior of swift_getGenericMetadata() is purely an implementation detail of generic metadata accessors. This patch allows two previously-XFAIL'd tests to pass.
1 parent f439a9d commit 65dd0e7

20 files changed

+264
-192
lines changed

include/swift/ABI/MetadataValues.h

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ enum class MetadataKind : uintptr_t {
3838
};
3939

4040
/// Kinds of Swift nominal type descriptor records.
41-
enum class NominalTypeKind : uintptr_t {
41+
enum class NominalTypeKind : unsigned {
4242
#define NOMINALTYPEMETADATAKIND(name, value) name = value,
4343
#include "MetadataKind.def"
4444
};
@@ -167,10 +167,10 @@ enum class TypeMetadataRecordKind : unsigned {
167167
/// and classes could be emitted as UniqueDirectType.
168168
UniqueIndirectClass,
169169

170-
/// The conformance is for a generic type.
171-
/// getGenericPattern() points to the generic metadata pattern used to
172-
/// form instances of the type.
173-
UniqueGenericPattern,
170+
/// The conformance is for a generic or resilient type.
171+
/// getNominalTypeDescriptor() points to the nominal type descriptor shared
172+
/// by all metadata instantiations of this type.
173+
UniqueNominalTypeDescriptor,
174174

175175
/// The conformance is for a nongeneric class type.
176176
/// getDirectType() points to the unique class object.

include/swift/Runtime/Metadata.h

Lines changed: 25 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1105,11 +1105,7 @@ struct Metadata {
11051105
/// Get the nominal type descriptor if this metadata describes a nominal type,
11061106
/// or return null if it does not.
11071107
const NominalTypeDescriptor *getNominalTypeDescriptor() const;
1108-
1109-
/// Get the generic metadata pattern from which this generic type instance was
1110-
/// instantiated, or null if the type is not generic.
1111-
const GenericMetadata *getGenericPattern() const;
1112-
1108+
11131109
/// Get the class object for this type if it has one, or return null if the
11141110
/// type is not a class (or not a class with a class object).
11151111
const ClassMetadata *getClassObject() const;
@@ -1309,20 +1305,15 @@ struct NominalTypeDescriptor {
13091305
}
13101306
} Enum;
13111307
};
1312-
1313-
RelativeDirectPointerIntPair<GenericMetadata, NominalTypeKind>
1314-
GenericMetadataPatternAndKind;
13151308

1316-
/// A pointer to the generic metadata pattern that is used to instantiate
1317-
/// instances of this type. Zero if the type is not generic.
1318-
GenericMetadata *getGenericMetadataPattern() const {
1319-
return const_cast<GenericMetadata*>(
1320-
GenericMetadataPatternAndKind.getPointer());
1321-
}
1309+
using MetadataAccessor = const Metadata *();
13221310

1323-
NominalTypeKind getKind() const {
1324-
return GenericMetadataPatternAndKind.getInt();
1325-
}
1311+
/// A pointer to the metadata accessor function that is used to instantiate
1312+
/// instances of this type. Zero if the type is not resilient or generic.
1313+
RelativeDirectPointer<MetadataAccessor> MetadataAccessorFn;
1314+
1315+
/// The kind of type described by this nominal type descriptor.
1316+
NominalTypeKind Kind;
13261317

13271318
/// The generic parameter descriptor header. This describes how to find and
13281319
/// parse the generic parameter vector in metadata records for this nominal
@@ -2172,7 +2163,7 @@ struct TypeMetadataRecord {
21722163
RelativeDirectPointer<Metadata> DirectType;
21732164

21742165
/// The generic metadata pattern for an unbound generic type.
2175-
RelativeDirectPointer<GenericMetadata> GenericPattern;
2166+
RelativeDirectPointer<NominalTypeDescriptor> TypeDescriptor;
21762167
};
21772168

21782169
/// Flags describing the type metadata record.
@@ -2194,19 +2185,19 @@ struct TypeMetadataRecord {
21942185
break;
21952186

21962187
case TypeMetadataRecordKind::UniqueIndirectClass:
2197-
case TypeMetadataRecordKind::UniqueGenericPattern:
2188+
case TypeMetadataRecordKind::UniqueNominalTypeDescriptor:
21982189
assert(false && "not direct type metadata");
21992190
}
22002191

22012192
return DirectType;
22022193
}
2203-
2204-
const GenericMetadata *getGenericPattern() const {
2194+
2195+
const NominalTypeDescriptor *getNominalTypeDescriptor() const {
22052196
switch (Flags.getTypeKind()) {
22062197
case TypeMetadataRecordKind::Universal:
22072198
return nullptr;
22082199

2209-
case TypeMetadataRecordKind::UniqueGenericPattern:
2200+
case TypeMetadataRecordKind::UniqueNominalTypeDescriptor:
22102201
break;
22112202

22122203
case TypeMetadataRecordKind::UniqueDirectClass:
@@ -2216,9 +2207,9 @@ struct TypeMetadataRecord {
22162207
assert(false && "not generic metadata pattern");
22172208
}
22182209

2219-
return GenericPattern;
2210+
return TypeDescriptor;
22202211
}
2221-
2212+
22222213
/// Get the canonical metadata for the type referenced by this record, or
22232214
/// return null if the record references a generic or universal type.
22242215
const Metadata *getCanonicalTypeMetadata() const;
@@ -2290,9 +2281,9 @@ struct ProtocolConformanceRecord {
22902281
/// An indirect reference to the metadata.
22912282
RelativeIndirectablePointer<const ClassMetadata *> IndirectClass;
22922283

2293-
/// The generic metadata pattern for a generic type which has instances that
2294-
/// conform to the protocol.
2295-
RelativeIndirectablePointer<GenericMetadata> GenericPattern;
2284+
/// The nominal type descriptor for a resilient or generic type which has
2285+
/// instances that conform to the protocol.
2286+
RelativeIndirectablePointer<NominalTypeDescriptor> TypeDescriptor;
22962287
};
22972288

22982289

@@ -2337,7 +2328,7 @@ struct ProtocolConformanceRecord {
23372328

23382329
case TypeMetadataRecordKind::UniqueDirectClass:
23392330
case TypeMetadataRecordKind::UniqueIndirectClass:
2340-
case TypeMetadataRecordKind::UniqueGenericPattern:
2331+
case TypeMetadataRecordKind::UniqueNominalTypeDescriptor:
23412332
assert(false && "not direct type metadata");
23422333
}
23432334

@@ -2354,7 +2345,7 @@ struct ProtocolConformanceRecord {
23542345

23552346
case TypeMetadataRecordKind::UniqueDirectType:
23562347
case TypeMetadataRecordKind::NonuniqueDirectType:
2357-
case TypeMetadataRecordKind::UniqueGenericPattern:
2348+
case TypeMetadataRecordKind::UniqueNominalTypeDescriptor:
23582349
case TypeMetadataRecordKind::UniqueIndirectClass:
23592350
assert(false && "not direct class object");
23602351
}
@@ -2375,19 +2366,19 @@ struct ProtocolConformanceRecord {
23752366
case TypeMetadataRecordKind::UniqueDirectType:
23762367
case TypeMetadataRecordKind::UniqueDirectClass:
23772368
case TypeMetadataRecordKind::NonuniqueDirectType:
2378-
case TypeMetadataRecordKind::UniqueGenericPattern:
2369+
case TypeMetadataRecordKind::UniqueNominalTypeDescriptor:
23792370
assert(false && "not indirect class object");
23802371
}
23812372

23822373
return IndirectClass;
23832374
}
23842375

2385-
const GenericMetadata *getGenericPattern() const {
2376+
const NominalTypeDescriptor *getNominalTypeDescriptor() const {
23862377
switch (Flags.getTypeKind()) {
23872378
case TypeMetadataRecordKind::Universal:
23882379
return nullptr;
23892380

2390-
case TypeMetadataRecordKind::UniqueGenericPattern:
2381+
case TypeMetadataRecordKind::UniqueNominalTypeDescriptor:
23912382
break;
23922383

23932384
case TypeMetadataRecordKind::UniqueDirectClass:
@@ -2397,7 +2388,7 @@ struct ProtocolConformanceRecord {
23972388
assert(false && "not generic metadata pattern");
23982389
}
23992390

2400-
return GenericPattern;
2391+
return TypeDescriptor;
24012392
}
24022393

24032394
/// Get the directly-referenced static witness table.
@@ -2645,6 +2636,7 @@ struct ClassFieldLayout {
26452636
/// Initialize the field offset vector for a dependent-layout class, using the
26462637
/// "Universal" layout strategy.
26472638
extern "C" void swift_initClassMetadata_UniversalStrategy(ClassMetadata *self,
2639+
GenericMetadata *pattern,
26482640
size_t numFields,
26492641
const ClassFieldLayout *fieldLayouts,
26502642
size_t *fieldOffsets);

lib/IRGen/GenDecl.cpp

Lines changed: 5 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1861,19 +1861,11 @@ getTypeEntityInfo(IRGenModule &IGM, CanType conformingType) {
18611861
if (IGM.hasMetadataPattern(nom)) {
18621862
// Conformances for generics, concrete subclasses of generics, and
18631863
// resiliently-sized types are represented by referencing the
1864-
// metadata pattern.
1865-
//
1866-
// FIXME: this is wrong if the conforming type is a resilient type from
1867-
// another module. In that case, we don't know if we require runtime
1868-
// metadata instantiation or not, and instead, we need a way to reference
1869-
// the metadata accessor function from the conformance table.
1870-
typeKind = TypeMetadataRecordKind::UniqueGenericPattern;
1871-
entity = LinkEntity::forTypeMetadata(
1872-
nom->getDeclaredType()->getCanonicalType(),
1873-
TypeMetadataAddress::AddressPoint,
1874-
/*isPattern*/ true);
1875-
defaultTy = IGM.TypeMetadataPatternStructTy;
1876-
defaultPtrTy = IGM.TypeMetadataPatternPtrTy;
1864+
// nominal type descriptor.
1865+
typeKind = TypeMetadataRecordKind::UniqueNominalTypeDescriptor;
1866+
entity = LinkEntity::forNominalTypeDescriptor(nom);
1867+
defaultTy = IGM.NominalTypeDescriptorTy;
1868+
defaultPtrTy = IGM.NominalTypeDescriptorPtrTy;
18771869
} else if (auto ct = dyn_cast<ClassType>(conformingType)) {
18781870
auto clas = ct->getDecl();
18791871
if (clas->isForeign()) {

lib/IRGen/GenMeta.cpp

Lines changed: 31 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2031,7 +2031,8 @@ namespace {
20312031
void layout() {
20322032
asImpl().addName();
20332033
asImpl().addKindDependentFields();
2034-
asImpl().addGenericMetadataPatternAndKind();
2034+
asImpl().addMetadataAccessorFn();
2035+
asImpl().addNominalTypeKind();
20352036
asImpl().addGenericParams();
20362037
}
20372038

@@ -2041,20 +2042,32 @@ namespace {
20412042
ntd->getDeclaredType()->getCanonicalType(),
20422043
/*willBeRelativelyAddressed*/ true));
20432044
}
2044-
2045-
void addGenericMetadataPatternAndKind() {
2045+
2046+
void addMetadataAccessorFn() {
20462047
NominalTypeDecl *ntd = asImpl().getTarget();
2047-
auto kind = asImpl().getKind();
2048-
if (!IGM.hasMetadataPattern(ntd)) {
2049-
// There's no pattern to link.
2050-
addConstantInt32(kind);
2048+
2049+
// If the type has constant metadata and this is known to be the case
2050+
// from all resilience domains that can access it, don't link the
2051+
// accessor.
2052+
if (!IGM.isResilient(ntd, IGM.getResilienceExpansionForAccess(ntd)) &&
2053+
!IGM.hasMetadataPattern(ntd)) {
2054+
addConstantInt32(asImpl().getKind());
20512055
return;
20522056
}
20532057

2054-
addRelativeAddressWithTag(
2055-
IGM.getAddrOfTypeMetadata(ntd->getDeclaredType()->getCanonicalType(),
2056-
/*pattern*/ true),
2057-
kind);
2058+
llvm::Function *fn;
2059+
if (ntd->isGenericContext()) {
2060+
fn = getGenericTypeMetadataAccessFunction(IGM, ntd, NotForDefinition);
2061+
} else {
2062+
CanType declaredType = ntd->getDeclaredType()->getCanonicalType();
2063+
fn = getTypeMetadataAccessFunction(IGM, declaredType, NotForDefinition);
2064+
}
2065+
2066+
addRelativeAddress(fn);
2067+
}
2068+
2069+
void addNominalTypeKind() {
2070+
addConstantInt32(asImpl().getKind());
20582071
}
20592072

20602073
void addGenericParams() {
@@ -2894,7 +2907,8 @@ namespace {
28942907
}
28952908

28962909
if (HasDependentMetadata) {
2897-
asImpl().emitInitializeMetadata(IGF, metadataValue, vwtableValue);
2910+
asImpl().emitInitializeMetadata(IGF, metadataValue, metadataPattern,
2911+
vwtableValue);
28982912
}
28992913

29002914
// The metadata is now complete.
@@ -3565,6 +3579,7 @@ namespace {
35653579

35663580
void emitInitializeMetadata(IRGenFunction &IGF,
35673581
llvm::Value *metadata,
3582+
llvm::Value *pattern,
35683583
llvm::Value *vwtable) {
35693584
assert(!HasDependentVWT && "class should never have dependent VWT");
35703585

@@ -3707,7 +3722,7 @@ namespace {
37073722
// Ask the runtime to lay out the class.
37083723
auto numFields = IGF.IGM.getSize(Size(storedProperties.size()));
37093724
IGF.Builder.CreateCall(IGF.IGM.getInitClassMetadataUniversalFn(),
3710-
{metadata, numFields,
3725+
{metadata, pattern, numFields,
37113726
firstField.getAddress(), fieldVector});
37123727
IGF.Builder.CreateLifetimeEnd(fields,
37133728
IGF.IGM.getPointerSize() * storedProperties.size() * 2);
@@ -4613,10 +4628,11 @@ namespace {
46134628

46144629
void emitInitializeMetadata(IRGenFunction &IGF,
46154630
llvm::Value *metadata,
4631+
llvm::Value *pattern,
46164632
llvm::Value *vwtable) {
46174633
// Nominal types are always preserved through SIL lowering.
46184634
auto structTy = Target->getDeclaredTypeInContext()->getCanonicalType();
4619-
IGM.getTypeInfoForLowered(CanType(Target->getDeclaredTypeInContext()))
4635+
IGM.getTypeInfoForLowered(structTy)
46204636
.initializeMetadata(IGF, metadata, vwtable,
46214637
SILType::getPrimitiveAddressType(structTy));
46224638
}
@@ -4761,6 +4777,7 @@ class GenericEnumMetadataBuilder
47614777

47624778
void emitInitializeMetadata(IRGenFunction &IGF,
47634779
llvm::Value *metadata,
4780+
llvm::Value *pattern,
47644781
llvm::Value *vwtable) {
47654782
// Nominal types are always preserved through SIL lowering.
47664783
auto enumTy = Target->getDeclaredTypeInContext()->getCanonicalType();

lib/IRGen/IRGenModule.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -278,6 +278,11 @@ IRGenModule::IRGenModule(IRGenModuleDispatcher &dispatcher, SourceFile *SF,
278278
ProtocolConformanceRecordPtrTy
279279
= ProtocolConformanceRecordTy->getPointerTo(DefaultAS);
280280

281+
NominalTypeDescriptorTy
282+
= llvm::StructType::create(LLVMContext, "swift.type_descriptor");
283+
NominalTypeDescriptorPtrTy
284+
= NominalTypeDescriptorTy->getPointerTo(DefaultAS);
285+
281286
TypeMetadataRecordTy
282287
= createStructType(*this, "swift.type_metadata_record", {
283288
RelativeAddressTy,

lib/IRGen/IRGenModule.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -389,6 +389,8 @@ class IRGenModule {
389389
llvm::PointerType *ObjCBlockPtrTy; /// %objc_block*
390390
llvm::StructType *ProtocolConformanceRecordTy;
391391
llvm::PointerType *ProtocolConformanceRecordPtrTy;
392+
llvm::StructType *NominalTypeDescriptorTy;
393+
llvm::PointerType *NominalTypeDescriptorPtrTy;
392394
llvm::StructType *TypeMetadataRecordTy;
393395
llvm::PointerType *TypeMetadataRecordPtrTy;
394396
llvm::StructType *FieldDescriptorTy;

lib/IRGen/RuntimeFunctions.def

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -573,13 +573,16 @@ FUNCTION(GetExistentialMetadata,
573573

574574
// struct FieldInfo { size_t Size; size_t AlignMask; };
575575
// void swift_initClassMetadata_UniversalStrategy(Metadata *self,
576+
// GenericMetadata *pattern,
576577
// size_t numFields,
577578
// const FieldInfo *fields,
578579
// size_t *fieldOffsets);
579580
FUNCTION(InitClassMetadataUniversal,
580581
swift_initClassMetadata_UniversalStrategy, RuntimeCC,
581582
RETURNS(VoidTy),
582-
ARGS(TypeMetadataPtrTy, SizeTy,
583+
ARGS(TypeMetadataPtrTy,
584+
TypeMetadataPatternPtrTy,
585+
SizeTy,
583586
SizeTy->getPointerTo(),
584587
SizeTy->getPointerTo()),
585588
ATTRS(NoUnwind))

stdlib/public/runtime/Metadata.cpp

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1504,6 +1504,7 @@ static void _swift_initializeSuperclass(ClassMetadata *theClass,
15041504
/// Initialize the field offset vector for a dependent-layout class, using the
15051505
/// "Universal" layout strategy.
15061506
void swift::swift_initClassMetadata_UniversalStrategy(ClassMetadata *self,
1507+
GenericMetadata *pattern,
15071508
size_t numFields,
15081509
const ClassFieldLayout *fieldLayouts,
15091510
size_t *fieldOffsets) {
@@ -1596,9 +1597,7 @@ void swift::swift_initClassMetadata_UniversalStrategy(ClassMetadata *self,
15961597
// even if Swift doesn't, because of SwiftObject.)
15971598
rodata->InstanceStart = size;
15981599

1599-
auto &allocator = unsafeGetInitializedCache(
1600-
self->getDescription()->getGenericMetadataPattern())
1601-
.getAllocator();
1600+
auto &allocator = unsafeGetInitializedCache(pattern).getAllocator();
16021601

16031602
// Always clone the ivar descriptors.
16041603
if (numFields) {
@@ -2385,14 +2384,6 @@ Metadata::getNominalTypeDescriptor() const {
23852384
}
23862385
}
23872386

2388-
const GenericMetadata *
2389-
Metadata::getGenericPattern() const {
2390-
auto ntd = getNominalTypeDescriptor();
2391-
if (!ntd)
2392-
return nullptr;
2393-
return ntd->getGenericMetadataPattern();
2394-
}
2395-
23962387
const ClassMetadata *
23972388
Metadata::getClassObject() const {
23982389
switch (getKind()) {

0 commit comments

Comments
 (0)