ReviewOS

zig-utils/zig-js

VM: lower block function declarations with exact Annex B bindings

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

Parent: #465 Related: #771, #785, #498

Current boundary

Ordinary-function lowering is now on main: distinct lexical/legacy bindings, whole-CaseBlock initialization, source-order legacy updates, labelled/conditional declarations, repeated captured cells, and exact with-record boundaries. Required-bytecode Annex B function-code witnesses improved from 2/159 to 159/159. Program and suspendable environment-mode declaration planning subsequently landed in #790; both paths now have completed pushed integration.

The shared-analysis extraction also exposed an interpreter bug: grouped destructuring lexical declarations were omitted from Annex B exclusions. For example, eval('let unused, { hidden } = {}; { function hidden() {} }'); typeof hidden returned function instead of undefined. The corrected AST traversal rejects that legacy binding while retaining normal eligible declarations. The shared analyzer and interpreter regression coverage landed in 18f60d8a. Compiler consumption and ordinary frame-mode lowering landed in 81ce8599; environment-mode lowering subsequently landed in #790.

Scope

  • Share the exact AST-level Annex B eligibility analysis between interpreter and compiler, preserving parameter/arguments exclusions, lexical ancestors, simple versus destructuring catches, labeled declarations, and function/async/generator distinctions.
  • Instantiate block and switch function bindings once per entry in the exact lexical scope; closures and direct eval must retain live identity, including repeated entries.
  • Keep sloppy legacy var bindings distinct from block bindings and copy the current lexical value only when the declaration statement is evaluated, with no with-object redirection.
  • Preserve ordinary function-body hoisting, duplicate-declaration order, branch-only declarations, TDZ, abrupt completion, debugger ordering, and required-bytecode fail-closed admission.
  • Extend forced-tree-walker/required-bytecode, moving-GC, OOM, no-GIL/TSan, and exact Test262 witnesses; record causal admission gains separately from default-tier conformance flips.

Acceptance

  • One shared, tested Annex B eligibility model drives interpreter and compiler; secure name membership and bounded allocation remain intact.
  • Blocks, switch CaseBlocks, labels/branches, loops, catch/finally, and with scopes preserve exact lexical/legacy identity and source-order updates.
  • Required bytecode executes supported ordinary block declarations without fallback; unsupported suspendable capture and disposal boundaries remain explicit.
  • Focused, full unit, exact relevant Test262, moving-GC/OOM, no-GIL/TSan, debugger, termination, and threadfuzz evidence is recorded.
  • Conventional commits land on main with issue links, exact flips, and no unsupported performance claim.

No source rewriting, eager heap environments for every local, snapshots in place of live lexical cells, speculative execution/replay, broad admission before semantics, or changes to stack/queue/job, Promise, Worker, or Map/Set iterator implementations.

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.

Environment-mode declaration implementation: 8d772d15 (#790). Its observed eval-context defects were subsequently fixed and verified in #795 and #797. The separate async native-borrow audit remains open in #791; native stack/queue/job and lifecycle work is not claimed complete.

9 days ago

Landed fix(scope): retain grouped Annex B lexical exclusions (#788).

The interpreter now uses the shared AST-only Annex B analysis, with declaration-identity, parameter/arguments, eval, catch, switch, label, and deterministic OOM coverage. The grouped let/const destructuring bug is fixed: sloppy eval no longer leaks an ineligible block function or replaces an existing outer variable; eligible controls remain exact.

Validation: merged full units 1992 passed, 1 platform skip, 0 failures/leaks; focused normal and TSan Annex B 12/12, zero reports. Relevant Test262 baseline b023626 -> merged candidate is byte-identical: Annex B function-code 159, Annex B statements 22, block 21, switch 111, eval-code 347, function-code 217, function expressions 264, function statements 451: total 1592 -> 1592 passed, zero failures/flips/regressions in these subtrees. The separate leak probe changes from incorrect function to correct undefined.

This lands the shared-analysis prerequisite and correctness fix, not block-function bytecode admission. Compiler consumption, distinct lexical/legacy lowering, and required-tier witnesses remain open. A separate earlier eval capture-state race exposed by Linux CI is #789 and is being prioritized.

9 days ago

Landed feat(vm): lower ordinary block function bindings (#788) directly on main as Chris, with no trailers.

Measured against cfef054: required-bytecode Annex B function-code witnesses 2/159 -> 159/159 (+157), each paired with a passing forced-tree-walker run. Default-tier Test262 results remain byte-identical: 3,024 passes, zero failures across twelve Annex B/eval/function/block/switch/with/loop subtrees; zero default-tier flips or regressions in that measured set.

Final full units: 1,998 pass / 1 platform skip / 0 fail / 0 leak. Allocation-failure checks: 35/35. Block-function checks: 6/6 in Debug, TSan and ReleaseSafe, including actual moving GC, no-GIL shared closures and interruption recovery. Seed-1 ReleaseFast threadfuzz: 400 default and 300 verify programs, zero failures.

The full run exposed an allocation-test fixture flaw: opportunistic arena backing-buffer resize changed the alloc count between fault replays. The fixture now explicitly refuses resize/remap so every growth allocation is fault-injected; production allocation is unchanged.

No performance claim or universal environment-mode claim: #790 retains two verified pre-existing global-switch failures and the remaining program/suspendable declaration work. Pushed integration remains pending.

Sign in to comment on this issue.