Skip to content

Commit b5880f3

Browse files
committed
allow name lookup to work with resilient types
cleanup from review comments
1 parent 70c5755 commit b5880f3

File tree

8 files changed

+136
-69
lines changed

8 files changed

+136
-69
lines changed

include/swift/Runtime/Metadata.h

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2104,6 +2104,13 @@ struct GenericMetadata {
21042104
const void *getMetadataTemplate() const {
21052105
return reinterpret_cast<const void *>(this + 1);
21062106
}
2107+
2108+
/// Return the nominal type descriptor for the template metadata
2109+
const NominalTypeDescriptor *getTemplateDescription() const {
2110+
auto bytes = reinterpret_cast<const uint8_t *>(getMetadataTemplate());
2111+
auto metadata = reinterpret_cast<const Metadata *>(bytes + AddressPoint);
2112+
return metadata->getNominalTypeDescriptor();
2113+
}
21072114
};
21082115

21092116
/// \brief The control structure of a generic protocol conformance.
@@ -2170,6 +2177,24 @@ struct TypeMetadataRecord {
21702177

21712178
return DirectType;
21722179
}
2180+
2181+
const GenericMetadata *getGenericPattern() const {
2182+
switch (Flags.getTypeKind()) {
2183+
case TypeMetadataRecordKind::Universal:
2184+
return nullptr;
2185+
2186+
case TypeMetadataRecordKind::UniqueGenericPattern:
2187+
break;
2188+
2189+
case TypeMetadataRecordKind::UniqueDirectClass:
2190+
case TypeMetadataRecordKind::UniqueIndirectClass:
2191+
case TypeMetadataRecordKind::UniqueDirectType:
2192+
case TypeMetadataRecordKind::NonuniqueDirectType:
2193+
assert(false && "not generic metadata pattern");
2194+
}
2195+
2196+
return GenericPattern;
2197+
}
21732198

21742199
/// Get the canonical metadata for the type referenced by this record, or
21752200
/// return null if the record references a generic or universal type.

lib/IRGen/GenDecl.cpp

Lines changed: 48 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -666,10 +666,8 @@ void IRGenModule::addProtocolConformanceRecord(
666666
}
667667

668668
static bool
669-
typeHasExplicitProtocolConformance(CanType type) {
670-
auto conformances =
671-
type->getNominalOrBoundGenericNominal()->getAllConformances();
672-
669+
hasExplicitProtocolConformance(NominalTypeDecl *decl) {
670+
auto conformances = decl->getAllConformances();
673671
for (auto conformance : conformances) {
674672
// inherited protocols do not emit explicit conformance records
675673
// TODO any special handling required for Specialized conformances?
@@ -697,8 +695,10 @@ void IRGenModule::addRuntimeResolvableType(CanType type) {
697695
// Don't emit type metadata records for types that can be found in the protocol
698696
// conformance table as the runtime will search both tables when resolving a
699697
// type by name.
700-
if (!typeHasExplicitProtocolConformance(type))
701-
RuntimeResolvableTypes.push_back(type);
698+
if (auto nom = type->getAnyNominal()) {
699+
if (!hasExplicitProtocolConformance(nom))
700+
RuntimeResolvableTypes.push_back(type);
701+
}
702702
}
703703

704704
void IRGenModule::emitGlobalLists() {
@@ -1793,6 +1793,34 @@ IRGenModule::getAddrOfLLVMVariableOrGOTEquivalent(LinkEntity entity,
17931793
return {gotEquivalent, DirectOrGOT::GOT};
17941794
}
17951795

1796+
/// If true, we lazily initialize metadata at runtime because the layout
1797+
/// is only partially known. Otherwise, we can emit a direct reference a
1798+
/// constant metadata symbol.
1799+
bool
1800+
IRGenModule::hasMetadataPattern(NominalTypeDecl *theDecl) {
1801+
assert(theDecl != nullptr);
1802+
// Protocols must be special-cased in a few places.
1803+
assert(!isa<ProtocolDecl>(theDecl));
1804+
1805+
// For classes, we already computed this when we did the layout.
1806+
// FIXME: Try not to call this for classes of other modules, by referencing
1807+
// the metadata accessor instead.
1808+
if (auto *theClass = dyn_cast<ClassDecl>(theDecl))
1809+
return irgen::getClassHasMetadataPattern(*this, theClass);
1810+
1811+
// Ok, we have a value type. If it is generic, it is always initialized
1812+
// at runtime.
1813+
if (theDecl->isGenericContext())
1814+
return true;
1815+
1816+
// If the type is not fixed-size, its size depends on resilient types,
1817+
// and the metadata is initialized at runtime.
1818+
if (!getTypeInfoForUnlowered(theDecl->getDeclaredType()).isFixedSize())
1819+
return true;
1820+
1821+
return false;
1822+
}
1823+
17961824
namespace {
17971825
struct TypeEntityInfo {
17981826
ProtocolConformanceFlags flags;
@@ -1802,17 +1830,21 @@ struct TypeEntityInfo {
18021830
} // end anonymous namespace
18031831

18041832
static TypeEntityInfo
1805-
getTypeEntityInfo(IRGenModule &IGM, CanType conformingType) {
1833+
getTypeEntityInfo(IRGenModule &IGM,
1834+
CanType conformingType,
1835+
bool allowUnboundGenericTypes) {
18061836
TypeMetadataRecordKind typeKind;
18071837
Optional<LinkEntity> entity;
18081838
llvm::Type *defaultTy, *defaultPtrTy;
18091839

1810-
if (auto bgt = dyn_cast<BoundGenericType>(conformingType)) {
1840+
auto nom = conformingType->getAnyNominal();
1841+
if (IGM.hasMetadataPattern(nom)) {
1842+
assert(allowUnboundGenericTypes || isa<BoundGenericType>(conformingType));
18111843
// Conformances for generics are represented by referencing the metadata
18121844
// pattern for the generic type.
18131845
typeKind = TypeMetadataRecordKind::UniqueGenericPattern;
18141846
entity = LinkEntity::forTypeMetadata(
1815-
bgt->getDecl()->getDeclaredType()->getCanonicalType(),
1847+
nom->getDeclaredType()->getCanonicalType(),
18161848
TypeMetadataAddress::AddressPoint,
18171849
/*isPattern*/ true);
18181850
defaultTy = IGM.TypeMetadataPatternStructTy;
@@ -1964,7 +1996,8 @@ llvm::Constant *IRGenModule::emitProtocolConformances() {
19641996
LinkEntity::forProtocolDescriptor(conformance->getProtocol()),
19651997
getPointerAlignment(), ProtocolDescriptorStructTy);
19661998
auto typeEntity = getTypeEntityInfo(*this,
1967-
conformance->getType()->getCanonicalType());
1999+
conformance->getType()->getCanonicalType(),
2000+
/*allowUnboundGenericTypes*/ false);
19682001
auto flags = typeEntity.flags
19692002
.withConformanceKind(ProtocolConformanceReferenceKind::WitnessTable);
19702003

@@ -2039,11 +2072,8 @@ llvm::Constant *IRGenModule::emitTypeMetadataRecords() {
20392072

20402073
SmallVector<llvm::Constant *, 8> elts;
20412074
for (auto type : RuntimeResolvableTypes) {
2042-
// Type metadata records for generic patterns are never emitted at
2043-
// compile time.
2044-
assert(!isa<BoundGenericType>(type));
2045-
2046-
auto typeEntity = getTypeEntityInfo(*this, type);
2075+
auto typeEntity = getTypeEntityInfo(*this, type,
2076+
/*allowUnboundGenericTypes*/ true);
20472077
auto typeRef = getAddrOfLLVMVariableOrGOTEquivalent(
20482078
typeEntity.entity, getPointerAlignment(), typeEntity.defaultTy);
20492079

@@ -2203,9 +2233,9 @@ llvm::GlobalValue *IRGenModule::defineTypeMetadata(CanType concreteType,
22032233
if (!section.empty())
22042234
var->setSection(section);
22052235

2206-
// Remove this test if we eventually support unbound generic types
2207-
if (!isPattern)
2208-
addRuntimeResolvableType(concreteType);
2236+
// Keep type metadata around for all types, although the runtime can currently
2237+
// only perform name lookup of non-generic types.
2238+
addRuntimeResolvableType(concreteType);
22092239

22102240
// For metadata patterns, we're done.
22112241
if (isPattern)

lib/IRGen/GenMeta.cpp

Lines changed: 6 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -187,40 +187,14 @@ static void emitPolymorphicParametersFromArray(IRGenFunction &IGF,
187187
}
188188
}
189189

190-
/// If true, we lazily initialize metadata at runtime because the layout
191-
/// is only partially known. Otherwise, we can emit a direct reference a
192-
/// constant metadata symbol.
193-
static bool hasMetadataPattern(IRGenModule &IGM, NominalTypeDecl *theDecl) {
194-
// Protocols must be special-cased in a few places.
195-
assert(!isa<ProtocolDecl>(theDecl));
196-
197-
// For classes, we already computed this when we did the layout.
198-
// FIXME: Try not to call this for classes of other modules, by referencing
199-
// the metadata accessor instead.
200-
if (auto *theClass = dyn_cast<ClassDecl>(theDecl))
201-
return getClassHasMetadataPattern(IGM, theClass);
202-
203-
// Ok, we have a value type. If it is generic, it is always initialized
204-
// at runtime.
205-
if (theDecl->isGenericContext())
206-
return true;
207-
208-
// If the type is not fixed-size, its size depends on resilient types,
209-
// and the metadata is initialized at runtime.
210-
if (!IGM.getTypeInfoForUnlowered(theDecl->getDeclaredType()).isFixedSize())
211-
return true;
212-
213-
return false;
214-
}
215-
216190
/// Attempts to return a constant heap metadata reference for a
217191
/// nominal type.
218192
llvm::Constant *irgen::tryEmitConstantTypeMetadataRef(IRGenModule &IGM,
219193
CanType type) {
220194
auto theDecl = type->getAnyNominal();
221195
assert(theDecl && "emitting constant metadata ref for non-nominal type?");
222196

223-
if (hasMetadataPattern(IGM, theDecl))
197+
if (IGM.hasMetadataPattern(theDecl))
224198
return nullptr;
225199

226200
if (auto theClass = type->getClassOrBoundGenericClass())
@@ -286,7 +260,7 @@ static llvm::Value *emitNominalMetadataRef(IRGenFunction &IGF,
286260
return emitForeignTypeMetadataRef(IGF, theType);
287261
}
288262

289-
bool isPattern = hasMetadataPattern(IGF.IGM, theDecl);
263+
bool isPattern = IGF.IGM.hasMetadataPattern(theDecl);
290264

291265
// If this is generic, check to see if we've maybe got a local
292266
// reference already.
@@ -1924,7 +1898,7 @@ namespace {
19241898

19251899
void addGenericMetadataPattern() {
19261900
NominalTypeDecl *ntd = asImpl().getTarget();
1927-
if (!hasMetadataPattern(IGM, ntd)) {
1901+
if (!IGM.hasMetadataPattern(ntd)) {
19281902
// If there are no generic parameters, there's no pattern to link.
19291903
addWord(llvm::ConstantPointerNull::get(IGM.TypeMetadataPatternPtrTy));
19301904
return;
@@ -3627,7 +3601,7 @@ void irgen::emitClassMetadata(IRGenModule &IGM, ClassDecl *classDecl,
36273601
// TODO: classes nested within generic types
36283602
llvm::Constant *init;
36293603
bool isPattern;
3630-
if (hasMetadataPattern(IGM, classDecl)) {
3604+
if (IGM.hasMetadataPattern(classDecl)) {
36313605
GenericClassMetadataBuilder builder(IGM, classDecl, layout, fieldLayout);
36323606
builder.layout();
36333607
init = builder.getInit();
@@ -4494,7 +4468,7 @@ void irgen::emitStructMetadata(IRGenModule &IGM, StructDecl *structDecl) {
44944468
// TODO: structs nested within generic types
44954469
llvm::Constant *init;
44964470
bool isPattern;
4497-
if (hasMetadataPattern(IGM, structDecl)) {
4471+
if (IGM.hasMetadataPattern(structDecl)) {
44984472
GenericStructMetadataBuilder builder(IGM, structDecl);
44994473
builder.layout();
45004474
init = builder.getInit();
@@ -4643,7 +4617,7 @@ void irgen::emitEnumMetadata(IRGenModule &IGM, EnumDecl *theEnum) {
46434617
llvm::Constant *init;
46444618

46454619
bool isPattern;
4646-
if (hasMetadataPattern(IGM, theEnum)) {
4620+
if (IGM.hasMetadataPattern(theEnum)) {
46474621
GenericEnumMetadataBuilder builder(IGM, theEnum);
46484622
builder.layout();
46494623
init = builder.getInit();

lib/IRGen/IRGenModule.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -794,7 +794,9 @@ private: \
794794
Address getAddrOfObjCISAMask();
795795

796796
StringRef mangleType(CanType type, SmallVectorImpl<char> &buffer);
797-
797+
798+
bool hasMetadataPattern(NominalTypeDecl *theDecl);
799+
798800
// Get the ArchetypeBuilder for the currently active generic context. Crashes
799801
// if there is no generic context.
800802
ArchetypeBuilder &getContextArchetypes();

stdlib/public/runtime/MetadataLookup.cpp

Lines changed: 33 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -220,25 +220,50 @@ const Metadata *TypeMetadataRecord::getCanonicalTypeMetadata() const {
220220
}
221221
}
222222

223+
// returns the type metadata for the type named by typeNode
224+
const Metadata *
225+
swift::_matchMetadataByMangledTypeName(const llvm::StringRef typeName,
226+
const Metadata *metadata,
227+
const GenericMetadata *pattern) {
228+
const NominalTypeDescriptor *ntd = nullptr;
229+
const Metadata *foundMetadata = nullptr;
230+
231+
if (metadata != nullptr)
232+
ntd = metadata->getNominalTypeDescriptor();
233+
else if (pattern != nullptr)
234+
ntd = pattern->getTemplateDescription();
235+
236+
if (ntd == nullptr || ntd->Name != typeName)
237+
return nullptr;
238+
239+
if (pattern != nullptr) {
240+
if (!ntd->GenericParams.hasGenericParams())
241+
foundMetadata = swift_getResilientMetadata(const_cast<GenericMetadata *>(pattern));
242+
} else {
243+
foundMetadata = metadata;
244+
}
245+
246+
return foundMetadata;
247+
}
248+
223249
// returns the type metadata for the type named by typeName
224250
static const Metadata *
225251
_searchTypeMetadataRecords(const TypeMetadataState &T,
226252
const llvm::StringRef typeName) {
227253
unsigned sectionIdx = 0;
228254
unsigned endSectionIdx = T.SectionsToScan.size();
255+
const Metadata *foundMetadata = nullptr;
229256

230257
for (; sectionIdx < endSectionIdx; ++sectionIdx) {
231258
auto &section = T.SectionsToScan[sectionIdx];
232259
for (const auto &record : section) {
233-
if (auto metadata = record.getCanonicalTypeMetadata()) {
234-
auto ntd = metadata->getNominalTypeDescriptor();
235-
236-
assert(ntd != nullptr);
260+
if (auto metadata = record.getCanonicalTypeMetadata())
261+
foundMetadata = _matchMetadataByMangledTypeName(typeName, metadata, nullptr);
262+
else if (auto pattern = record.getGenericPattern())
263+
foundMetadata = _matchMetadataByMangledTypeName(typeName, nullptr, pattern);
237264

238-
if (typeName == ntd->Name) {
239-
return metadata;
240-
}
241-
}
265+
if (foundMetadata != nullptr)
266+
return foundMetadata;
242267
}
243268
}
244269

stdlib/public/runtime/Private.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,11 @@ namespace swift {
111111
/// Returns true if common value witnesses were used, false otherwise.
112112
void installCommonValueWitnesses(ValueWitnessTable *vwtable);
113113

114+
const Metadata *
115+
_matchMetadataByMangledTypeName(const llvm::StringRef metadataNameRef,
116+
const Metadata *metadata,
117+
const GenericMetadata *pattern);
118+
114119
const Metadata *
115120
_searchConformancesByMangledTypeName(const llvm::StringRef typeName);
116121

stdlib/public/runtime/ProtocolConformance.cpp

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -608,18 +608,16 @@ swift::_searchConformancesByMangledTypeName(const llvm::StringRef typeName) {
608608
for (; sectionIdx < endSectionIdx; ++sectionIdx) {
609609
auto &section = C.SectionsToScan[sectionIdx];
610610
for (const auto &record : section) {
611-
if (auto metadata = record.getCanonicalTypeMetadata()) {
612-
auto ntd = metadata->getNominalTypeDescriptor();
613-
614-
if (ntd == nullptr)
615-
continue;
611+
if (auto metadata = record.getCanonicalTypeMetadata())
612+
foundMetadata = _matchMetadataByMangledTypeName(typeName, metadata, nullptr);
613+
else if (auto pattern = record.getGenericPattern())
614+
foundMetadata = _matchMetadataByMangledTypeName(typeName, nullptr, pattern);
616615

617-
if (typeName == ntd->Name) {
618-
foundMetadata = metadata;
619-
break;
620-
}
621-
}
616+
if (foundMetadata != nullptr)
617+
break;
622618
}
619+
if (foundMetadata != nullptr)
620+
break;
623621
}
624622

625623
pthread_mutex_unlock(&C.SectionsToScanLock);

test/Interpreter/class_resilience.swift

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@ ResilientClassTestSuite.test("ClassWithResilientProperty") {
4141
expectEqual(c.s.w, 30)
4242
expectEqual(c.s.h, 40)
4343
expectEqual(c.color, 50)
44+
expectTrue(_typeByName("main.ClassWithResilientProperty")
45+
== ClassWithResilientProperty.self)
4446
}
4547

4648

@@ -98,6 +100,8 @@ ResilientClassTestSuite.test("ClassWithResilientlySizedProperty") {
98100
expectEqual(c.r.s.h, 40)
99101
expectEqual(c.r.color, 50)
100102
expectEqual(c.color, 60)
103+
expectTrue(_typeByName("main.ClassWithResilientlySizedProperty")
104+
== ClassWithResilientlySizedProperty.self)
101105
}
102106

103107

@@ -125,6 +129,8 @@ ResilientClassTestSuite.test("ChildOfParentWithResilientStoredProperty") {
125129
expectEqual(c.s.h, 40)
126130
expectEqual(c.color, 50)
127131
expectEqual(c.enabled, 60)
132+
expectTrue(_typeByName("main.ChildOfParentWithResilientStoredProperty")
133+
== ChildOfParentWithResilientStoredProperty.self)
128134
}
129135

130136

@@ -152,6 +158,8 @@ ResilientClassTestSuite.test("ChildOfOutsideParentWithResilientStoredProperty")
152158
expectEqual(c.s.h, 40)
153159
expectEqual(c.color, 50)
154160
expectEqual(c.enabled, 60)
161+
expectTrue(_typeByName("main.ChildOfOutsideParentWithResilientStoredProperty")
162+
== ChildOfOutsideParentWithResilientStoredProperty.self)
155163
}
156164

157165

0 commit comments

Comments
 (0)