ReviewOS

zig-utils/zig-js

Compiler: lower named rest parameters into VM frames

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

Parents: #465, #498 Related: #728, #729, #730

Problem

A plain ordinary function whose formal list ends in a named rest parameter is still rejected as plain_rejected_parameter_prologue. Unlike defaults or destructuring parameters, a named rest parameter has no parameter expression and does not require a separate parameter Environment. The VM already owns exact activation slots, captured-frame lifetime, ordinary Array creation, and unmapped arguments-object semantics; rejecting this form keeps semantically eligible calls on the tree walker.

Scope

  • Record the exact final rest-formal index and activation slot in immutable Chunk metadata.
  • Bind every leading simple formal from its exact argument index, then create and populate the rest Array from the remaining arguments in specification order.
  • Preserve the existing base-constructor private-brand/field initialization boundary and propagate allocation failure before body execution.
  • Keep sloppy non-simple arguments unmapped, with poison-pill callee; strict behavior and explicit arguments parameters remain exact.
  • Preserve nested-arrow/upvalue capture, recursion, activation reuse, moving/concurrent GC, no-GIL shared-chunk execution, debugger locals, and stack traces.
  • Admit top-level functions, nested closures, methods, and eligible base constructors with named rest parameters through the same verified compiler path.

Defaults, destructuring formals, direct eval, derived-constructor field ordering, and Annex B block functions remain separate explicit #465 boundaries.

No-workaround rules

  • No tree-walker callback from VM entry, eager Environment allocation, source rewriting, guessed arity, aliased mapped arguments for a non-simple list, skipped Array elements, hidden rest pooling, or swallowed OOM.
  • No stacks, queues, jobs, Promise, microtask, Worker lifecycle, or Map/Set iterator changes.

Acceptance

  • Admission and bytecode tests prove the rest slot/index contract for functions, nested closures, methods, and eligible constructors.
  • Forced tree-walker and required bytecode agree on zero/one/many extras, missing leading arguments, mutation/escape, nested-arrow capture, recursion, length, arguments-object identity, poison callee, abrupt OOM, and activation reuse.
  • Moving-GC/no-GIL/TSan witnesses preserve escaped rest arrays and shared immutable Chunk metadata.
  • Full units, focused frontend/VM, threadfuzz, and exact nonzero Test262 rest-parameter/function/method accounting pass with zero regressions.
  • Conventional commits land directly on main and cross-link #465, #498, #728, #729, and #730.
9 days ago

Implemented directly on main as three conventional commits:

  • cadfab9b — compiler/Chunk metadata, exact VM frame binding, unmapped non-simple arguments, precise allocation roots, and semantic/admission coverage.
  • 742cbb8e — deterministic rest ArrayCreate OOM injection proving caller-state restoration, activation reuse, and successful recovery.
  • 48e2ab0f — four native no-GIL lanes repeatedly execute one shared immutable rest-function chunk with exact lane-local results; no JS Thread/Worker/job lifecycle surface is involved.

Validation evidence:

  • Full sharded Debug units: 1,871 passed, 1 skipped, 0 failed, 0 leaked (the two later acceptance witnesses each passed focused Debug and TSan, bringing the discovered suite to 1,874 tests).
  • Focused named-rest tree-walker/required-VM/no-GIL differential: passed normally and under TSan; moving compaction, closure escape, activation reuse, recursion/spread, arrows, methods, base constructors, length, unmapped arguments, poison callee, and mutation isolation agree exactly.
  • Focused frontend: 15/15. Focused VM: 4/4.
  • Default threadfuzz: 400 programs from seed 1, 0 failures.
  • TSan threadfuzz: 400 programs from seed 1, 0 failures.
  • Exact parent/candidate Test262: 2,319 → 2,319 passing, 0 failures, 0 gains, 0 regressions. The compared transcripts were byte-identical across rest-parameters, function, arrow-function, object, method, and class-method directories.

Defaults, destructuring formals, direct eval, derived-constructor field ordering, and Annex B block functions remain explicit separate boundaries under #465/#498. Related work remains linked through #728, #729, and #730.

9 days ago

The next non-simple entry form, initializer-free destructuring parameters, is complete in #736 via e2ba5ac3. It shares immutable non-simple metadata and unmapped arguments semantics with named rest, while pattern/rest mixed lists remain an explicit ordering barrier.

9 days ago

#738 is complete in d95aaf63. Literal defaults share named-rest’s immutable non-simple and unmapped-arguments contract, while any default/rest mixture remains rejected until both allocation and selection execute in one observable left-to-right entry stream.

Sign in to comment on this issue.