fix(javascript): stop replaying earlier writes for each object property write

Repeated property writes to one object made member-mutation collection
cubic. Each write evaluated its target binding to rule out a primitive,
and every evaluation folded all earlier mutation paths, copying every
slot once per path. 2,000 writes to one object took 27 s and 4,000 took
203 s.

- A recorded write always leaves a non-primitive binding value, so only
  the first write to a binding needs the primitive check.
- Apply mutation paths per slot in one pass with the same ordering
  semantics instead of one full slot copy per path.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: N0zoM1z0 <161784452+N0zoM1z0@users.noreply.github.com>
This commit is contained in:
authored and GitHub committed 2026-10-10 14:04:31 +08:00
1 parent 66863b609f
commit 1ec490f361
4 files changed
+106 -48

No files matched your search

@@ -10,7 +10,7 @@ import { semanticSlotAtPath } from "./javascriptSemanticSlots.js";
import {
invalidateSemanticEscapedPath,
invalidateSemanticMutationPath,
invalidateSemanticMutationPaths,
} from "./javascriptSemanticMutationValues.js";
import type { JavaScriptBindingProvenance } from "./javascriptSemanticIr.js";
@@ -211,13 +211,7 @@ const evaluateBinding = (
if (isPrimitive(captured)) value = captured;
}
}
let projected = value;
for (const path of binding.mutatedPaths) {
projected = invalidateSemanticMutationPath(projected, path);
// Every subsequent write returns this same root unknown. Replaying those
// paths at every newly collected effect otherwise becomes quadratic.
if (projected.status === "unknown") break;
}
let projected = invalidateSemanticMutationPaths(value, binding.mutatedPaths);
for (const escape of binding.escapedPaths) {
// Escapes only invalidate object references; other lattice values survive.
if (projected.status !== "object" && projected.status !== "array") break;