ReviewOS

zig-utils/zig-js

Compiler: inventory plain-function bindings once

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

Parents: #465, #493, #496 Related: #615

Problem

Compiler.compilePlainFunctionInner first calls functionHasShadowableLexical; on the common no-shadow path it then calls functionHasTdzHazard. Both helpers independently allocate a spelling map, insert the same parameters and declarations, and walk the complete statement tree through shadowScanStmt before TDZ reference analysis begins. A detected lexical shadow correctly short-circuits the second helper today and must remain a neutral control.

The common-path cost is bounded but duplicated for every no-shadow bytecode-admitted plain function. Functions with no lexical bindings also perform a complete TDZ reference walk whose answer is provably false. Attacker-sized declaration and statement surfaces therefore pay duplicate hashing, allocation, and AST traversal before lowering. #615 removed the more severe per-pending-name reference scans; this child owns the remaining duplicate inventory and empty-lexical work without changing TDZ policy.

Scope

  • Add exact parse-plus-plain-function-compile witnesses at 1K/2K/4K declaration widths.
  • Include unique lexical growth, var-only, repeated/shadowed lexical, parameter-shadow, destructuring, nested-control, and real TDZ-hazard controls.
  • Produce one immutable binding inventory that supplies shadowing, lexical-presence, and pending-lexical membership for TDZ analysis.
  • Skip TDZ reference analysis only when that exhaustive inventory proves the function owns no lexical binding.
  • Preserve distinct-slot lexical lowering, conservative spelling-based shadow handling, exhaustive AST coverage, and allocation failure propagation.
  • Measure structural checksum/admission/opcode policy, allocations/bytes, instructions/cycles, and wall diagnostics through the exact-parent pipeline.

No-workaround rules

  • No weakening TDZ checks, merging distinct bindings, skipping declaration forms, caching mutable AST identity globally, or broadening checked opcodes to avoid exact classification.

Acceptance

  • The benchmark contract proves exact admission, chunk shape/checksum, local/lexical slot inventory, and checked-opcode policy for every control.
  • Binding inventory and shadow classification traverse the function declaration surface once.
  • Exact-parent growth evidence demonstrates the removed traversal/allocation cost without semantic or checksum drift.
  • Focused compiler/frontend and forced tree-walker↔required-bytecode differentials pass.
  • Relevant Test262 function/lexical/destructuring/control-flow subtrees have nonzero, exact before→after accounting with zero regressions.
  • Full units and applicable sanitizer gates pass.
9 days ago

Landed benchmark-first on main:

  • 3bc06b01 — bench(frontend): add binding inventory witness (#621)
  • 84efdae5 — perf(compiler): reuse plain-function binding inventory (#621)

The implementation builds one exhaustive spelling inventory, reuses it for shadow and TDZ decisions, and skips the TDZ reference walk only when the inventory proves there is no lexical binding. Both top-level and nested plain-function compilation use the same helper. Repeated lexical and parameter-shadow cases retain the prior conservative short-circuit.

Functional benchmark replay:

  • every one of nine admission/chunk checksums is parent/candidate exact;
  • unique 1K/2K/4K removes 9/10/11 allocation requests and 102,416/204,840/409,664 bytes;
  • var-only, destructuring rejection, nested-control, and forward-TDZ 4K each remove 11 requests / 409,664 bytes;
  • repeated-lexical and parameter-shadow controls remain allocation-byte exact;
  • parent/candidate runner SHA-256: 4a38d5f2683a29a3328aab24bff60a09d661c11cc446b18c29a7df9e9554edb1 / 02f9d72a5549f66e4a88f40cb9e7075ff09b9734d96abe2b248a6f2074632dbc.

Correctness gates:

  • compiler-filtered units: 71/71 normally and 71/71 under TSan, zero leaks;
  • focused frontend: 12/12;
  • full sharded units: 1,734 pass / 1 platform skip / 0 fail / 0 leak across 10 shards;
  • dependency audit: 15 edges / 0 migrations / 60 tools.

Exact Test262 binaries were rebuilt after the final commit-message-only amendment (parent d0dbf143…, candidate 0d9c1495…). Ten independently guarded, byte-identical pairs cover expressions/function 264, statements/function 451, variable 178, let 145, const 136, destructuring/binding 19, block 21, if 69, try 201, and for 385: 0 fail / 1,869 pass → 0 / 1,869, zero flips.

#621 remains open for the forced tier corpus witness and guarded exact-parent instructions/cycles/allocation publication. No wall-time claim is made from functional replays.

9 days ago

Forced tier identity is now complete without entering the separate thread/job witness: the established try/dstr/obj-ptrn-rest-getter.js and try/dstr/ary-init-iter-close.js Test262 cases both pass in forced tree-walker and required-bytecode modes on the final #621 candidate, with clear before/after process snapshots. Together with 71/71 compiler, 12/12 frontend, and 71/71 compiler TSan, the focused/differential acceptance row is complete. Only guarded exact-parent growth evidence remains.

9 days ago

Guarded evidence setup has been rebuilt without accepting or publishing timing:

  • exact parent: 3bc06b01
  • exact candidate: 84efdae5
  • toolchain: Zig 0.17.0-dev.1441+d5181a9c9
  • frozen source SHA-256: 159f6aa7448f19389d361bef4331ec8033acd40e835f6f838eb0101486788b26
  • durable parent/candidate runner SHA-256: 04c9c70c53080ae313d293eaee5a4e63aecea6632efdcb82342bdaa1cb8b0381 / 3775bd4d25d7072a73e68d1e4a00195bb56d741cbc60ed6300761ee4686a2997

Parent and candidate functional replay at 1K/2K/4K is checksum-identical. At 64 logical jobs the exact checksums are 10666555712, 41935887616, and 38728115584. The current exact-parent and algorithmic-growth self-tests both pass from a clean current-main collector worktree.

No performance sample has been retained: an unrelated Home Zig test remains alive and is correctly classified by #617 as a competing job. Collection will start only after the process exits and the host passes the same fail-closed preflight.

9 days ago

Exact-parent growth evidence landed in 1a0cf6e2 (`evidence(compiler): land binding-inventory growth rows (#621)`).

Contract: parent `3bc06b0` -> candidate `84efdae` (first-parent verified), Zig `0.17.0-dev.1441+d5181a9`, quiet_reference host, AC power, seven order-balanced pairs per width at jobs=10 over the deterministic `binding_inventory_unique` witness (checksums 1666649330 / 6552482440 / 6051268060 matched exactly on both variants at every sample).

Result: both sides remain linear — first-to-last exponent parent 1.003 vs candidate 1.003, exactly as expected for removing a constant-factor duplicate traversal rather than changing asymptotics — while the candidate strictly reduces work at every width:

widthinstructions cand/parentallocations/job P/Cbytes/job P/C
10240.9401x3217 / 32082529009 / 2426593
20480.9397x6307 / 62975643177 / 5438337
40960.9405x12467

Sign in to comment on this issue.