Skip to content

Commit f5df5d1

Browse files
committed
[ABI] Put mangled inherited protocol witnesses into the resilient witness table
Emit mangled inherited protocol witnesses into the resilient witness table, and realize them when we instantiate the resilient witness table. Don’t put mangled inherited protocol witnesses into non-resilient witness tables: there is no efficient way to make sure they are realized, so keep the previous instantiation-function approach. Implements the rest of rdar://problem/46282080. (cherry picked from commit c0519c7)
1 parent 456d7c3 commit f5df5d1

File tree

5 files changed

+79
-52
lines changed

5 files changed

+79
-52
lines changed

lib/IRGen/GenProto.cpp

Lines changed: 41 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1320,17 +1320,23 @@ class AccessorConformanceInfo : public ConformanceInfo {
13201320
void addOutOfLineBaseProtocol(ProtocolDecl *baseProto) {
13211321
#ifndef NDEBUG
13221322
auto &entry = SILEntries.front();
1323+
#endif
1324+
SILEntries = SILEntries.slice(1);
1325+
1326+
// Resilient conformances get a resilient witness table.
1327+
if (ResilientConformance)
1328+
return;
1329+
1330+
#ifndef NDEBUG
13231331
assert(entry.getKind() == SILWitnessTable::BaseProtocol
13241332
&& "sil witness table does not match protocol");
13251333
assert(entry.getBaseProtocolWitness().Requirement == baseProto
13261334
&& "sil witness table does not match protocol");
13271335
auto piIndex = PI.getBaseIndex(baseProto);
13281336
assert((size_t)piIndex.getValue() ==
1329-
Table.size() - WitnessTableFirstRequirementOffset &&
1337+
Table.size() - WitnessTableFirstRequirementOffset &&
13301338
"offset doesn't match ProtocolInfo layout");
13311339
#endif
1332-
1333-
SILEntries = SILEntries.slice(1);
13341340

13351341
// TODO: Use the witness entry instead of falling through here.
13361342

@@ -1346,18 +1352,10 @@ class AccessorConformanceInfo : public ConformanceInfo {
13461352
return;
13471353
}
13481354

1349-
// Emit a mangled name.
1350-
if (isDependentConformance(astConf->getRootConformance(),
1351-
/*considerResilience=*/false))
1352-
RequiresSpecialization = true;
1353-
1354-
auto proto = Conformance.getProtocol();
1355-
CanType selfType = proto->getProtocolSelfType()->getCanonicalType();
1356-
AssociatedConformance requirement(proto, selfType, baseProto);
1357-
llvm::Constant *witnessEntry =
1358-
getAssociatedConformanceWitness(requirement, ConcreteType,
1359-
ProtocolConformanceRef(astConf));
1360-
Table.addBitCast(witnessEntry, IGM.Int8PtrTy);
1355+
// Otherwise, we'll need to derive it at instantiation time.
1356+
RequiresSpecialization = true;
1357+
SpecializedBaseConformances.push_back({Table.size(), &conf});
1358+
Table.addNullPointer(IGM.Int8PtrTy);
13611359
}
13621360

13631361
void addMethod(SILDeclRef requirement) {
@@ -1761,6 +1759,22 @@ void WitnessTableBuilder::collectResilientWitnesses(
17611759
continue;
17621760
}
17631761

1762+
// Inherited conformance witnesses.
1763+
if (entry.getKind() == SILWitnessTable::BaseProtocol) {
1764+
const auto &witness = entry.getBaseProtocolWitness();
1765+
auto baseProto = witness.Requirement;
1766+
auto proto = SILWT->getProtocol();
1767+
CanType selfType = proto->getProtocolSelfType()->getCanonicalType();
1768+
AssociatedConformance requirement(proto, selfType, baseProto);
1769+
ProtocolConformanceRef inheritedConformance =
1770+
ConformanceInContext.getAssociatedConformance(selfType, baseProto);
1771+
llvm::Constant *witnessEntry =
1772+
getAssociatedConformanceWitness(requirement, ConcreteType,
1773+
inheritedConformance);
1774+
resilientWitnesses.push_back(witnessEntry);
1775+
continue;
1776+
}
1777+
17641778
if (entry.getKind() != SILWitnessTable::Method)
17651779
continue;
17661780

@@ -1978,6 +1992,18 @@ namespace {
19781992
IGM.getAddrOfLLVMVariableOrGOTEquivalent(
19791993
LinkEntity::forAssociatedConformanceDescriptor(requirement));
19801994
B.addRelativeAddress(assocConformanceDescriptor);
1995+
} else if (entry.getKind() == SILWitnessTable::BaseProtocol) {
1996+
// Associated conformance descriptor for a base protocol.
1997+
const auto &witness = entry.getBaseProtocolWitness();
1998+
auto proto = SILWT->getProtocol();
1999+
AssociatedConformance requirement(proto,
2000+
proto->getSelfInterfaceType()
2001+
->getCanonicalType(),
2002+
witness.Requirement);
2003+
auto baseConformanceDescriptor =
2004+
IGM.getAddrOfLLVMVariableOrGOTEquivalent(
2005+
LinkEntity::forAssociatedConformanceDescriptor(requirement));
2006+
B.addRelativeAddress(baseConformanceDescriptor);
19812007
} else if (entry.getKind() == SILWitnessTable::Method) {
19822008
// Method descriptor.
19832009
auto declRef = entry.getMethodWitness().Requirement;

stdlib/public/runtime/Metadata.cpp

Lines changed: 19 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -3952,6 +3952,7 @@ static bool doesNotRequireInstantiation(
39523952
/// witnesses stored in the generic witness table structure itself.
39533953
static void initializeResilientWitnessTable(
39543954
const ProtocolConformanceDescriptor *conformance,
3955+
const Metadata *conformingType,
39553956
const GenericWitnessTable *genericTable,
39563957
void **table) {
39573958
auto protocol = conformance->getProtocol();
@@ -3965,7 +3966,7 @@ static void initializeResilientWitnessTable(
39653966
auto reqDescriptor = witness.Requirement.get();
39663967

39673968
// The requirement descriptor may be NULL, in which case this is a
3968-
// requirement introduced in a later version of the protocol./
3969+
// requirement introduced in a later version of the protocol.
39693970
if (!reqDescriptor) continue;
39703971

39713972
// If the requirement descriptor doesn't land within the bounds of the
@@ -3988,35 +3989,24 @@ static void initializeResilientWitnessTable(
39883989
for (size_t i = 0, e = protocol->NumRequirements; i < e; ++i) {
39893990
unsigned witnessIndex = WitnessTableFirstRequirementOffset + i;
39903991

3992+
// If we don't have a witness, fill in the default implementation.
39913993
// If we already have a witness, there's nothing to do.
3992-
if (table[witnessIndex])
3993-
continue;
3994-
3995-
// Otherwise, fill in a default implementation.
39963994
auto &reqt = requirements[i];
3997-
void *impl = reqt.DefaultImplementation.get();
3998-
table[witnessIndex] = impl;
3999-
}
4000-
}
4001-
4002-
/// Realize witness tables for base protocols.
4003-
static void realizeBaseProtocolWitnessTables(const ProtocolDescriptor *protocol,
4004-
const Metadata *conformingType,
4005-
WitnessTable *witnessTable) {
4006-
// Loop over the requirements, realizing witness tables for base class
4007-
// conformances.
4008-
auto requirements = protocol->getRequirements();
4009-
auto baseReq = protocol->getRequirementBaseDescriptor();
4010-
for (size_t i = 0, e = protocol->NumRequirements; i < e; ++i) {
4011-
// Once we hit a non-base protocol requirement, we're done.
4012-
auto &reqt = requirements[i];
4013-
if (reqt.Flags.getKind() != ProtocolRequirementFlags::Kind::BaseProtocol)
4014-
break;
3995+
if (!table[witnessIndex]) {
3996+
void *impl = reqt.DefaultImplementation.get();
3997+
table[witnessIndex] = impl;
3998+
}
40153999

4016-
// Realize the base protocol witness table.
4017-
(void)swift_getAssociatedConformanceWitness(witnessTable,
4018-
conformingType, conformingType,
4019-
baseReq, &reqt);
4000+
// Realize base protocol witnesses.
4001+
if (reqt.Flags.getKind() == ProtocolRequirementFlags::Kind::BaseProtocol &&
4002+
table[witnessIndex]) {
4003+
// Realize the base protocol witness table.
4004+
auto baseReq = protocol->getRequirementBaseDescriptor();
4005+
(void)swift_getAssociatedConformanceWitness((WitnessTable *)table,
4006+
conformingType,
4007+
conformingType,
4008+
baseReq, &reqt);
4009+
}
40204010
}
40214011
}
40224012

@@ -4079,9 +4069,8 @@ WitnessTableCacheEntry::allocate(
40794069
}
40804070

40814071
// Fill in any default requirements.
4082-
initializeResilientWitnessTable(conformance, genericTable, table);
4072+
initializeResilientWitnessTable(conformance, Type, genericTable, table);
40834073
auto castTable = reinterpret_cast<WitnessTable*>(table);
4084-
realizeBaseProtocolWitnessTables(protocol, Type, castTable);
40854074

40864075
// Call the instantiation function if present.
40874076
if (!genericTable->Instantiator.isNull()) {
@@ -4114,10 +4103,7 @@ swift::swift_getWitnessTable(const ProtocolConformanceDescriptor *conformance,
41144103
// accessor directly.
41154104
auto genericTable = conformance->getGenericWitnessTable();
41164105
if (!genericTable || doesNotRequireInstantiation(conformance, genericTable)) {
4117-
auto pattern = conformance->getWitnessTablePattern();
4118-
realizeBaseProtocolWitnessTables(conformance->getProtocol(), type,
4119-
const_cast<WitnessTable *>(pattern));
4120-
return uniqueForeignWitnessTableRef(pattern);
4106+
return uniqueForeignWitnessTableRef(conformance->getWitnessTablePattern());
41214107
}
41224108

41234109
auto &cache = getCache(genericTable);

test/IRGen/associated_type_witness.swift

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,15 @@ struct Computed<T, U> : Assocked {
9797
typealias Assoc = Pair<T, U>
9898
}
9999

100+
// Instantiation function for GenericComputed : DerivedFromSimpleAssoc.
101+
// CHECK-LABEL: define internal void @"$s23associated_type_witness15GenericComputedVyxGAA22DerivedFromSimpleAssocAAWI"(i8**, %swift.type* %"GenericComputed<T>", i8**)
102+
// CHECK: [[T0:%.*]] = call i8** @swift_getWitnessTable({{.*}}@"$s23associated_type_witness15GenericComputedVyxGAA14HasSimpleAssocAAMc"
103+
// CHECK-NEXT: [[T1:%.*]] = bitcast i8** [[T0]] to i8*
104+
// CHECK-NEXT: [[T2:%.*]] = getelementptr inbounds i8*, i8** %0, i32 1
105+
// CHECK-NEXT: store i8* [[T1]], i8** [[T2]], align 8
106+
// CHECK-NEXT: ret void
107+
108+
100109
struct PBox<T: P> {}
101110
protocol HasSimpleAssoc {
102111
associatedtype Assoc
@@ -106,7 +115,7 @@ protocol DerivedFromSimpleAssoc : HasSimpleAssoc {}
106115
// Generic witness table pattern for GenericComputed : DerivedFromSimpleAssoc.
107116
// GLOBAL-LABEL: @"$s23associated_type_witness15GenericComputedVyxGAA22DerivedFromSimpleAssocAAWp" = internal constant [2 x i8*]
108117
// GLOBAL-SAME: @"$s23associated_type_witness15GenericComputedVyxGAA22DerivedFromSimpleAssocAAMc"
109-
// GLOBAL-SAME: @"associated conformance 23associated_type_witness15GenericComputedVyxGAA22DerivedFromSimpleAssocA2A03HashI0"
118+
// GLOBAL-SAME: i8* null
110119

111120
// Relative reference to private data
112121
struct GenericComputed<T: P> : DerivedFromSimpleAssoc {
@@ -139,5 +148,5 @@ struct UsesVoid : HasSimpleAssoc {
139148
// GLOBAL-SAME: i16 2,
140149
// GLOBAL-SAME: i16 1,
141150

142-
// No instantiator function needed
143-
// GLOBAL-SAME: i32 0
151+
// Relative reference to instantiator function
152+
// GLOBAL-SAME: i32 trunc (i64 sub (i64 ptrtoint (void (i8**, %swift.type*, i8**)* @"$s23associated_type_witness15GenericComputedVyxGAA22DerivedFromSimpleAssocAAWI" to i64),

test/IRGen/generic_wt_linkage.sil

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,6 @@ sil_default_witness_table hidden DerivedFromSimpleAssoc {
4444
no_default
4545
}
4646

47-
// CHECK: define internal swiftcc i8** @"$s4test15GenericComputedVyxGAA22DerivedFromSimpleAssocAAxAA03HasfG0PWT"
47+
// CHECK: define internal void @"$s4test15GenericComputedVyxGAA22DerivedFromSimpleAssocAAWI"
4848

4949

test/IRGen/protocol_resilience_descriptors.swift

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,12 @@ where Element: ProtocolWithRequirements, Element.T == Y {
7979
public func second() { }
8080
}
8181

82+
// CHECK-USAGE: @"$s31protocol_resilience_descriptors17ConformsToDerivedV010resilient_A009ResilientF8ProtocolAAMc" =
83+
// CHECK-SAME: @"associated conformance 31protocol_resilience_descriptors17ConformsToDerivedV010resilient_A009ResilientF8ProtocolAaD0h4BaseI0"
84+
public struct ConformsToDerived : ResilientDerivedProtocol {
85+
public func requirement() -> Int { return 0 }
86+
}
87+
8288
// ----------------------------------------------------------------------------
8389
// Resilient protocol usage
8490
// ----------------------------------------------------------------------------

0 commit comments

Comments
 (0)