Skip to content

Commit 8e874cd

Browse files
committed
SIL: add better support for specialized witness tables.
Store specialize witness tables in a separate lookup table in the module. This allows that for a normal conformance there can exist the original _and_ a specialized witness table. Also, add a boolean property `isSpecialized` to `WitnessTable` which indicates whether the witness table is specialized or not.
1 parent 721944a commit 8e874cd

File tree

21 files changed

+168
-70
lines changed

21 files changed

+168
-70
lines changed

SwiftCompilerSources/Sources/SIL/WitnessTable.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,9 @@ public struct WitnessTable : CustomStringConvertible, NoReflectionChildren {
111111

112112
public var isDefinition: Bool { !bridged.isDeclaration() }
113113

114+
// True, if this is a specialized witness table (currently only used in embedded mode).
115+
public var isSpecialized: Bool { bridged.isSpecialized() }
116+
114117
public var description: String {
115118
return String(taking: bridged.getDebugDescription())
116119
}

include/swift/SIL/SILBridging.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1089,6 +1089,7 @@ struct BridgedWitnessTable {
10891089
BRIDGED_INLINE SwiftInt getNumEntries() const;
10901090
SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedWitnessTableEntry getEntry(SwiftInt index) const;
10911091
BRIDGED_INLINE bool isDeclaration() const;
1092+
BRIDGED_INLINE bool isSpecialized() const;
10921093
};
10931094

10941095
struct OptionalBridgedWitnessTable {

include/swift/SIL/SILBridgingImpl.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1978,6 +1978,10 @@ bool BridgedWitnessTable::isDeclaration() const {
19781978
return table->isDeclaration();
19791979
}
19801980

1981+
bool BridgedWitnessTable::isSpecialized() const {
1982+
return table->isSpecialized();
1983+
}
1984+
19811985
SwiftInt BridgedDefaultWitnessTable::getNumEntries() const {
19821986
return SwiftInt(table->getEntries().size());
19831987
}

include/swift/SIL/SILModule.h

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -255,9 +255,14 @@ class SILModule {
255255
VTableEntryCache;
256256

257257
/// Lookup table for SIL witness tables from conformances.
258-
llvm::DenseMap<const ProtocolConformance *, SILWitnessTable *>
258+
llvm::DenseMap<const RootProtocolConformance *, SILWitnessTable *>
259259
WitnessTableMap;
260260

261+
/// Lookup table for specialized witness tables from conformances.
262+
/// Currently only used in embedded mode.
263+
llvm::DenseMap<const ProtocolConformance *, SILWitnessTable *>
264+
specializedWitnessTableMap;
265+
261266
/// The list of SILWitnessTables in the module.
262267
WitnessTableListType witnessTables;
263268

@@ -866,16 +871,17 @@ class SILModule {
866871
/// i.e. it can be linked by linkFunction.
867872
bool hasFunction(StringRef Name);
868873

869-
/// Look up the SILWitnessTable representing the lowering of a protocol
870-
/// conformance, and collect the substitutions to apply to the referenced
871-
/// witnesses, if any.
872-
///
873-
/// \arg C The protocol conformance mapped key to use to lookup the witness
874-
/// table.
875-
/// \arg deserializeLazily If we cannot find the witness table should we
876-
/// attempt to lazily deserialize it.
874+
/// Look up the SILWitnessTable representing the lowering of a conformance `C`.
875+
/// If a specialized witness table exists for the conformance, return the specialized table.
876+
/// Specialized witness tables are currently only used in embedded mode.
877877
SILWitnessTable *lookUpWitnessTable(const ProtocolConformance *C);
878878

879+
/// Look up the SILWitnessTable representing the lowering of a conformance `C`.
880+
/// The `isSpecialized` flag specifies if only non-specialized or specialized witness
881+
/// tables are looked up.
882+
/// Specialized witness tables are currently only used in embedded mode.
883+
SILWitnessTable *lookUpWitnessTable(const ProtocolConformance *C, bool isSpecialized);
884+
879885
/// Attempt to lookup \p Member in the witness table for \p C.
880886
///
881887
/// Also, deserialize all referenced functions according to the \p linkgingMode.

include/swift/SIL/SILWitnessTable.h

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,9 @@ class SILWitnessTable : public llvm::ilist_node<SILWitnessTable>,
181181
/// whether or not entries is empty since you can have an empty witness table
182182
/// that is not a declaration.
183183
bool IsDeclaration;
184-
184+
185+
bool specialized;
186+
185187
/// Whether or not this witness table is serialized, which allows
186188
/// devirtualization from another module.
187189
unsigned SerializedKind : 2;
@@ -190,11 +192,12 @@ class SILWitnessTable : public llvm::ilist_node<SILWitnessTable>,
190192
SILWitnessTable(SILModule &M, SILLinkage Linkage, SerializedKind_t Serialized,
191193
StringRef name, ProtocolConformance *conformance,
192194
ArrayRef<Entry> entries,
193-
ArrayRef<ProtocolConformanceRef> conditionalConformances);
195+
ArrayRef<ProtocolConformanceRef> conditionalConformances,
196+
bool specialized);
194197

195198
/// Private constructor for making SILWitnessTable declarations.
196199
SILWitnessTable(SILModule &M, SILLinkage Linkage, StringRef Name,
197-
ProtocolConformance *conformance);
200+
ProtocolConformance *conformance, bool specialized);
198201

199202
void addWitnessTable();
200203

@@ -203,11 +206,13 @@ class SILWitnessTable : public llvm::ilist_node<SILWitnessTable>,
203206
static SILWitnessTable *
204207
create(SILModule &M, SILLinkage Linkage, SerializedKind_t SerializedKind,
205208
ProtocolConformance *conformance, ArrayRef<Entry> entries,
206-
ArrayRef<ProtocolConformanceRef> conditionalConformances);
209+
ArrayRef<ProtocolConformanceRef> conditionalConformances,
210+
bool specialized);
207211

208212
/// Create a new SILWitnessTable declaration.
209213
static SILWitnessTable *create(SILModule &M, SILLinkage Linkage,
210-
ProtocolConformance *conformance);
214+
ProtocolConformance *conformance,
215+
bool specialized);
211216

212217
~SILWitnessTable();
213218

@@ -238,6 +243,9 @@ class SILWitnessTable : public llvm::ilist_node<SILWitnessTable>,
238243
/// Returns true if this witness table is a definition.
239244
bool isDefinition() const { return !isDeclaration(); }
240245

246+
// Returns true, if this is a specialized witness table (currently only used in embedded mode).
247+
bool isSpecialized() const { return specialized; }
248+
241249
/// Returns true if this witness table is going to be (or was) serialized.
242250
bool isSerialized() const {
243251
return SerializedKind_t(SerializedKind) == IsSerialized;

include/swift/SILOptimizer/OptimizerBridgingImpl.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -453,7 +453,7 @@ BridgedWitnessTable BridgedPassContext::createWitnessTable(BridgedLinkage linkag
453453
return {swift::SILWitnessTable::create(*mod, (swift::SILLinkage)linkage,
454454
serialized ? swift::IsSerialized : swift::IsNotSerialized,
455455
conformance.unbridged().getConcrete(),
456-
entries, {})};
456+
entries, {}, /*specialized=*/true)};
457457
}
458458

459459
BridgedVTable BridgedPassContext::createSpecializedVTable(BridgedType classType,

lib/AST/ASTMangler.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -299,7 +299,7 @@ std::string ASTMangler::mangleWitnessTable(const ProtocolConformance *C) {
299299
if (auto *sc = dyn_cast<SpecializedProtocolConformance>(C)) {
300300
appendProtocolConformance(sc);
301301
appendOperator("WP");
302-
} else if (isa<NormalProtocolConformance>(C)) {
302+
} else if (isa<NormalProtocolConformance>(C) || isa<InheritedProtocolConformance>(C)) {
303303
appendProtocolConformance(C);
304304
appendOperator("WP");
305305
} else if (isa<SelfProtocolConformance>(C)) {

lib/IRGen/GenProto.cpp

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1387,9 +1387,9 @@ class DirectConformanceInfo : public ConformanceInfo {
13871387
class SpecializedConformanceInfo : public ConformanceInfo {
13881388
friend ProtocolInfo;
13891389

1390-
const SpecializedProtocolConformance *Conformance;
1390+
const ProtocolConformance *Conformance;
13911391
public:
1392-
SpecializedConformanceInfo(const SpecializedProtocolConformance *C)
1392+
SpecializedConformanceInfo(const ProtocolConformance *C)
13931393
: Conformance(C) {}
13941394

13951395
llvm::Value *getTable(IRGenFunction &IGF,
@@ -2608,8 +2608,15 @@ IRGenModule::getConformanceInfo(const ProtocolDecl *protocol,
26082608
const ConformanceInfo *info;
26092609

26102610
auto *specConf = conformance;
2611-
if (auto *inheritedC = dyn_cast<InheritedProtocolConformance>(conformance))
2611+
if (auto *inheritedC = dyn_cast<InheritedProtocolConformance>(conformance)) {
2612+
SILWitnessTable *wt = getSILModule().lookUpWitnessTable(inheritedC);
2613+
if (wt && wt->getConformance() == inheritedC) {
2614+
info = new SpecializedConformanceInfo(inheritedC);
2615+
Conformances.try_emplace(conformance, info);
2616+
return *info;
2617+
}
26122618
specConf = inheritedC->getInheritedConformance();
2619+
}
26132620

26142621
// If there is a specialized SILWitnessTable for the specialized conformance,
26152622
// directly use it.

lib/SIL/IR/Linker.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -299,7 +299,8 @@ void SILLinkerVisitor::visitProtocolConformance(
299299

300300
SILLinkage linkage = getLinkageForProtocolConformance(rootC, NotForDefinition);
301301
WT = SILWitnessTable::create(Mod, linkage,
302-
const_cast<RootProtocolConformance *>(rootC));
302+
const_cast<RootProtocolConformance *>(rootC),
303+
/*specialized=*/ false);
303304
}
304305
// If the module is at or past the Lowered stage, then we can't do any
305306
// further deserialization, since pre-IRGen SIL lowering changes the types

lib/SIL/IR/SILModule.cpp

Lines changed: 39 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -240,14 +240,28 @@ void SILModule::flushDeletedInsts() {
240240

241241
SILWitnessTable *
242242
SILModule::lookUpWitnessTable(const ProtocolConformance *C) {
243-
assert(C && "null conformance passed to lookUpWitnessTable");
243+
// First try to lookup a specialized witness table for that conformance.
244+
if (auto *wt = lookUpWitnessTable(C, /*isSpecialized=*/true)) {
245+
return wt;
246+
}
247+
return lookUpWitnessTable(C, /*isSpecialized=*/false);
248+
}
244249

245-
// Attempt to lookup the witness table from the table.
246-
auto found = WitnessTableMap.find(C);
247-
if (found == WitnessTableMap.end())
248-
return nullptr;
250+
SILWitnessTable *
251+
SILModule::lookUpWitnessTable(const ProtocolConformance *C, bool isSpecialized) {
252+
assert(C && "null conformance passed to lookUpWitnessTable");
249253

250-
return found->second;
254+
if (isSpecialized) {
255+
// First try to lookup a specialized witness table for that conformance.
256+
auto foundSpec = specializedWitnessTableMap.find(C);
257+
if (foundSpec != specializedWitnessTableMap.end())
258+
return foundSpec->second;
259+
} else if (auto *rootConf = dyn_cast<RootProtocolConformance>(C)) {
260+
auto found = WitnessTableMap.find(rootConf);
261+
if (found != WitnessTableMap.end())
262+
return found->second;
263+
}
264+
return nullptr;
251265
}
252266

253267
SILDefaultWitnessTable *
@@ -287,7 +301,9 @@ void SILModule::deleteWitnessTable(SILWitnessTable *Wt) {
287301
auto Conf = Wt->getConformance();
288302
assert(lookUpWitnessTable(Conf) == Wt);
289303
getSILLoader()->invalidateWitnessTable(Wt);
290-
WitnessTableMap.erase(Conf);
304+
specializedWitnessTableMap.erase(Conf);
305+
if (auto *rootConf = dyn_cast<RootProtocolConformance>(Conf))
306+
WitnessTableMap.erase(rootConf);
291307
witnessTables.erase(Wt);
292308
}
293309

@@ -579,15 +595,24 @@ SILModule::lookUpFunctionInWitnessTable(ProtocolConformanceRef C,
579595
linker.processConformance(C);
580596
}
581597
ProtocolConformance *conf = C.getConcrete();
582-
if (auto *inheritedC = dyn_cast<InheritedProtocolConformance>(conf))
583-
conf = inheritedC->getInheritedConformance();
584-
585-
if (!isa<SpecializedProtocolConformance>(conf) || !lookupInSpecializedWitnessTable) {
586-
conf = conf->getRootConformance();
598+
SILWitnessTable *wt = nullptr;
599+
600+
if (lookupInSpecializedWitnessTable) {
601+
wt = lookUpWitnessTable(conf);
602+
if (!wt) {
603+
if (auto *inheritedC = dyn_cast<InheritedProtocolConformance>(conf)) {
604+
conf = inheritedC->getInheritedConformance();
605+
wt = lookUpWitnessTable(conf);
606+
}
607+
if (!wt && !isa<SpecializedProtocolConformance>(conf)) {
608+
conf = conf->getRootConformance();
609+
wt = lookUpWitnessTable(conf);
610+
}
611+
}
612+
} else {
613+
wt = lookUpWitnessTable(conf->getRootConformance());
587614
}
588615

589-
SILWitnessTable *wt = lookUpWitnessTable(conf);
590-
591616
if (!wt) {
592617
LLVM_DEBUG(llvm::dbgs() << " Failed speculative lookup of "
593618
"witness for: ";

0 commit comments

Comments
 (0)