ReviewOS

zig-utils/zig-js

Optimizer: allocate closures with live activation bindings

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

Parent: #467

At 80e4595, warmed ordinary, arrow, and generator-producing factories return the correct [6,6,6] result in Node, JavaScriptCore, and zig-js. Their optimizer artifacts are enabled but have zero native bytecode steps and exit before the first make_closure instruction.

Implement closure allocation through the canonical VM factory together with live activation storage. Closure publication makes a defining Frame escape; later reads and writes must observe the same synchronized bindings as captured functions, including changes made during callbacks. Recoveries must preserve canonical live storage rather than overwrite it with stale SSA snapshots.

Scope:

  • Model closure allocation and activation storage locations as backend-neutral IR effects.
  • Retain SSA locals for functions whose activation has not become observable; use canonical frame-backed bindings where closure allocation or lexical/mapped binding semantics require them.
  • Preserve ordinary/named/arrow/generator/async template identity, lexical this/new.target/super/private/module context, immutable self-name bindings, capture environments, and existing allocation-failure behavior.
  • Support exact regular, mapped, and lexical local access and initialization in the admitted storage model, including TDZ-before-immutable ordering.
  • Preserve canonical frame locals across native callback, side exit and OSR; keep precise roots and escaped-frame synchronization.

Acceptance:

  • Warmed factories execute actual native closure allocation and continue through correct live local reads/writes without stale snapshots or recompile loops.
  • Off/on differentials cover escaped writes, closure callbacks mutating the defining activation, mapped parameters, lexical/TDZ/const behavior, named functions, arrows, generator/async templates, and realm/context capture.
  • Serialized and no-GIL worker controls, GC/relocation, recursion, exact budget/termination, OOM and retirement tests pass.
  • IR/native metadata verifiers reject malformed storage locations, local recoveries, operand roots, and activation requirements.
  • Relevant Debug/ReleaseSafe/unsuppressed TSan, production, exact-parent conformance and threadfuzz gates pass with nonzero denominators. The combined cold unit link remains the separate human memory-policy blocker in #933.
  • Document actual admission and the remaining #467 language/control boundary precisely.

No source-name recognition, copied environment snapshots, unsynchronized escaped-slot access, or disguised full-language claim.

9 days ago

Landed in 4010bc51.

Closure templates allocate through the canonical VM factory. Observable activations use synchronized regular/mapped/lexical binding effects; unobservable locals retain SSA. Native entry checks the owning chunk and actual slot storage. Recovery preserves live locals, OSR imports storage locations, and scoped native roots retain suspended callers and their frames.

The pinned controls cover actual native factory completions, closure callbacks changing the defining frame, mapped arguments, TDZ/const ordering, named/arrow/generator/async templates, receiver/new-target/super/private context, realms/modules, retirement, OOM cleanup, exact budget/termination, and four shared workers. The moving-GC witness relocates both escaped frames and a suspended parent's scratch object in serialized and parallel modes. Metadata mutations reject locations used as operands/results/control, stale local recoveries, invalid masks and malformed activation storage.

Validation:

  • 18 focused Debug controls; 253 ReleaseSafe tests; 253 unsuppressed ReleaseSafe TSan tests; 25 unsuppressed Debug TSan controls. Both sanitizer builds instrument the engine, regex and GC modules; sanitizer symbols were checked, TSAN_OPTIONS was unset and no suppressions were supplied. The earlier broad Debug TSan run was interrupted and is not passing evidence.
  • Production: JIT 158 pass / 1 skip; VM 7, concurrency 4 and frontend 79 pass; the focused production TSan fixture, library, root inventory and 378-file link check pass. Pinned BunPress builds/checks 51 pages with only the optimizer page's manifest outputs changed.
  • Exact-parent test262: 7,014 cases across 11 subtrees pass before and after, with zero failures or VM divergences on either side. Counts: function expressions 264, declarations 451, arrows 343, generators 290, async functions 93, async generators 623, classes 4,059, arguments 263, eval 347, let 145 and const 136. Flips 0 cases. Each subtree ran with --diag and --vm-witness-subtree; exact bad-path sets and nonzero denominators were checked.
  • Threadfuzz: default 400 and broad 300 deterministic programs, zero failures.
  • Production factory probe: [[1,1,1],[1,1,1],[6,6,6]] before and after another 256 invocations of each warmed factory. Native-completion assertions independently prove that the candidate factories execute the new effects.

Before binary (80e4595) SHA-256: b5214f0b2e2837a1a72ccda0bf2620cbd1d4f98bde72fb769cf3109ee4141239. After: b52583c4c1d7fffeb70d79be90c7a42515754636bd1cc77af8e39b7c9fde2ed1. Corpus revision: 4249661388e5d3f92a85186213da140a6481490f.

The parent #467 remains open for its remaining language/control boundary. The combined cold unit link remains the memory-policy gate in #933; the independently observed hosted Condition notification failure is tracked by #1103. This does not claim a green full hosted matrix or a public speedup.

Sign in to comment on this issue.