ReviewOS

zig-utils/zig-js

VM: retain live frame bindings in deferred class members

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

Parents: #465, #771. Related: #794, #796, #619, #801.

Original boundary (implemented below)

Compiler.compileExpr(.class_expr) rejects when classDeferredBodiesCaptureFrame finds a real slot capture in the current or enclosing ordinary VM frame. eval_class constructs deferred members from the Environment chain only. This is a correctness barrier, not a completed universal-admission path.

The #801 ordering reproduction passes as program code in both tiers, but its IIFE wrapper fails required-bytecode admission at e4f76af and the #801 draft. Its class setters capture the IIFE's log slot; computed-key/RHS helpers also refer to local bindings. Exact reproduction and diagnostics are linked from #465. #619 optimized the classifier while deliberately preserving this rejection; it does not implement frame capture.

Implementation boundary

  • Plan exact live defining-environment views for deferred class methods, instance/static initializers and static blocks, using the existing activation binding machinery from #771/#794 where applicable.
  • Interleave current/enclosing frame views and intervening runtime lexical/with/class environments without reparenting shared environments or replacing live bindings with snapshots.
  • Preserve class-name TDZ/immutability, mutable captured locals, mapped arguments, parameter/body scopes, private environments, super/this/new.target and direct eval.
  • Keep heritage and computed-name evaluation eager, once-only, and in exact source order; deferred bodies must observe the defining scope at their actual execution time.
  • Publish/retain/rewrite captured environments and their backing frames through collection, escape, threads and abrupt/OOM paths; do not redesign the separately owned VM activation/job lifecycle.

Acceptance

  • Paired tree-walker/required controls cover reads, writes, shadowing, TDZ, nested frames, class self-binding, parameter defaults, field/static effects and eval.
  • Escaped methods/constructors/fields retain live identity after their creating call returns; required mode reports no fallback for the newly admitted cases.
  • Actual moving-GC, no-GIL/TSan, allocation-failure replay and relevant class/function corpus gates pass.
  • Exact-parent compiler/admission and runtime evidence is reported independently from #619 classifier scaling.

No blanket environment allocation, detached slot snapshots, source rewriting, suppressed failures, disabled moving GC or tree-walker fallback counted as VM completion.

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.

9 days ago

The live class-capture implementation passes the initial 28 paired controls, plus four later-binding/direct-eval controls. Exact-parent initial corpus comparison: 8838/805 -> 8842/801 over the same 9643 eligible positive files (four gains, zero new failures); final combined measurement is pending. Stronger moving tests exposed independent pre-existing ownership defects: #804 implicit constructed receiver/primitive result selection, and #805 class/prototype/environment state across computed names and static effects. Both are being fixed and tested as prerequisites; no test is disabled or fallback counted as success. Native activation/job lifecycle remains unchanged.

9 days ago

Combined local production checks now pass: 2,037 unit tests passed, one skipped, zero failures/leaks in 542.0 s across four shards. Focused Debug+TSan and ReleaseSafe cover 32 paired semantic controls, 20 actual-moving cases, constructor primitive/object results and allocation-failure restoration. A strengthened no-GIL test also creates classes concurrently in each worker; its final Debug and unsuppressed TSan runs pass. Final exact-parent paired corpus/fuzz and the final ReleaseSafe test-only rebuild remain in progress. #804 and #805 remain independently tracked construction-ownership prerequisites; native stack/queue/job lifecycle is unchanged. Evidence: /Users/chris/.cache/zig-js-803.Ll0xKj/.

9 days ago

Pushed integration caught a benchmark contract omission: run 33135419183 failed benchmark-comparison-harness because the updated frontend class-capture/TDZ guards changed the native runner hash without a successor to frozen V29. Tracked and being repaired in #809 with a hash-inheriting V30; no history rewrite or benchmark gate exemption. This issue and #804/#805 remain open pending successful descendant integration.

9 days ago

Integration now tracks descendant f2340f27: https://github.com/zig-utils/zig-js/actions/runs/33137549779 . The stale frontend runner pin is repaired in #809 by immutable V30, with 65/65 Home matrix guards and both docs gates passing. The intermediate 18cd453 run was superseded after 16 successful jobs, no failures; it is not a complete gate. #800/#801/#803/#804/#805 stay open until the complete descendant run succeeds. The new full Debug and focused TSan/ReleaseSafe evidence is in #806; native stack/queue/job lifecycle remains outside this batch.

Sign in to comment on this issue.