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.
This commit is contained in:
Erik Eckstein
2025-04-17 11:54:11 +02:00
parent 721944a936
commit 8e874cd2b2
21 changed files with 167 additions and 69 deletions

View File

@@ -240,14 +240,28 @@ void SILModule::flushDeletedInsts() {
SILWitnessTable *
SILModule::lookUpWitnessTable(const ProtocolConformance *C) {
// First try to lookup a specialized witness table for that conformance.
if (auto *wt = lookUpWitnessTable(C, /*isSpecialized=*/true)) {
return wt;
}
return lookUpWitnessTable(C, /*isSpecialized=*/false);
}
SILWitnessTable *
SILModule::lookUpWitnessTable(const ProtocolConformance *C, bool isSpecialized) {
assert(C && "null conformance passed to lookUpWitnessTable");
// Attempt to lookup the witness table from the table.
auto found = WitnessTableMap.find(C);
if (found == WitnessTableMap.end())
return nullptr;
return found->second;
if (isSpecialized) {
// First try to lookup a specialized witness table for that conformance.
auto foundSpec = specializedWitnessTableMap.find(C);
if (foundSpec != specializedWitnessTableMap.end())
return foundSpec->second;
} else if (auto *rootConf = dyn_cast<RootProtocolConformance>(C)) {
auto found = WitnessTableMap.find(rootConf);
if (found != WitnessTableMap.end())
return found->second;
}
return nullptr;
}
SILDefaultWitnessTable *
@@ -287,7 +301,9 @@ void SILModule::deleteWitnessTable(SILWitnessTable *Wt) {
auto Conf = Wt->getConformance();
assert(lookUpWitnessTable(Conf) == Wt);
getSILLoader()->invalidateWitnessTable(Wt);
WitnessTableMap.erase(Conf);
specializedWitnessTableMap.erase(Conf);
if (auto *rootConf = dyn_cast<RootProtocolConformance>(Conf))
WitnessTableMap.erase(rootConf);
witnessTables.erase(Wt);
}
@@ -579,15 +595,24 @@ SILModule::lookUpFunctionInWitnessTable(ProtocolConformanceRef C,
linker.processConformance(C);
}
ProtocolConformance *conf = C.getConcrete();
if (auto *inheritedC = dyn_cast<InheritedProtocolConformance>(conf))
conf = inheritedC->getInheritedConformance();
SILWitnessTable *wt = nullptr;
if (!isa<SpecializedProtocolConformance>(conf) || !lookupInSpecializedWitnessTable) {
conf = conf->getRootConformance();
if (lookupInSpecializedWitnessTable) {
wt = lookUpWitnessTable(conf);
if (!wt) {
if (auto *inheritedC = dyn_cast<InheritedProtocolConformance>(conf)) {
conf = inheritedC->getInheritedConformance();
wt = lookUpWitnessTable(conf);
}
if (!wt && !isa<SpecializedProtocolConformance>(conf)) {
conf = conf->getRootConformance();
wt = lookUpWitnessTable(conf);
}
}
} else {
wt = lookUpWitnessTable(conf->getRootConformance());
}
SILWitnessTable *wt = lookUpWitnessTable(conf);
if (!wt) {
LLVM_DEBUG(llvm::dbgs() << " Failed speculative lookup of "
"witness for: ";