Skip to content

Commit 1df1653

Browse files
committed
IRGen: Clean up and fix lazy metadata emission for reflection
We were wastefully emitting an accessor if a field had a type, for example if my field type was (() -> (X, Array<Y>>) we would force the emission of a function to construct (() -> (X, Array<Y>)) even though all we care about is the type metadata for X and Y. Conversely, we would skip the field type if it contained an archetype, even if it otherwise contained metadata that we need to force to emit, for instance something like (T, X) where T is a generic parameter and X is a nominal type. A final side effect is we no longer try to emit type metadata for one-element tuples when emitting enum payload metadata, which is something I want to assert against.
1 parent dbac940 commit 1df1653

File tree

4 files changed

+34
-72
lines changed

4 files changed

+34
-72
lines changed

lib/IRGen/GenDecl.cpp

Lines changed: 0 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1099,30 +1099,8 @@ void IRGenerator::emitLazyDefinitions() {
10991099
while (!LazyTypeMetadata.empty() ||
11001100
!LazyTypeContextDescriptors.empty() ||
11011101
!LazyFunctionDefinitions.empty() ||
1102-
!LazyFieldTypes.empty() ||
11031102
!LazyWitnessTables.empty()) {
11041103

1105-
while (!LazyFieldTypes.empty()) {
1106-
auto info = LazyFieldTypes.pop_back_val();
1107-
auto &IGM = *info.IGM;
1108-
1109-
for (auto fieldType : info.fieldTypes) {
1110-
if (fieldType->hasArchetype())
1111-
continue;
1112-
1113-
// All of the required attributes are going to be preserved
1114-
// by field reflection metadata in the mangled name, so
1115-
// there is no need to worry about ownership semantics here.
1116-
if (auto refStorTy = dyn_cast<ReferenceStorageType>(fieldType))
1117-
fieldType = refStorTy.getReferentType();
1118-
1119-
// Make sure that all of the field type metadata is forced,
1120-
// otherwise there might be a problem when fields are accessed
1121-
// through reflection.
1122-
(void)irgen::getOrCreateTypeMetadataAccessFunction(IGM, fieldType);
1123-
}
1124-
}
1125-
11261104
// Emit any lazy type metadata we require.
11271105
while (!LazyTypeMetadata.empty()) {
11281106
NominalTypeDecl *type = LazyTypeMetadata.pop_back_val();

lib/IRGen/GenMeta.cpp

Lines changed: 9 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1198,37 +1198,6 @@ namespace {
11981198
}
11991199
return numFields;
12001200
}
1201-
1202-
/// Track the field types of a struct or class for reflection metadata
1203-
/// emission.
1204-
static void
1205-
addFieldTypes(IRGenModule &IGM, NominalTypeDecl *type,
1206-
NominalTypeDecl::StoredPropertyRange storedProperties) {
1207-
SmallVector<CanType, 4> types;
1208-
for (VarDecl *prop : storedProperties) {
1209-
auto propertyType = type->mapTypeIntoContext(prop->getInterfaceType())
1210-
->getCanonicalType();
1211-
types.push_back(propertyType);
1212-
}
1213-
1214-
IGM.addFieldTypes(types);
1215-
}
1216-
1217-
/// Track the payload types of an enum for reflection metadata
1218-
/// emission.
1219-
static void addFieldTypes(IRGenModule &IGM,
1220-
ArrayRef<EnumImplStrategy::Element> enumElements) {
1221-
SmallVector<CanType, 4> types;
1222-
1223-
for (auto &elt : enumElements) {
1224-
auto caseType = elt.decl->getParentEnum()->mapTypeIntoContext(
1225-
elt.decl->getArgumentInterfaceType())
1226-
->getCanonicalType();
1227-
types.push_back(caseType);
1228-
}
1229-
1230-
IGM.addFieldTypes(types);
1231-
}
12321201

12331202
class StructContextDescriptorBuilder
12341203
: public TypeContextDescriptorBuilderBase<StructContextDescriptorBuilder,
@@ -1264,7 +1233,9 @@ namespace {
12641233
// uint32_t FieldOffsetVectorOffset;
12651234
B.addInt32(FieldVectorOffset / IGM.getPointerSize());
12661235

1267-
addFieldTypes(IGM, getType(), properties);
1236+
// For any nominal type metadata required for reflection.
1237+
for (auto *prop : properties)
1238+
IGM.IRGen.noteUseOfTypeMetadata(prop->getValueInterfaceType());
12681239
}
12691240

12701241
uint16_t getKindSpecificFlags() {
@@ -1336,7 +1307,9 @@ namespace {
13361307
// uint32_t NumEmptyCases;
13371308
B.addInt32(Strategy.getElementsWithNoPayload().size());
13381309

1339-
addFieldTypes(IGM, Strategy.getElementsWithPayload());
1310+
// For any nominal type metadata required for reflection.
1311+
for (auto elt : Strategy.getElementsWithPayload())
1312+
IGM.IRGen.noteUseOfTypeMetadata(elt.decl->getArgumentInterfaceType());
13401313
}
13411314

13421315
uint16_t getKindSpecificFlags() {
@@ -1646,7 +1619,9 @@ namespace {
16461619
// uint32_t FieldOffsetVectorOffset;
16471620
B.addInt32(getFieldVectorOffset() / IGM.getPointerSize());
16481621

1649-
addFieldTypes(IGM, getType(), properties);
1622+
// For any nominal type metadata required for reflection.
1623+
for (auto *prop : properties)
1624+
IGM.IRGen.noteUseOfTypeMetadata(prop->getValueInterfaceType());
16501625
}
16511626
};
16521627
} // end anonymous namespace
@@ -1772,10 +1747,6 @@ IRGenModule::getAddrOfAnonymousContextDescriptor(DeclContext *DC,
17721747
[&]{ AnonymousContextDescriptorBuilder(*this, DC).emit(); });
17731748
}
17741749

1775-
void IRGenModule::addFieldTypes(ArrayRef<CanType> fieldTypes) {
1776-
IRGen.addFieldTypes(fieldTypes, this);
1777-
}
1778-
17791750
static void emitInitializeFieldOffsetVector(IRGenFunction &IGF,
17801751
SILType T,
17811752
llvm::Value *metadata,

lib/IRGen/IRGenModule.h

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -241,14 +241,6 @@ class IRGenerator {
241241

242242
llvm::SetVector<SILFunction*> DynamicReplacements;
243243

244-
struct FieldTypeMetadata {
245-
IRGenModule *IGM;
246-
std::vector<CanType> fieldTypes;
247-
};
248-
249-
/// Field types we need to verify are present.
250-
llvm::SmallVector<FieldTypeMetadata, 4> LazyFieldTypes;
251-
252244
/// SIL functions that we need to emit lazily.
253245
llvm::SmallVector<SILFunction*, 4> LazyFunctionDefinitions;
254246

@@ -367,6 +359,13 @@ class IRGenerator {
367359
noteUseOfTypeGlobals(type, true, RequireMetadata);
368360
}
369361

362+
void noteUseOfTypeMetadata(Type type) {
363+
type.visit([&](Type t) {
364+
if (auto *nominal = t->getAnyNominal())
365+
noteUseOfTypeMetadata(nominal);
366+
});
367+
}
368+
370369
void noteUseOfTypeContextDescriptor(NominalTypeDecl *type,
371370
RequireMetadata_t requireMetadata) {
372371
noteUseOfTypeGlobals(type, false, requireMetadata);
@@ -386,9 +385,6 @@ class IRGenerator {
386385
/// Adds \p Conf to LazyWitnessTables if it has not been added yet.
387386
void addLazyWitnessTable(const ProtocolConformance *Conf);
388387

389-
void addFieldTypes(ArrayRef<CanType> fieldTypes, IRGenModule *IGM) {
390-
LazyFieldTypes.push_back({IGM, {fieldTypes.begin(), fieldTypes.end()}});
391-
}
392388

393389
void addClassForEagerInitialization(ClassDecl *ClassDecl);
394390

@@ -850,7 +846,6 @@ class IRGenModule {
850846
void addUsedGlobal(llvm::GlobalValue *global);
851847
void addCompilerUsedGlobal(llvm::GlobalValue *global);
852848
void addObjCClass(llvm::Constant *addr, bool nonlazy);
853-
void addFieldTypes(ArrayRef<CanType> fieldTypes);
854849
void addProtocolConformance(ConformanceDescription &&conformance);
855850

856851
llvm::Constant *emitSwiftProtocols();

test/IRGen/lazy_field_metadata.swift

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// RUN: %target-swift-frontend -emit-ir -wmo -O %s | %FileCheck %s
2+
3+
// Both should be emitted:
4+
5+
// CHECK: @"$s19lazy_field_metadata011GenericWithD5FieldVMn" = hidden constant
6+
// CHECK: @"$s19lazy_field_metadata24GenericWithConcreteFieldVMn" = hidden constant
7+
8+
struct GenericWithConcreteField<T> {
9+
let z = 123
10+
}
11+
12+
struct GenericWithGenericField<T> {
13+
var field = GenericWithConcreteField<T>()
14+
}
15+
16+
public func forceMetadata() -> Any.Type {
17+
return GenericWithGenericField<Int>.self
18+
}

0 commit comments

Comments
 (0)