perf(resolution): generation-tagged supertype memo + method owner index — Swift compiler 185→98s, byte-identical (#1395)
The swiftc =2/nm:mc-* attribution located the wall: the getSupertypes conformance walk ran 971,200 times (565s of combined worker time, 581µs each) — every resolveMethodOnType miss re-queried implements/extends edges for every same-named type node, recursing depth-4 through Swift's protocol landscape with no memoization, and post-inference resolveMethodOnType averaged 1,912µs per call. Fix 1 — generation-tagged getSupertypes memo. Supertype edges GROW during the resolution loop (batch k persists its edges BEFORE batch k+1 fans out — the #1320 ordering), so a plain cache would freeze an early batch's emptier answer. Within a batch the edge state is fixed by that same ordering, so memo entries carry a generation that advances at every batch entry point (resolveBatchYielding / resolveListForAdmission — covering the sequential loop, pool workers, sync admission, and the conformance pass); a stale-gen entry recomputes. Behavior-identical to no memo at every point in time; walk invocation counts match the unmemoized run exactly (971,200 / 24,336 / 76,415). Fix 2 — per-(language, method-name) owner index in getMethodMatches: candidates bucket once by their qualifiedName's last two segments (exactly the span the match predicate tests), so a (type, method) query is a map lookup instead of an O(candidates) scan per methodMatchCache miss. ObjC selectors and multi-segment typeNames keep the legacy linear path. Also ships nm:mc-rmot / nm:rmot-supers =2 attribution rows. swiftc: settle 100.2→31.3s, resolveMethodOnType 1,912→202µs, wall 183.5→97.8s (was 185s at the head-to-head; cbm's same-box number is 119.1s). Gates: swiftc old-vs-new dump byte-identical (1,837,235 rows), swiftc pooled-vs-CODEGRAPH_NO_PARALLEL_RESOLVE=1 identical (the generation-semantics risk surface), dubbo old-vs-new identical (49k Java instance-method hits share both paths), Alamofire identical; suite 2,689 ×2 with CODEGRAPH_KERNEL_EXPECT=1. Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
974e6c8b95
commit
157c8e735d
@@ -587,12 +587,16 @@ export function resolveMethodOnType(
|
||||
// populated in the conformance pass. Still VALIDATED (the method must exist on
|
||||
// a supertype), so a wrong inference produces no edge.
|
||||
if (depth < 4 && context.getSupertypes) {
|
||||
for (const supertype of context.getSupertypes(typeName, ref.language)) {
|
||||
const via = resolveMethodOnType(
|
||||
supertype, methodName, ref, context, confidence, resolvedBy, preferredFqn, depth + 1,
|
||||
);
|
||||
if (via) return via;
|
||||
}
|
||||
const viaSupers = nmTimedT('rmot-supers', ref, (): ResolvedRef | null => {
|
||||
for (const supertype of context.getSupertypes!(typeName, ref.language)) {
|
||||
const via = resolveMethodOnType(
|
||||
supertype, methodName, ref, context, confidence, resolvedBy, preferredFqn, depth + 1,
|
||||
);
|
||||
if (via) return via;
|
||||
}
|
||||
return null;
|
||||
});
|
||||
if (viaSupers) return viaSupers;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@@ -1685,7 +1689,7 @@ export function matchMethodCall(
|
||||
.getImportMappings(ref.filePath, ref.language)
|
||||
.find((i) => i.localName === inferredType)?.source
|
||||
: undefined;
|
||||
const typedMatch = resolveMethodOnType(
|
||||
const typedMatch = nmTimedT('mc-rmot', ref, () => resolveMethodOnType(
|
||||
inferredType,
|
||||
methodName!,
|
||||
ref,
|
||||
@@ -1693,7 +1697,7 @@ export function matchMethodCall(
|
||||
0.9,
|
||||
'instance-method',
|
||||
importedFqn,
|
||||
);
|
||||
));
|
||||
if (typedMatch) {
|
||||
return typedMatch;
|
||||
}
|
||||
@@ -1728,7 +1732,7 @@ export function matchMethodCall(
|
||||
// imported FQN so resolveMethodOnType can disambiguate (#314).
|
||||
const imports = context.getImportMappings(ref.filePath, ref.language);
|
||||
const importedFqn = imports.find((i) => i.localName === inferredType)?.source;
|
||||
const typedMatch = resolveMethodOnType(
|
||||
const typedMatch = nmTimedT('mc-rmot', ref, () => resolveMethodOnType(
|
||||
inferredType,
|
||||
methodName!,
|
||||
ref,
|
||||
@@ -1736,7 +1740,7 @@ export function matchMethodCall(
|
||||
0.9,
|
||||
'instance-method',
|
||||
importedFqn,
|
||||
);
|
||||
));
|
||||
if (typedMatch) {
|
||||
return typedMatch;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user