ReviewOS

zig-utils/zig-js

GC: retain ordinary construction receivers through reentrant initialization

#804
Closed chris opened this 10 days ago ·
10 days ago

Parents: #473, #803. Related: #801.

The #803 actual-moving nursery test fails in forced tree-walker mode when an instance field initializer triggers a native moving checkpoint. The field is assigned on the relocated receiver, but Interpreter.constructNT returns its original unrewritten this_val after callFunctionNT returns a primitive. The same raw fallback result exists in vm.construct after runFunction.

This is a pre-existing ordinary-construction result-ownership defect, independent of class frame admission. Both paths need their own exact receiver root and must reload the implicit constructed result after the constructor/initializer returns. An explicit object return must still replace the receiver.

Acceptance:

  • Root/reload the implicit constructed receiver in tree-walker and VM/native construction helpers without changing dispatch or activation lifecycle.
  • Prove actual relocation during ordinary bodies and base-class field initialization, including exact receiver identity and explicit object-return controls.
  • Verify local OOM unwinding, no-GIL/TSan, relevant construction/class conformance and full units; land an issue-linked commit. Pushed CI remains separately pending below.

No forwarding stale pointers, pinned receiver, disabled moving GC or fallback substitution. This child covers the result across constructor-body/initializer effects; the broader prototype-lookup and pending argument ownership audit remains part of #473.

Evidence: /Users/chris/.cache/zig-js-803.Ll0xKj/focused-debug-dynamic.log, instance_field (tree_walker), TestUnexpectedResult after a moving checkpoint.

Landed implementation and measured local evidence

f83c4191 — feat(vm): retain live deferred class captures (#803) is on origin/main, authored and committed by Chris without trailers. The cohesive class-capture change includes independently tracked construction ownership prerequisites #804/#805; native stack/queue/job and activation lifecycle remain unchanged.

Against parent ab23a1b and pinned Test262 4249661:

  • Same 9,643 eligible positive paired files: 8,838 pass / 805 fail -> 8,842 pass / 801 fail. Four required-bytecode gains, all statements/class/elements private-field/name cases; zero regressions.
  • Thirteen default class/function reports are byte-identical: 11,494 pass / zero fail. Expressions/new 59 and Reflect/construct 10 are unchanged too (11,563 total; zero default-tier flips).
  • Local paired controls: 9/41 -> 41/41. Class captures 3/32 -> 32/32, constructor primitive/object returns 6/8 -> 8/8 (Symbol/BigInt gains), original super-pattern IIFE 0/1 -> 1/1. Required mode reports no fallback.
  • Full Debug: 2,037 pass, one platform skip, zero failures/leaks, 542.0 s across four shards.
  • Debug+TSan and ReleaseSafe pass 20 actual-moving cases, semantic controls, compiler allocation replay and runtime/constructor OOM restoration. Every moving case asserts one moving minor and a changed subject pointer; static/returned identities are checked, not only field contents.
  • The no-GIL test was strengthened after the full-suite build to create classes concurrently in workers as well as exercising escaped captures. Final Debug, unsuppressed TSan and ReleaseSafe reruns pass; production source is unchanged.
  • Seed-one fuzz: 400 default + 300 verify programs, zero failures. Twelve compiler diagnostics pass structural and allocation-observation checks. These one-sample dirty-tree checks are not public performance evidence or a #619 scaling claim.

Evidence: /Users/chris/.cache/zig-js-803.Ll0xKj/README.md, retained fixtures, final source/binary hashes, full shard logs, exact paired gains/regressions and per-invocation compiler diagnostic rows. Temporary Test262 fixtures and completed build caches were removed; final evidence remains.

  • Complete pushed integration: CI 33144524467 at descendant 81978f7b completed successfully: 53 jobs passed, one scheduled-only job skipped, zero failures. This supersedes earlier pending, cancelled, or failed integration reports; those earlier runs are not counted as successful gates.

Completed integration (2026-08-28 UTC)

Implementation: f83c4191. The measured local evidence above and in the linked implementation comments remains unchanged.

  • Complete pushed integration: CI 33144524467 at descendant 81978f7b completed successfully: 53 jobs passed, one scheduled-only job skipped, zero failures. This supersedes earlier pending, cancelled, or failed integration reports; those earlier runs are not counted as successful gates.

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.

10 days ago

The same implicit-result branch also mistakes internally represented primitive Symbols/BigInts for explicit object returns. Exact-parent paired witnesses confirm both return undefined property values instead of the constructed receiver; Number and explicit-object controls pass. The fix now distinguishes real JavaScript objects as well as rooting/reloading the receiver. This preserves explicit object replacement and requires constructor result tests in both tiers.

Sign in to comment on this issue.