[Isolated conformances] Cache resolved global actor for conformances

In the prior implementation of runtime resolution of isolated conformances,
the runtime had to look in both the protocol conformance descriptor and
in all conditional conformance requirements (recursively) to find any
isolated conformances. If it found one, it had to demangle the global
actor type to metadata. Since swift_conformsToProtocol is a hot path through
the runtime, we can't afford this non-constant-time work in the common
case.

Instead, cache the resolved global actor and witness table as part of the
conformance cache, so that we have access to this information every time
we look up a witness table for a conformance. Propagate this up through
various callers (e.g., generic requirement checking) to the point where
we either stash it in the cache or check it at runtime. This gets us down
to a very quick check (basically, NULL-or-not) for nonisolated conformances,
and just one check for isolated conformances.
This commit is contained in:
Doug Gregor
2025-03-07 15:51:08 -08:00
parent 6dd141ad54
commit 48aa75d86f
8 changed files with 346 additions and 272 deletions

View File

@@ -529,13 +529,18 @@ static bool _unknownClassConformsToObjCProtocol(const OpaqueValue *value,
}
#endif
bool swift::_conformsToProtocol(const OpaqueValue *value,
const Metadata *type,
ProtocolDescriptorRef protocol,
const WitnessTable **conformance) {
bool swift::_conformsToProtocol(
const OpaqueValue *value,
const Metadata *type,
ProtocolDescriptorRef protocol,
const WitnessTable **conformance,
const Metadata **globalActorIsolationType,
const WitnessTable **globalActorIsolationWitnessTable) {
// Look up the witness table for protocols that need them.
if (protocol.needsWitnessTable()) {
auto witness = swift_conformsToProtocolCommon(type, protocol.getSwiftProtocol());
auto witness = swift_conformsToProtocolCommonIsolated(
type, protocol.getSwiftProtocol(), globalActorIsolationType,
globalActorIsolationWitnessTable);
if (!witness)
return false;
if (conformance)
@@ -624,7 +629,8 @@ static bool _conformsToProtocols(const OpaqueValue *value,
}
for (auto protocol : existentialType->getProtocols()) {
if (!_conformsToProtocol(value, type, protocol, conformances))
if (!_conformsToProtocol(
value, type, protocol, conformances, nullptr, nullptr))
return false;
if (conformances != nullptr && protocol.needsWitnessTable()) {
assert(*conformances != nullptr);