Parents: #473, #465. Related: #784, #800; separate from reserved native activation/job lifecycle audits #787 and #791.
Source-audited ownership gaps
At main 2865b8b, Interpreter.toPrimitive keeps raw Value v / Object o locals while invoking @@toPrimitive getters, ordinary valueOf/toString accessors, methods that may return objects and continue conversion, and host conversion callbacks. Later calls/field reads reuse those locals. A caller root retains the object but cannot rewrite these callee-local copies after moving collection.
Member and super simple/compound/logical assignment branches likewise carry raw receivers, computed key storage, old values, or expression results across getter/RHS/coercion/setter boundaries. Identifier compound assignment already roots its old operand; the member/super paths need their own exact ownership audit. The numeric-update change in #800 roots the update caller and postfix pair, but does not establish correctness of all nested coercion internals or other assignment operators.
The original source audit is now backed by deterministic before/after actual-relocation failures and final passing regression tests, recorded below.
Acceptance
No conservative pinning substitute, disabled moving GC, stale-pointer forwarding workaround, repeated coercion, sanitizer suppression, or native stack/queue/job ownership redesign.
Landed implementation and final local evidence
ab23a1bb — fix(gc): root reentrant coercion and assignment state (#801) is on origin/main, authored and committed by Chris without trailers.
ToPrimitive now publishes and reloads callee-local receiver state. One exact property Reference retains base, receiver and canonical key through assignment and destructuring effects, including delayed ToPropertyKey and early captured super bases. Shared VM/native property helpers retain computed receivers and expression results. Allocation-free synchronous tree-call records cover suspended caller state, the callee Function/environment, pending parameters and existing lazy legacy arguments; block environments/completions also relocate. Existing VM activation/native stack/queue/job lifecycle is unchanged.
Measured against e4f76af with Test262 4249661388e5d3f92a85186213da140a6481490f:
- Six standalone moving-nursery reproductions: 0/6 -> 6/6, each with exactly one moving minor and a changed subject pointer.
- Final checked-in moving matrix: 32 forced-tree + 31 required-VM cases, all pass in Debug and Debug+TSan. Callbacks are created after selecting their tier; the warmed native loop triggers the actual collection. Required mode records zero plain-function fallback.
- Ten paired ordering controls: 8/10 -> 10/10. Gains are array-rest key-coercion order and super destructuring target-base capture. These local controls are not counted as upstream corpus gains.
- Fourteen disjoint default-tier diagnostics are byte-identical: 15,319 pass / 0 fail before and after; 0 upstream Test262 flips, no measured regressions. Built-ins BigInt 77, Date 594, Number 340, Object 3411, String 1223, Symbol 98; expressions addition 48, assignment 485, class 4059, compound-assignment 454, equals 47, logical-assignment 78, subtraction 38; statements/class 4367.
- Final full Debug units: 2,031 pass, one platform skip, zero failures/leaks, 659.6 s across four timing-balanced shards.
- Debug+TSan passes all 63 moving cases, shared no-GIL calls in both tiers, every-allocation failure replay and suspended-caller trace/rewrite mapping, without reports or suppressions. The TSan binary predates only the unrelated ordering test's IIFE-to-program rewrite; selected tests and production source are identical.
- Seed-1 ReleaseFast threadfuzz: 400 default + 300 verify programs, zero failures. Format/diff checks and source checksums pass. No public performance claim.
Host conversion hooks are checked after relocation separately from primitive-wrapper fallthrough. Primitive conversion stays allocation-free under an exhausted allocator. Exact OOM replay checks empty root lists, restored caller environment and depth, using a real GC heap independently of the interpreter's failing allocation arena.
#802 retains missing VM legacy arguments introspection (reproduced without GC on baseline); only the existing tree-walker view is relocated here. #803 originally retained function-scoped deferred class captures; the descendant linked below now implements that boundary and passes the original super-pattern IIFE in both tiers. This #801 commit itself only tested the ordering regression in program form. Native audits #787/#791 remain separate.
Evidence: /Users/chris/.cache/zig-js-801.9pDs7h/README.md. All ten temporary corpus files were byte-compared and removed. Final binaries, source diff, hashes, fixtures, logs and shard plans are retained; 787 MB of isolated build caches were removed, leaving 203 MB of evidence. User-owned .codex is untouched.
f83c4191 — feat(vm): retain live deferred class captures (#803) additionally implements #803 deferred class captures and construction ownership prerequisites #804/#805. Final local combined production checks pass 2,037 units (one platform skip), 20 added actual-moving class/construction cases, focused TSan/no-GIL/OOM and 700 fuzz programs. Existing #801 checks remain in the full suite. Local success does not replace pushed integration.
Cleanup update: superseded #799/#801 Debug/TSan unit binaries were removed after their hashes and logs were retained. Their evidence READMEs document retirement; source diffs, witnesses, transcripts, shard plans and available corpus runners remain.
Completed integration (2026-08-28 UTC)
Implementation: ab23a1bb. The measured local evidence above and in the linked implementation comments remains unchanged.
Closing this implemented issue as completed. Parent-roadmap work and independently tracked follow-ups remain open; this closure does not claim those broader scopes are finished.
Parents: #473, #465. Related: #784, #800; separate from reserved native activation/job lifecycle audits #787 and #791.
Source-audited ownership gaps
At main 2865b8b, Interpreter.toPrimitive keeps raw Value v / Object o locals while invoking @@toPrimitive getters, ordinary valueOf/toString accessors, methods that may return objects and continue conversion, and host conversion callbacks. Later calls/field reads reuse those locals. A caller root retains the object but cannot rewrite these callee-local copies after moving collection.
Member and super simple/compound/logical assignment branches likewise carry raw receivers, computed key storage, old values, or expression results across getter/RHS/coercion/setter boundaries. Identifier compound assignment already roots its old operand; the member/super paths need their own exact ownership audit. The numeric-update change in #800 roots the update caller and postfix pair, but does not establish correctness of all nested coercion internals or other assignment operators.
The original source audit is now backed by deterministic before/after actual-relocation failures and final passing regression tests, recorded below.
Acceptance
No conservative pinning substitute, disabled moving GC, stale-pointer forwarding workaround, repeated coercion, sanitizer suppression, or native stack/queue/job ownership redesign.
Landed implementation and final local evidence
ab23a1bb — fix(gc): root reentrant coercion and assignment state (#801) is on origin/main, authored and committed by Chris without trailers.
ToPrimitive now publishes and reloads callee-local receiver state. One exact property Reference retains base, receiver and canonical key through assignment and destructuring effects, including delayed ToPropertyKey and early captured super bases. Shared VM/native property helpers retain computed receivers and expression results. Allocation-free synchronous tree-call records cover suspended caller state, the callee Function/environment, pending parameters and existing lazy legacy arguments; block environments/completions also relocate. Existing VM activation/native stack/queue/job lifecycle is unchanged.
Measured against e4f76af with Test262 4249661388e5d3f92a85186213da140a6481490f:
Host conversion hooks are checked after relocation separately from primitive-wrapper fallthrough. Primitive conversion stays allocation-free under an exhausted allocator. Exact OOM replay checks empty root lists, restored caller environment and depth, using a real GC heap independently of the interpreter's failing allocation arena.
#802 retains missing VM legacy arguments introspection (reproduced without GC on baseline); only the existing tree-walker view is relocated here. #803 originally retained function-scoped deferred class captures; the descendant linked below now implements that boundary and passes the original super-pattern IIFE in both tiers. This #801 commit itself only tested the ordering regression in program form. Native audits #787/#791 remain separate.
Evidence: /Users/chris/.cache/zig-js-801.9pDs7h/README.md. All ten temporary corpus files were byte-compared and removed. Final binaries, source diff, hashes, fixtures, logs and shard plans are retained; 787 MB of isolated build caches were removed, leaving 203 MB of evidence. User-owned .codex is untouched.
f83c4191 — feat(vm): retain live deferred class captures (#803) additionally implements #803 deferred class captures and construction ownership prerequisites #804/#805. Final local combined production checks pass 2,037 units (one platform skip), 20 added actual-moving class/construction cases, focused TSan/no-GIL/OOM and 700 fuzz programs. Existing #801 checks remain in the full suite. Local success does not replace pushed integration.
Cleanup update: superseded #799/#801 Debug/TSan unit binaries were removed after their hashes and logs were retained. Their evidence READMEs document retirement; source diffs, witnesses, transcripts, shard plans and available corpus runners remain.
Completed integration (2026-08-28 UTC)
Implementation: ab23a1bb. The measured local evidence above and in the linked implementation comments remains unchanged.
Closing this implemented issue as completed. Parent-roadmap work and independently tracked follow-ups remain open; this closure does not claim those broader scopes are finished.