Skip to content

VM: retain live frame bindings in deferred class members #803

Description

@chrisbbreuer

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 VM: expose ordinary activation bindings to direct eval #771/VM: retain live frame bindings for nested suspendable closures #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 Compiler: scan deferred class frame captures once #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 4249661388e5d3f92a85186213da140a6481490f:

  • 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 Compiler: scan deferred class frame captures once #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.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions