ReviewOS

zig-utils/zig-js

VM: own derived constructor super activation semantics

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

Parent: #746 Parents of parent: #465, #498 Predecessor: #747

Problem

#747 moved complete base-class instance initialization into constructor bytecode, leaving the causal plain_policy_class_constructor_semantics boundary only on derived constructors. The VM already checks uninitialized this for super-property operations, but an ordinary activation does not yet own the derived this cell, super() construction/binding transition, post-super brands/fields, or derived completion rules.

Scope

  • Represent each derived constructor activation with an initially unbound this cell shared by lexical arrows, plus exact save/restore through nested/tail calls, throws/finally, recursion, debugger/stack frames, and OOM.
  • Lower super(...args) canonically: capture the current superclass before argument effects; evaluate arguments left-to-right; validate/construct with the most-derived new.target; reject repeated calls only after superclass side effects; bind the returned object once; then install private brands and run compiled instance elements in source order.
  • Direct-forward synthesized default constructors without consulting an observable spread iterator.
  • Enforce derived completion: an explicit object return wins without super(); a non-undefined primitive return throws; undefined/fallthrough reads the bound this and throws when it remains uninitialized.
  • Preserve this, super properties, new.target, direct-eval and field-initializer restrictions, lexical arrows (including an arrow invoking super() across an intervening call), current constructor prototype mutation rules, moving GC, and shared no-GIL execution.
  • Remove plain_policy_class_constructor_semantics only when the entire derived constructor activation lowers; every unsupported nested syntax remains causally fail-closed.

No-workaround rules

  • No eager placeholder binding, tree-walker/AST callback from constructor bytecode, source rewriting, duplicated/skipped brands or fields, post-argument superclass lookup, observable default-constructor spread, constructor-shape whitelist, permissive policy default, or hidden fallback in required mode.
  • No stacks, queues, jobs, Promise, microtask, Worker lifecycle, or Map/Set iterator changes.

Acceptance

  • Forced tree-walker and required bytecode agree on explicit/default derived construction, extends null, dynamic superclass mutation, argument order, repeated/missing super(), object/undefined/primitive returns, and alternate superclass objects.
  • Public/private fields, auto-accessors, brands, computed names, parameter initialization, this/super/new.target, direct eval, lexical arrows, exceptions/finally, recursion/reentry, and debugger/watchdog state preserve exact ordering.
  • Moving-GC/compaction, deterministic OOM restoration, native shared-chunk no-GIL, TSan, focused compiler/VM/frontend, full units, threadfuzz, and exact nonzero relevant Test262 accounting pass with zero regressions.
  • Admission inventory compiles complete derived constructors, retains causal barriers for incomplete nested lowering, and introduces no interpreter callback or hidden fallback.
  • A conventional commit lands directly on main and cross-links #465, #498, #746, and #747.
9 days ago

Implementation mapping is complete. The VM change will extend activation save/restore with the shared derived-this cell and lexical constructor state; compile superclass capture before argument effects; perform explicit-new.target construction and one-shot binding; reuse #747 bytecode field operations after successful super(); handle default direct forwarding and derived completion centrally; and keep direct-eval/unsupported nested lowering causal. No jobs/Promise/microtask/Worker lifecycle or Map/Set iterator surfaces are in scope.

9 days ago

Landed in afb9ce2c on main.

The VM now owns derived constructor activation state, one-shot this publication, explicit/spread/default super() construction, post-super brands and fields, derived completion at bytecode/native/OSR exits, lexical-arrow propagation, and exact superclass/key evaluation order. Direct eval remains the explicit causal plain_rejected_unsupported_lowering boundary; required mode never falls back.

Validation:

  • Test262 statements/class: 4,367 -> 4,367 pass; expressions/class: 4,059 -> 4,059 pass; 0 failures and 0 flips.
  • Full units: 1,895 pass, 1 skip, 0 fail/leak.
  • Focused frontend: 26/26; deterministic OOM restoration passed.
  • Derived TSan: 3/3; shared no-GIL TSan: 1/1.
  • Threadfuzz: 400/400 normal and 400/400 TSan, 0 failures.
  • ABI audits: Home public 50/50, Home private 447/447, Bun private 437/437; C API fixtures passed.
  • Docs: 277-file link audit and 50-page manifest-checked build passed.

Sign in to comment on this issue.