ReviewOS

zig-utils/zig-js

GC: trace and relocate saved VM caller activation state

#786
Closed chris opened this 9 days ago ·
9 days ago

Parents: #785, #477 Related: #771, #784

Reproduction and cause

The new #785 moving-safepoint witness creates a slot-backed lexical binding inside with, enters direct eval, requests a nursery relocation, and calls an already-native numeric loop. On returning from that nested VM activation, lexical access throws ReferenceError. Activation.saved_env lives only in the arena-backed Activation, outside the registered Exec roots; popActivation restores the stale pre-move Environment pointer. The same audit finds other saved caller Values and object pointers outside the precise root set. Existing Exec.saved_home_object/saved_super_ctor demonstrate the correct ownership pattern.

Scope

Move managed caller restoration state into the existing registered Exec root view, trace and relocate every managed edge, preserve exact state through normal return, throw, tail-call inheritance, and activation reuse, and add deterministic moving-GC coverage. Do not change operand-stack, queue, job, Promise, Worker, or iterator implementations.

Acceptance

  • Saved caller Environment, this/new.target, realm/global, import-meta, active function, and this-cell contents remain rooted and relocate precisely.
  • Return, abrupt completion, tail-call inheritance, and activation reuse preserve exact caller identities without stale retained edges.
  • A moving-safepoint regression proves actual relocation during nested eval/native execution and resumes exact bindings afterward.
  • Focused normal and TSan root/activation tests plus relevant Test262 accounting pass; full required gates are reported explicitly.

No pinning, disabled compaction, snapshots, conservative-stack dependency, or interpreter fallback.

Completed integration

CI run 33113309062 completed successfully on main commit 8a1398ffc04e9e30987f968693667c7271ca3ce1, a descendant containing this implementation. All 53 executed jobs succeeded (unit and TSan-unit shards, Linux no-GIL TSan, functional/no-GIL corpus gates, fuzz profiles, ABI, Wasm, Test262 parallel, and docs); the scheduled-only nightly job was skipped. Together with the measured local evidence in the comments, this completes this issue's acceptance.

The independently scoped provisional root-registration/preparation defect remains open in #787. This closure covers registered caller-root relocation and exact eval environment identity, not that outstanding activation-driver ownership work. The exposed capture-metadata race was fixed and verified in #789.

9 days ago

The implementation now keeps all managed caller restoration copies on the already-registered Exec: Environment, this/new.target, realm/global, import-meta, active function, this-cell contents, method scope, and debugger Environment. Tracing and relocation cover each edge; return and tail-call inheritance consume those rewritten copies, and reusable activations clear them. The exact in-eval moving-safepoint regression now passes and confirms both a nursery collection and the holder address changing. Broader normal/TSan/root/activation checks are running before landing. No stack or job implementation changed.

9 days ago

Landed fix(vm): preserve runtime eval scopes and caller roots (#785, #786) on main.

All managed caller restoration copies now live in the existing registered Exec root view, including saved environment, this/new.target, global, import-meta, active function, this-cell, and debugger environment. Trace/relocation covers every edge; return and tail-call inheritance consume rewritten copies, and reusable activation release clears retained edges.

The regression triggers a real nursery move during nested direct-eval/native execution, verifies a changed object address and moving-collection count, and resumes exact caller lexical/var bindings. It failed before this fix and passes afterward, including TSan. Synthetic root relocation also verifies every new managed field.

Validation: full units 1988 passed, 1 platform skip, zero failures/leaks; focused eval 67/67, debugger 13/13, activation 28/28, root relocation 1/1, termination 4/4 and shell timeout 1/1; TSan direct eval 36/36 and root relocation 1/1, zero reports; default/verify threadfuzz 400/300 passed. Relevant exact-parent Test262 9886 -> 9886 pass, zero flips/regressions. Full pushed required integration is pending.

#787 separately tracks the pre-existing failure-atomic registration/preparation gap; this commit does not claim to repair provisional activation ownership or the reserved stack/driver lifecycle.

Sign in to comment on this issue.