ReviewOS

zig-utils/zig-js

Compiler: lower initializer-free destructuring parameters into VM frames

#736
Closed chris opened this 8 days ago ·
8 days ago

Parents: #465, #498 Related: #726, #730, #735

Implemented by e2ba5ac3.

Problem

Plain ordinary functions whose formal list contains an array/object binding pattern are still rejected as plain_rejected_parameter_prologue, even when the pattern has no parameter/default/computed expression and therefore needs no distinct parameter Environment. #726/#730 already provide exact activation-owned BindingInitialization bytecode, iterator closing, object-rest copying, precise temporary roots, and frame/upvalue stores; the remaining barrier is formal binding metadata and entry ordering.

Scope

  • Admit array/object formal patterns only when the whole formal list has no top-level default, nested pattern default, computed property key, or named rest formal.
  • Allocate one hidden activation input slot per pattern formal, collect every nested binding name into ordinary parameter bindings, and run native BindingInitialization left-to-right before the function body.
  • Preserve missing/undefined/null behavior, iterator acquisition/step/value/close ordering, proxy/getter order, elisions, nested array/object patterns, array rest, object rest, abrupt completion, recursion, reentrancy, closures, activation reuse, moving GC, and no-GIL shared-chunk execution.
  • Treat the entire list as non-simple: sloppy arguments remains unmapped with poison callee, and a pattern that binds arguments suppresses the implicit arguments object exactly.
  • Cover ordinary functions, arrows, methods, eligible base constructors, and on-demand automatic admission.

Top-level defaults, nested pattern defaults, computed pattern keys, a named rest formal mixed with patterns, direct eval, derived-constructor field ordering, and Annex B block functions remain separate explicit #465 barriers because they require observable parameter-expression/environment or entry-order work.

No-workaround rules

  • No Environment allocation presented as a frame fast path, tree-walker callback from admitted bytecode, bind_pattern, source rewriting, eager iterable materialization, duplicate iterator/property evaluation, guessed binding slots, swallowed abrupt completion/OOM, or widened admission beyond the proven initializer-free grammar.
  • No stacks, queues, jobs, Promise, microtask, Worker lifecycle, or Map/Set iterator changes.

Acceptance

  • Compiler metadata/admission tests prove exact input and binding slots and no bind_pattern for nested array/object/rest patterns.
  • Forced tree-walker and required bytecode agree on success, missing/null failures, iterator/proxy order, IteratorClose, closures/reentrancy, arguments semantics, methods/constructors/arrows, recursion, activation reuse, and moving GC.
  • Deterministic OOM and shared-chunk no-GIL/TSan witnesses preserve caller state and immutable metadata.
  • Full units, focused compiler/frontend/VM, threadfuzz, and exact nonzero Test262 parameter/destructuring accounting pass with zero regressions.
  • Conventional commits land directly on main and cross-link #465, #498, #726, #730, and #735.
8 days ago

Prerequisite native-entry guard #737 is complete in e71ce6cb: any non-simple parameter metadata now refuses activation-eliding direct native calls before artifact selection, while ordinary in-frame tiering remains available.

8 days ago

Completed in e2ba5ac3 and pushed directly to main.

Evidence:

  • exact Test262 destructuring accounting: 5,023 → 5,023 passes, byte-identical diagnostics, 0 gains/regressions;
  • full Debug units: 1,877 passed, 1 skipped, 0 failed/leaked across 1,878 tests;
  • focused compiler/frontend/VM: admission proofs green, frontend 16/16, VM 4/4;
  • semantic/OOM/shared-chunk/native-entry witnesses pass normally and under TSan;
  • default and TSan threadfuzz: 400 seeded programs each, 0 failures.

The implementation uses hidden activation input slots plus native VM BindingInitialization bytecode, preserves unmapped non-simple arguments, rejects every scoped parameter-expression/mixed-rest barrier, and explicitly disables all activation-eliding native/leaf/recurrence kernels for non-simple metadata. No stacks, queues, jobs, Promise, microtask, Worker lifecycle, or Map/Set iterator surfaces changed.

8 days ago

Follow-up #738 is complete in d95aaf63. #736’s native destructuring entry stream now interleaves exact primitive-literal default selection by formal index, including top-level defaults on patterns; expression-bearing and rest-mixed forms remain explicit barriers.

8 days ago

Related compiler-frame follow-up #739 landed in feat(compiler): lower closed default expressions (#739). It reuses #736/#738’s ordered parameter-frame path while keeping nested pattern expressions and other observable forms as explicit interpreter barriers.

8 days ago

The initializer-free destructuring slots from #736 now feed exact later defaults through #741: feat(compiler): lower earlier parameter defaults (#741) admits bare references to names bound by an earlier array/object formal.

Sign in to comment on this issue.