fix(javascript): close full-read alias cycles at the binding in call resolution
#4243 moved local call resolution from binding-level to initializer-level cycle detection. Results inside a cycle are cycle-dependent and never cached, so a mesh of mutual reassignments whose reads select every write enumerated every initializer order: 12 writes took 1.5 s and each further pair ~35x more. A read that selects every initializer resolves the same candidates wherever the chain re-enters it, and a longer chain only cuts more of them, so closing that cycle at the binding adds no callable and keeps the mesh linear (12 writes: 5 ms). Position-narrowed reads keep their per-initializer cycles. Refs: #4348 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
42fc6c53ae
commit
91a863c73a
2 files changed
+46
-1
No files matched your search
@@ -82,6 +82,27 @@ it("bounds shared partial callback alias expansion by AST size", () => {
|
||||
expect(large.referenceReads).toBeLessThan(3 * small.referenceReads);
|
||||
});
|
||||
|
||||
it("closes reassignment meshes at bindings whose reads select every write", () => {
|
||||
const measure = (writes: number) => {
|
||||
const context = indexed(`function f(){} function g(){} let a = f, b = g;
|
||||
function run(){ ${Array.from({ length: writes }, (_, i) => (i % 2 === 0 ? "a=b;" : "b=a;")).join("")} a(); }`);
|
||||
const run = context.state.program.body.at(-1);
|
||||
if (!t.isFunctionDeclaration(run)) throw new Error("Missing run");
|
||||
const last = run.body.body.at(-1);
|
||||
if (!t.isExpressionStatement(last) || !t.isCallExpression(last.expression))
|
||||
throw new Error("Missing call");
|
||||
const reads = vi.spyOn(context.bindingCache, "get");
|
||||
const result = context.resolve(last.expression.callee);
|
||||
expect(result).toMatchObject({ complete: false });
|
||||
expect(result.callableIds).toHaveLength(2);
|
||||
return reads.mock.calls.length;
|
||||
};
|
||||
const small = measure(6);
|
||||
const large = measure(10);
|
||||
expect(small).toBeGreaterThan(0);
|
||||
expect(large).toBeLessThan(3 * small);
|
||||
});
|
||||
|
||||
it.each([
|
||||
["if(flag){cb=fallback;cb();}", true],
|
||||
["if(flag)cb=fallback;cb();", false],
|
||||
|
||||
Reference in new issue
Block a user