Skip to content

Commit 874607b

Browse files
committed
SIL: Include all witnesses in SILDefaultWitnessTable, not just resilient defaults
Previously SILDefaultWitnessTables only included "resilient" default implementations, which are currently defined as those that appear at the end of a protocol, after any requirements without defaults. However, this was too inflexible. Instead, include all entries in the SILDefaultWitnessTable, with invalid entries standing in for requirements without defaults. Previously, the minimum witness table size was a separate parameter, also appearing in SIL syntax; now it can be calculated by looking at the entries themselves. The getResilientDefaultEntries() method of SILDefaultWitnessTable returns the same result as getEntries() did previously.
1 parent 0b320a6 commit 874607b

File tree

12 files changed

+104
-61
lines changed

12 files changed

+104
-61
lines changed

include/swift/SIL/SILDefaultWitnessTable.h

Lines changed: 20 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -57,11 +57,11 @@ class SILDefaultWitnessTable : public llvm::ilist_node<SILDefaultWitnessTable>,
5757
: Requirement(Requirement), Witness(Witness) {}
5858

5959
bool isValid() const {
60-
return Requirement.isNull();
60+
return !Requirement.isNull();
6161
}
6262

6363
const SILDeclRef &getRequirement() const {
64-
assert(!Requirement.isNull());
64+
assert(isValid());
6565
return Requirement;
6666
}
6767
SILFunction *getWitness() const {
@@ -94,7 +94,6 @@ class SILDefaultWitnessTable : public llvm::ilist_node<SILDefaultWitnessTable>,
9494

9595
/// Private constructor for making SILDefaultWitnessTable definitions.
9696
SILDefaultWitnessTable(SILModule &M, const ProtocolDecl *Protocol,
97-
unsigned MinimumWitnessTableSizeInWords,
9897
ArrayRef<Entry> entries);
9998

10099
void addDefaultWitnessTable();
@@ -107,11 +106,9 @@ class SILDefaultWitnessTable : public llvm::ilist_node<SILDefaultWitnessTable>,
107106
/// Create a new SILDefaultWitnessTable definition with the given entries.
108107
static SILDefaultWitnessTable *create(SILModule &M,
109108
const ProtocolDecl *Protocol,
110-
unsigned MinimumWitnessTableSizeInWords,
111109
ArrayRef<Entry> entries);
112110

113-
void convertToDefinition(unsigned MinimumWitnessTableSizeInWords,
114-
ArrayRef<Entry> entries);
111+
void convertToDefinition(ArrayRef<Entry> entries);
115112

116113
~SILDefaultWitnessTable();
117114

@@ -122,26 +119,32 @@ class SILDefaultWitnessTable : public llvm::ilist_node<SILDefaultWitnessTable>,
122119
const ProtocolDecl *getProtocol() const { return Protocol; }
123120

124121
/// Return the minimum witness table size, in words.
125-
unsigned getMinimumWitnessTableSize() const {
126-
return MinimumWitnessTableSizeInWords;
127-
}
122+
///
123+
/// This will not change if requirements with default implementations are
124+
/// added at the end of the protocol.
125+
unsigned getMinimumWitnessTableSize() const;
128126

129127
/// Return the default witness table size, in words.
130128
///
131-
/// The runtime size of a witness table is the minimum size plus the default
132-
/// size -- if a conformance omits any of the default witnesses, they will be
133-
/// copied in at runtime.
134-
///
135-
/// For now, we assume each default entry is a single word; this assumption
136-
/// will no longer hold if we decide to implement resilient associated type
137-
/// requirements.
129+
/// This is the number of resilient default entries that were known when the
130+
/// protocol definition was compiled; at runtime, it may be smaller or larger,
131+
/// so this should only be used when emitting metadata for the protocol
132+
/// definition itself.
138133
unsigned getDefaultWitnessTableSize() const {
139-
return Entries.size();
134+
return Entries.size() - getMinimumWitnessTableSize();
140135
}
141136

142137
/// Return all of the default witness table entries.
143138
ArrayRef<Entry> getEntries() const { return Entries; }
144139

140+
/// Return all of the resilient default implementations.
141+
///
142+
/// This is the array of witnesses actually emitted as part of the protocol's
143+
/// metadata; see the comment in getMinimumWitnessTableSize().
144+
ArrayRef<Entry> getResilientDefaultEntries() {
145+
return Entries.slice(getMinimumWitnessTableSize());
146+
}
147+
145148
/// Verify that the default witness table is well-formed.
146149
void verify(const SILModule &M) const;
147150

lib/IRGen/GenMeta.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5005,7 +5005,7 @@ namespace {
50055005
addConstantInt16(DefaultWitnesses->getMinimumWitnessTableSize());
50065006
addConstantInt16(DefaultWitnesses->getDefaultWitnessTableSize());
50075007

5008-
for (auto entry : DefaultWitnesses->getEntries()) {
5008+
for (auto entry : DefaultWitnesses->getResilientDefaultEntries()) {
50095009
addWord(IGM.getAddrOfSILFunction(entry.getWitness(), NotForDefinition));
50105010
}
50115011
} else {

lib/Parse/ParseSIL.cpp

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4328,13 +4328,6 @@ bool Parser::parseSILDefaultWitnessTable() {
43284328
// Parse the protocol.
43294329
ProtocolDecl *protocol = parseProtocolDecl(*this, WitnessState);
43304330

4331-
// Parse the minimum witness table size.
4332-
unsigned minimumWitnessTableSize;
4333-
if (WitnessState.parseInteger(
4334-
minimumWitnessTableSize,
4335-
diag::sil_invalid_minimum_witness_table_size))
4336-
return true;
4337-
43384331
// Parse the body.
43394332
SourceLoc LBraceLoc = Tok.getLoc();
43404333
consumeToken(tok::l_brace);
@@ -4349,9 +4342,14 @@ bool Parser::parseSILDefaultWitnessTable() {
43494342
Identifier EntryKeyword;
43504343
SourceLoc KeywordLoc;
43514344
if (parseIdentifier(EntryKeyword, KeywordLoc,
4352-
diag::expected_tok_in_sil_instr, "method"))
4345+
diag::expected_tok_in_sil_instr, "method, no_default"))
43534346
return true;
43544347

4348+
if (EntryKeyword.str() == "no_default") {
4349+
witnessEntries.push_back(SILDefaultWitnessTable::Entry());
4350+
continue;
4351+
}
4352+
43554353
if (EntryKeyword.str() != "method") {
43564354
diagnose(KeywordLoc, diag::expected_tok_in_sil_instr, "method");
43574355
return true;
@@ -4382,9 +4380,7 @@ bool Parser::parseSILDefaultWitnessTable() {
43824380
parseMatchingToken(tok::r_brace, RBraceLoc, diag::expected_sil_rbrace,
43834381
LBraceLoc);
43844382

4385-
SILDefaultWitnessTable::create(*SIL->M, protocol,
4386-
minimumWitnessTableSize,
4387-
witnessEntries);
4383+
SILDefaultWitnessTable::create(*SIL->M, protocol, witnessEntries);
43884384
BodyScope.reset();
43894385
return false;
43904386
}

lib/SIL/SILDefaultWitnessTable.cpp

Lines changed: 30 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -35,15 +35,12 @@ void SILDefaultWitnessTable::addDefaultWitnessTable() {
3535

3636
SILDefaultWitnessTable *
3737
SILDefaultWitnessTable::create(SILModule &M, const ProtocolDecl *Protocol,
38-
unsigned MinimumWitnessTableSizeInWords,
3938
ArrayRef<SILDefaultWitnessTable::Entry> entries){
4039
// Allocate the witness table and initialize it.
4140
void *buf = M.allocate(sizeof(SILDefaultWitnessTable),
4241
alignof(SILDefaultWitnessTable));
4342
SILDefaultWitnessTable *wt =
44-
::new (buf) SILDefaultWitnessTable(M, Protocol,
45-
MinimumWitnessTableSizeInWords,
46-
entries);
43+
::new (buf) SILDefaultWitnessTable(M, Protocol, entries);
4744

4845
wt->addDefaultWitnessTable();
4946

@@ -68,27 +65,21 @@ SILDefaultWitnessTable::create(SILModule &M, const ProtocolDecl *Protocol) {
6865
SILDefaultWitnessTable::
6966
SILDefaultWitnessTable(SILModule &M,
7067
const ProtocolDecl *Protocol,
71-
unsigned MinimumWitnessTableSizeInWords,
7268
ArrayRef<Entry> entries)
73-
: Mod(M), Protocol(Protocol), MinimumWitnessTableSizeInWords(0), Entries(),
74-
IsDeclaration(true) {
69+
: Mod(M), Protocol(Protocol), Entries(), IsDeclaration(true) {
7570

76-
convertToDefinition(MinimumWitnessTableSizeInWords, entries);
71+
convertToDefinition(entries);
7772
}
7873

7974
SILDefaultWitnessTable::SILDefaultWitnessTable(SILModule &M,
8075
const ProtocolDecl *Protocol)
81-
: Mod(M), Protocol(Protocol), MinimumWitnessTableSizeInWords(0), Entries(),
82-
IsDeclaration(true) {}
76+
: Mod(M), Protocol(Protocol), Entries(), IsDeclaration(true) {}
8377

8478
void SILDefaultWitnessTable::
85-
convertToDefinition(unsigned MinimumWitnessTableSizeInWords,
86-
ArrayRef<Entry> entries) {
79+
convertToDefinition(ArrayRef<Entry> entries) {
8780
assert(IsDeclaration);
8881
IsDeclaration = false;
8982

90-
this->MinimumWitnessTableSizeInWords = MinimumWitnessTableSizeInWords;
91-
9283
void *buf = Mod.allocate(sizeof(Entry)*entries.size(), alignof(Entry));
9384
memcpy(buf, entries.begin(), sizeof(Entry)*entries.size());
9485
Entries = MutableArrayRef<Entry>(static_cast<Entry*>(buf), entries.size());
@@ -101,6 +92,31 @@ convertToDefinition(unsigned MinimumWitnessTableSizeInWords,
10192
}
10293
}
10394

95+
unsigned SILDefaultWitnessTable::getMinimumWitnessTableSize() const {
96+
unsigned defaultEntries = 0;
97+
unsigned minimumEntries = 0;
98+
99+
// Count the number of entries up to and including the last null entry.
100+
// This is the number of witnesses that all conforming types must
101+
// provide.
102+
//
103+
// Any witnesses after the last null entry all have defaults, and can
104+
// be omitted from conformances; these are the resilient defaults.
105+
//
106+
// FIXME: Really this should look at availability instead.
107+
for (auto entry : Entries) {
108+
if (entry.isValid()) {
109+
defaultEntries++;
110+
} else {
111+
minimumEntries++;
112+
minimumEntries += defaultEntries;
113+
defaultEntries = 0;
114+
}
115+
}
116+
117+
return minimumEntries;
118+
}
119+
104120
SILDefaultWitnessTable::~SILDefaultWitnessTable() {
105121
// Drop the reference count of witness functions referenced by this table.
106122
for (auto entry : getEntries()) {

lib/SIL/SILPrinter.cpp

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2104,10 +2104,14 @@ void SILWitnessTable::dump() const {
21042104
void SILDefaultWitnessTable::print(llvm::raw_ostream &OS, bool Verbose) const {
21052105
// sil_default_witness_table <Protocol> <MinSize>
21062106
OS << "sil_default_witness_table"
2107-
<< " " << getProtocol()->getName()
2108-
<< " " << getMinimumWitnessTableSize() << " {\n";
2107+
<< " " << getProtocol()->getName() << " {\n";
21092108

21102109
for (auto &witness : getEntries()) {
2110+
if (!witness.isValid()) {
2111+
OS << " no_default\n";
2112+
continue;
2113+
}
2114+
21112115
// method #declref: @function
21122116
OS << " method ";
21132117
witness.getRequirement().print(OS);

lib/SIL/SILVerifier.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3162,6 +3162,9 @@ void SILDefaultWitnessTable::verify(const SILModule &M) const {
31623162
// witness tables should not reference SILFunctions without
31633163
// public/public_external linkage.
31643164
for (const Entry &E : getEntries()) {
3165+
if (!E.isValid())
3166+
continue;
3167+
31653168
SILFunction *F = E.getWitness();
31663169
assert(!isLessVisibleThan(F->getLinkage(), SILLinkage::Public) &&
31673170
"Default witness tables should not reference internal "

lib/SILGen/SILGenType.cpp

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -519,33 +519,36 @@ namespace {
519519
struct SILGenDefaultWitnessTable
520520
: public SILWitnessVisitor<SILGenDefaultWitnessTable> {
521521

522-
unsigned MinimumWitnessCount;
523522
SmallVector<SILDefaultWitnessTable::Entry, 8> DefaultWitnesses;
524523

525-
SILGenDefaultWitnessTable() : MinimumWitnessCount(0) {}
524+
SILGenDefaultWitnessTable() {}
525+
526+
void addMissingDefault() {
527+
DefaultWitnesses.push_back(SILDefaultWitnessTable::Entry());
528+
}
526529

527530
void addOutOfLineBaseProtocol(ProtocolDecl *baseProto) {
528-
MinimumWitnessCount++;
531+
addMissingDefault();
529532
}
530533

531534
void addMethod(FuncDecl *func) {
532-
MinimumWitnessCount++;
535+
addMissingDefault();
533536
}
534537

535538
void addConstructor(ConstructorDecl *ctor) {
536-
MinimumWitnessCount++;
539+
addMissingDefault();
537540
}
538541

539542
void addAssociatedType(AssociatedTypeDecl *ty,
540543
ArrayRef<ProtocolDecl *> protos) {
541-
MinimumWitnessCount++;
544+
addMissingDefault();
542545

543546
for (auto *protocol : protos) {
544547
// Only reference the witness if the protocol requires it.
545548
if (!Lowering::TypeConverter::protocolRequiresWitnessTable(protocol))
546549
continue;
547550

548-
MinimumWitnessCount++;
551+
addMissingDefault();
549552
}
550553
}
551554
};
@@ -559,6 +562,5 @@ void SILGenModule::emitDefaultWitnessTable(ProtocolDecl *protocol) {
559562
SILGenDefaultWitnessTable builder;
560563
builder.visitProtocolDecl(protocol);
561564

562-
defaultWitnesses->convertToDefinition(builder.MinimumWitnessCount,
563-
builder.DefaultWitnesses);
565+
defaultWitnesses->convertToDefinition(builder.DefaultWitnesses);
564566
}

lib/SILOptimizer/IPO/DeadFunctionElimination.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -348,6 +348,9 @@ class DeadFunctionElimination : FunctionLivenessComputation {
348348
// Check default witness methods.
349349
for (SILDefaultWitnessTable &WT : Module->getDefaultWitnessTableList()) {
350350
for (const SILDefaultWitnessTable::Entry &entry : WT.getEntries()) {
351+
if (!entry.isValid())
352+
continue;
353+
351354
SILFunction *F = entry.getWitness();
352355
auto *fd = cast<AbstractFunctionDecl>(entry.getRequirement().getDecl());
353356

test/IRGen/protocol_resilience.sil

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ import resilient_protocol
2121

2222
// CHECK: @_TMp19protocol_resilience17ResilientProtocol = {{(protected )?}}constant <{{.*}}> <{
2323
// CHECK-SAME: i32 1031,
24-
// CHECK-SAME: i16 2,
24+
// CHECK-SAME: i16 4,
2525
// CHECK-SAME: i16 4,
2626
// CHECK-SAME: void (%swift.opaque*, %swift.type*, i8**)* @defaultC,
2727
// CHECK-SAME: void (%swift.opaque*, %swift.type*, i8**)* @defaultD
@@ -156,7 +156,11 @@ bb0(%0 : $@thick Self.Type):
156156
}
157157

158158

159-
sil_default_witness_table ResilientProtocol 2 {
159+
sil_default_witness_table ResilientProtocol {
160+
no_default
161+
no_default
162+
no_default
163+
no_default
160164
method #ResilientProtocol.defaultC!1: @defaultC
161165
method #ResilientProtocol.defaultD!1: @defaultD
162166
method #ResilientProtocol.defaultE!1: @defaultE

test/SIL/Parser/default_witness_tables.sil

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,13 +34,21 @@ bb0(%0 : $*Self):
3434
sil public_external @defaultE : $@convention(witness_method) <Self where Self : ResilientProtocol> (@in_guaranteed Self) -> ()
3535

3636

37-
// CHECK-LABEL: sil_default_witness_table ResilientProtocol 4 {
37+
// CHECK-LABEL: sil_default_witness_table ResilientProtocol {
38+
// CHECK: no_default
39+
// CHECK: no_default
40+
// CHECK: no_default
41+
// CHECK: no_default
3842
// CHECK: #ResilientProtocol.defaultC!1: @defaultC
3943
// CHECK: #ResilientProtocol.defaultD!1: @defaultD
4044
// CHECK: #ResilientProtocol.defaultE!1: @defaultE
4145
// CHECK: }
4246

43-
sil_default_witness_table ResilientProtocol 4 {
47+
sil_default_witness_table ResilientProtocol {
48+
no_default
49+
no_default
50+
no_default
51+
no_default
4452
method #ResilientProtocol.defaultC!1: @defaultC
4553
method #ResilientProtocol.defaultD!1: @defaultD
4654
method #ResilientProtocol.defaultE!1: @defaultE

test/SILGen/protocol_resilience.swift

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,14 @@ protocol InternalProtocol {
1414
func f()
1515
}
1616

17-
// CHECK-LABEL: sil_default_witness_table P 0 {
17+
// CHECK-LABEL: sil_default_witness_table P {
1818
// CHECK-NEXT: }
1919

20-
// CHECK-LABEL: sil_default_witness_table ResilientProtocol 4 {
20+
// CHECK-LABEL: sil_default_witness_table ResilientProtocol {
21+
// CHECK-NEXT: no_default
22+
// CHECK-NEXT: no_default
23+
// CHECK-NEXT: no_default
24+
// CHECK-NEXT: no_default
2125
// CHECK-NEXT: }
2226

2327
// GLOBAL-NOT: sil_default_witness_table InternalProtocol

test/SILOptimizer/devirt_default_witness_method.sil

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ bb0(%0 : $*Self):
1515
return %result : $()
1616
}
1717

18-
sil_default_witness_table ResilientProtocol 1 {
18+
sil_default_witness_table ResilientProtocol {
1919
method #ResilientProtocol.defaultA!1: @defaultA
2020
}
2121

0 commit comments

Comments
 (0)