Skip to content

Commit 6483b2f

Browse files
committed
SIL: Add 'fragile' bit to SILDefaultWitnessTable
We used to serialize default witness tables for all protocols, which doesn't make much sense. Now only serialize the fragile ones. For now, SILGen sets the fragile bit on the default witness table of all public protocols.
1 parent 229f86f commit 6483b2f

File tree

10 files changed

+108
-54
lines changed

10 files changed

+108
-54
lines changed

include/swift/SIL/SILDefaultWitnessTable.h

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,12 +98,17 @@ class SILDefaultWitnessTable : public llvm::ilist_node<SILDefaultWitnessTable>,
9898
/// the default witness table from outside its defining translation unit.
9999
bool IsDeclaration;
100100

101+
/// Whether or not this witness table is fragile. Fragile means that the
102+
/// table may be serialized and "inlined" into another module.
103+
bool IsFragile;
104+
101105
/// Private constructor for making SILDefaultWitnessTable declarations.
102106
SILDefaultWitnessTable(SILModule &M, SILLinkage Linkage,
103107
const ProtocolDecl *Protocol);
104108

105109
/// Private constructor for making SILDefaultWitnessTable definitions.
106110
SILDefaultWitnessTable(SILModule &M, SILLinkage Linkage,
111+
bool IsFragile,
107112
const ProtocolDecl *Protocol,
108113
ArrayRef<Entry> entries);
109114

@@ -116,6 +121,7 @@ class SILDefaultWitnessTable : public llvm::ilist_node<SILDefaultWitnessTable>,
116121

117122
/// Create a new SILDefaultWitnessTable definition with the given entries.
118123
static SILDefaultWitnessTable *create(SILModule &M, SILLinkage Linkage,
124+
bool IsFragile,
119125
const ProtocolDecl *Protocol,
120126
ArrayRef<Entry> entries);
121127

@@ -127,13 +133,19 @@ class SILDefaultWitnessTable : public llvm::ilist_node<SILDefaultWitnessTable>,
127133
/// Set the linkage of the default witness table.
128134
void setLinkage(SILLinkage l) { Linkage = l; }
129135

130-
void convertToDefinition(ArrayRef<Entry> entries);
136+
void convertToDefinition(ArrayRef<Entry> entries, bool isFragile);
131137

132138
~SILDefaultWitnessTable();
133139

134140
/// Return true if this is a declaration with no body.
135141
bool isDeclaration() const { return IsDeclaration; }
136142

143+
/// Return true if this is a definition with a body.
144+
bool isDefinition() const { return !IsDeclaration; }
145+
146+
/// Returns true if this default witness table is fragile.
147+
bool isFragile() const { return IsFragile; }
148+
137149
/// Return the AST ProtocolDecl this default witness table is associated with.
138150
const ProtocolDecl *getProtocol() const { return Protocol; }
139151

include/swift/Serialization/ModuleFormat.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ const uint16_t VERSION_MAJOR = 0;
5454
/// in source control, you should also update the comment to briefly
5555
/// describe what change you made. The content of this comment isn't important;
5656
/// it just ensures a conflict if two people change the module format.
57-
const uint16_t VERSION_MINOR = 327; // Last change: begin_access/end_access
57+
const uint16_t VERSION_MINOR = 328; // Last change: default witness table fragile bit
5858

5959
using DeclID = PointerEmbeddedInt<unsigned, 31>;
6060
using DeclIDField = BCFixed<31>;

lib/Parse/ParseSIL.cpp

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4969,7 +4969,7 @@ ProtocolConformance *SILParser::parseProtocolConformanceHelper(
49694969
return retVal;
49704970
}
49714971

4972-
/// decl-sil-witness ::= 'sil_witness_table' sil-linkage?
4972+
/// decl-sil-witness ::= 'sil_witness_table' sil-linkage? fragile?
49734973
/// normal-protocol-conformance decl-sil-witness-body
49744974
/// normal-protocol-conformance ::=
49754975
/// generic-parameter-list? type: protocolName module ModuleName
@@ -5174,7 +5174,7 @@ bool Parser::parseSILWitnessTable() {
51745174
}
51755175

51765176
/// decl-sil-default-witness ::= 'sil_default_witness_table'
5177-
/// sil-linkage identifier
5177+
/// sil-linkage? fragile? identifier
51785178
/// decl-sil-default-witness-body
51795179
/// decl-sil-default-witness-body:
51805180
/// '{' sil-default-witness-entry* '}'
@@ -5188,7 +5188,13 @@ bool Parser::parseSILDefaultWitnessTable() {
51885188
// Parse the linkage.
51895189
Optional<SILLinkage> Linkage;
51905190
parseSILLinkage(Linkage, *this);
5191-
5191+
5192+
bool isFragile = false;
5193+
if (parseDeclSILOptional(nullptr, &isFragile, nullptr, nullptr,
5194+
nullptr, nullptr, nullptr, nullptr, nullptr,
5195+
nullptr, WitnessState))
5196+
return true;
5197+
51925198
Scope S(this, ScopeKind::TopLevel);
51935199
// We should use WitnessTableBody. This ensures that the generic params
51945200
// are visible.
@@ -5254,7 +5260,8 @@ bool Parser::parseSILDefaultWitnessTable() {
52545260
if (!Linkage)
52555261
Linkage = SILLinkage::Public;
52565262

5257-
SILDefaultWitnessTable::create(*SIL->M, *Linkage, protocol, witnessEntries);
5263+
SILDefaultWitnessTable::create(*SIL->M, *Linkage, isFragile, protocol,
5264+
witnessEntries);
52585265
BodyScope.reset();
52595266
return false;
52605267
}

lib/SIL/SILDefaultWitnessTable.cpp

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -36,12 +36,13 @@ void SILDefaultWitnessTable::addDefaultWitnessTable() {
3636

3737
SILDefaultWitnessTable *
3838
SILDefaultWitnessTable::create(SILModule &M, SILLinkage Linkage,
39+
bool IsFragile,
3940
const ProtocolDecl *Protocol,
4041
ArrayRef<SILDefaultWitnessTable::Entry> entries){
4142
// Allocate the witness table and initialize it.
4243
auto *buf = M.allocate<SILDefaultWitnessTable>(1);
4344
SILDefaultWitnessTable *wt =
44-
::new (buf) SILDefaultWitnessTable(M, Linkage, Protocol, entries);
45+
::new (buf) SILDefaultWitnessTable(M, Linkage, IsFragile, Protocol, entries);
4546

4647
wt->addDefaultWitnessTable();
4748

@@ -66,24 +67,26 @@ SILDefaultWitnessTable::create(SILModule &M, SILLinkage Linkage,
6667
SILDefaultWitnessTable::
6768
SILDefaultWitnessTable(SILModule &M,
6869
SILLinkage Linkage,
70+
bool IsFragile,
6971
const ProtocolDecl *Protocol,
7072
ArrayRef<Entry> entries)
71-
: Mod(M), Linkage(Linkage), Protocol(Protocol), Entries(),
72-
IsDeclaration(true) {
73+
: Mod(M), Linkage(Linkage), Protocol(Protocol),
74+
Entries(), IsDeclaration(true), IsFragile(false) {
7375

74-
convertToDefinition(entries);
76+
convertToDefinition(entries, IsFragile);
7577
}
7678

7779
SILDefaultWitnessTable::SILDefaultWitnessTable(SILModule &M,
7880
SILLinkage Linkage,
7981
const ProtocolDecl *Protocol)
80-
: Mod(M), Linkage(Linkage), Protocol(Protocol), Entries(),
81-
IsDeclaration(true) {}
82+
: Mod(M), Linkage(Linkage), Protocol(Protocol),
83+
Entries(), IsDeclaration(true), IsFragile(false) {}
8284

8385
void SILDefaultWitnessTable::
84-
convertToDefinition(ArrayRef<Entry> entries) {
86+
convertToDefinition(ArrayRef<Entry> entries, bool isFragile) {
8587
assert(IsDeclaration);
8688
IsDeclaration = false;
89+
IsFragile = isFragile;
8790

8891
Entries = Mod.allocateCopy(entries);
8992

lib/SIL/SILModule.cpp

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,7 @@ SILModule::lookUpWitnessTable(const ProtocolConformance *C,
174174
return wtable;
175175

176176
// Otherwise try to deserialize it. If we succeed return the deserialized
177-
// function.
177+
// witness table.
178178
//
179179
// *NOTE* In practice, wtable will be deserializedTable, but I do not want to rely
180180
// on that behavior for now.
@@ -196,21 +196,20 @@ SILModule::lookUpDefaultWitnessTable(const ProtocolDecl *Protocol,
196196

197197
auto found = DefaultWitnessTableMap.find(Protocol);
198198
if (found == DefaultWitnessTableMap.end()) {
199-
if (deserializeLazily) {
200-
SILLinkage linkage =
201-
getSILLinkage(getDeclLinkage(Protocol), ForDefinition);
202-
SILDefaultWitnessTable *wtable =
203-
SILDefaultWitnessTable::create(*this, linkage, Protocol);
204-
wtable = getSILLoader()->lookupDefaultWitnessTable(wtable);
205-
if (wtable)
206-
DefaultWitnessTableMap[Protocol] = wtable;
207-
return wtable;
208-
}
209-
210199
return nullptr;
211200
}
212201

213-
return found->second;
202+
auto *wtable = found->second;
203+
204+
if (wtable->isDefinition())
205+
return wtable;
206+
207+
if (deserializeLazily)
208+
if (auto deserialized = getSILLoader()->lookupDefaultWitnessTable(wtable))
209+
return deserialized;
210+
211+
// If we fail, just return the declaration.
212+
return wtable;
214213
}
215214

216215
SILDefaultWitnessTable *

lib/SIL/SILVerifier.cpp

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4085,12 +4085,17 @@ void SILDefaultWitnessTable::verify(const SILModule &M) const {
40854085
continue;
40864086

40874087
SILFunction *F = E.getWitness();
4088-
// FIXME
4089-
#if 0
4090-
assert(!isLessVisibleThan(F->getLinkage(), getLinkage()) &&
4091-
"Default witness tables should not reference "
4092-
"less visible functions.");
4093-
#endif
4088+
4089+
// If a SILDefaultWitnessTable is going to be serialized, it must only
4090+
// reference public or shared [fragile] functions.
4091+
if (isFragile()) {
4092+
assert((!isLessVisibleThan(F->getLinkage(), getLinkage()) ||
4093+
(F->isFragile() &&
4094+
F->getLinkage() == SILLinkage::Shared)) &&
4095+
"Default witness tables should not reference "
4096+
"less visible functions.");
4097+
}
4098+
40944099
assert(F->getLoweredFunctionType()->getRepresentation() ==
40954100
SILFunctionTypeRepresentation::WitnessMethod &&
40964101
"Default witnesses must have witness_method representation.");

lib/SILGen/SILGenDecl.cpp

Lines changed: 39 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2025,16 +2025,48 @@ class SILGenDefaultWitnessTable
20252025
: public SILGenWitnessTable<SILGenDefaultWitnessTable> {
20262026
using super = SILGenWitnessTable<SILGenDefaultWitnessTable>;
20272027

2028-
public:
20292028
SILGenModule &SGM;
20302029
ProtocolDecl *Proto;
20312030
SILLinkage Linkage;
2031+
IsFragile_t isFragile;
20322032

20332033
SmallVector<SILDefaultWitnessTable::Entry, 8> DefaultWitnesses;
20342034

2035-
SILGenDefaultWitnessTable(SILGenModule &SGM, ProtocolDecl *proto,
2036-
SILLinkage linkage)
2037-
: SGM(SGM), Proto(proto), Linkage(linkage) { }
2035+
public:
2036+
SILGenDefaultWitnessTable(SILGenModule &SGM, ProtocolDecl *proto)
2037+
: SGM(SGM), Proto(proto) {
2038+
Linkage = getSILLinkage(getDeclLinkage(Proto), ForDefinition);
2039+
2040+
isFragile = IsNotFragile;
2041+
2042+
// Serialize the witness table if we're serializing everything with
2043+
// -sil-serialize-all.
2044+
if (SGM.makeModuleFragile)
2045+
isFragile = IsFragile;
2046+
2047+
// Serialize the witness table if the protocol is externally
2048+
// visible.
2049+
if (Proto->getEffectiveAccess() >= Accessibility::Public)
2050+
isFragile = IsFragile;
2051+
2052+
// Not all protocols use witness tables; in this case we just skip
2053+
// all of emit() below completely.
2054+
if (!Lowering::TypeConverter::protocolRequiresWitnessTable(proto))
2055+
Proto = nullptr;
2056+
}
2057+
2058+
SILDefaultWitnessTable *emit() {
2059+
if (!Proto)
2060+
return nullptr;
2061+
2062+
visitProtocolDecl(Proto);
2063+
2064+
auto *wtable =
2065+
SGM.M.createDefaultWitnessTableDeclaration(Proto, Linkage);
2066+
wtable->convertToDefinition(DefaultWitnesses, IsFragile);
2067+
2068+
return wtable;
2069+
}
20382070

20392071
void addMissingDefault() {
20402072
DefaultWitnesses.push_back(SILDefaultWitnessTable::Entry());
@@ -2068,7 +2100,7 @@ class SILGenDefaultWitnessTable
20682100
SILDeclRef witnessRef,
20692101
IsFreeFunctionWitness_t isFree,
20702102
Witness witness) {
2071-
SILFunction *witnessFn = SGM.emitProtocolWitness(nullptr, IsNotFragile,
2103+
SILFunction *witnessFn = SGM.emitProtocolWitness(nullptr, isFragile,
20722104
requirementRef, witnessRef,
20732105
isFree, witness);
20742106
auto entry = SILDefaultWitnessTable::Entry(requirementRef, witnessFn);
@@ -2102,15 +2134,8 @@ class SILGenDefaultWitnessTable
21022134
} // end anonymous namespace
21032135

21042136
void SILGenModule::emitDefaultWitnessTable(ProtocolDecl *protocol) {
2105-
SILLinkage linkage =
2106-
getSILLinkage(getDeclLinkage(protocol), ForDefinition);
2107-
2108-
SILGenDefaultWitnessTable builder(*this, protocol, linkage);
2109-
builder.visitProtocolDecl(protocol);
2110-
2111-
SILDefaultWitnessTable *defaultWitnesses =
2112-
M.createDefaultWitnessTableDeclaration(protocol, linkage);
2113-
defaultWitnesses->convertToDefinition(builder.DefaultWitnesses);
2137+
SILGenDefaultWitnessTable builder(*this, protocol);
2138+
builder.emit();
21142139
}
21152140

21162141
SILFunction *SILGenModule::

lib/Serialization/DeserializeSIL.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2547,8 +2547,9 @@ readDefaultWitnessTable(DeclID WId, SILDefaultWitnessTable *existingWt) {
25472547
(void)kind;
25482548

25492549
unsigned RawLinkage;
2550+
bool isFragile;
25502551
DeclID protoId;
2551-
DefaultWitnessTableLayout::readRecord(scratch, protoId, RawLinkage);
2552+
DefaultWitnessTableLayout::readRecord(scratch, protoId, RawLinkage, isFragile);
25522553

25532554
auto Linkage = fromStableSILLinkage(RawLinkage);
25542555
if (!Linkage) {
@@ -2627,7 +2628,7 @@ readDefaultWitnessTable(DeclID WId, SILDefaultWitnessTable *existingWt) {
26272628
kind = SILCursor.readRecord(entry.ID, scratch);
26282629
}
26292630

2630-
wT->convertToDefinition(witnessEntries);
2631+
wT->convertToDefinition(witnessEntries, isFragile);
26312632
wTableOrOffset.set(wT, /*fully deserialized*/ true);
26322633
if (Callback)
26332634
Callback->didDeserializeDefaultWitnessTableEntries(MF->getAssociatedModule(), wT);

lib/Serialization/SILFormat.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -213,8 +213,9 @@ namespace sil_block {
213213

214214
using DefaultWitnessTableLayout = BCRecordLayout<
215215
SIL_DEFAULT_WITNESS_TABLE,
216-
DeclIDField, // ID of ProtocolDecl
217-
SILLinkageField // Linkage
216+
DeclIDField, // ID of ProtocolDecl
217+
SILLinkageField, // Linkage
218+
BCFixed<1> // fragile
218219
// Default witness table entries will be serialized after.
219220
>;
220221

lib/Serialization/SerializeSIL.cpp

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1951,7 +1951,9 @@ writeSILDefaultWitnessTable(const SILDefaultWitnessTable &wt) {
19511951
Out, ScratchRecord,
19521952
SILAbbrCodes[DefaultWitnessTableLayout::Code],
19531953
S.addDeclRef(wt.getProtocol()),
1954-
toStableSILLinkage(wt.getLinkage()));
1954+
toStableSILLinkage(wt.getLinkage()),
1955+
wt.isFragile()
1956+
);
19551957

19561958
for (auto &entry : wt.getEntries()) {
19571959
if (!entry.isValid()) {
@@ -2073,9 +2075,8 @@ void SILSerializer::writeSILBlock(const SILModule *SILMod) {
20732075

20742076
// Write out DefaultWitnessTables.
20752077
for (const SILDefaultWitnessTable &wt : SILMod->getDefaultWitnessTables()) {
2076-
// FIXME: Don't need to serialize private and internal default witness
2077-
// tables.
2078-
if (wt.getProtocol()->getDeclContext()->isChildContextOf(assocDC))
2078+
if ((ShouldSerializeAll || wt.isFragile()) &&
2079+
wt.getProtocol()->getDeclContext()->isChildContextOf(assocDC))
20792080
writeSILDefaultWitnessTable(wt);
20802081
}
20812082

0 commit comments

Comments
 (0)