Problem
The clean representative timing collector for #460 reaches moving young collections while Promise reaction jobs are executing. Interpreter.current_microtask is traced and relocated, but promise.runJob copies the Microtask and Reaction by value and continues using raw *Promise / Value locals after invoking JavaScript. A JIT safepoint can compact the registered root while those native locals retain the old address.
A bounded reproducer on current main (9d0227a3) is:
env LC_ALL=C bench-comparison-zig-js independent_steady representative_async_microtasks 6000 1 8It fails under strict GC with GC mark of non-GC cell from traceReaction / markValue. The exact parent also fails; #510 fixed a different stale edge in suspended captured VM frames and is not the regression source.
The interrupted full row had reached a 20.5 GB physical footprint, and a 3-second stack sample showed all eight workers active, predominantly in repeated young collection/marking rather than deadlocked.
Required fix
- Execute jobs through the registered
current_microtaskstorage, not an untracked by-value copy. - Add a precise relocatable root representation for raw Promise pointers held by native helpers across JavaScript re-entry / allocation safepoints.
- Cover trace and relocation structurally and with a real moving-GC Promise handler witness.
- Re-run the bounded 8-lane async reproducer, focused TSan, the full unit gate, and then resume #460 publication evidence.
- Preserve PromiseJobs FIFO/checksum semantics; do not weaken strict GC validation or reduce the benchmark workload.