perf(codegen): a fixed-size allocation expression keeps the buffer-view tier (bench_int_arithmetic 395 → 149 ms) - #9181
Conversation
|
Caution Review failedThe pull request is closed. ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (1)
📝 WalkthroughWalkthroughThe compiler now recognizes arithmetic expressions with fixed-length operands as known ChangesUint8Array allocation handling
Estimated code review effort: 1 (Trivial) | ~5 minutes Merge Risk: ⚪ Minimal · up to The change allows fixed-size arithmetic allocation expressions to retain the optimized buffer-view path, improving performance while preserving the documented correctness behavior; no actionable merge-blocking risk remains. 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
Full details: Title checkExplanation The title clearly identifies the primary code-generation optimization and its performance impact. The reported benchmark values differ from the detailed measurements, but the title remains directly related to the main change. Full details: Description checkExplanation The description is detailed and covers the motivation, implementation, related issue, performance measurements, and correctness validation. It does not use the template headings or include the required checklist and explicit build/test command status, but the substantive information is mostly complete. Full details: Docstring CoverageExplanation Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 1 functions across 1 files. (1 skipped: 1 unsupported.)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
Gate on the Linux box, commit Lint: formatting PASS, CI-plan self-test PASS, gap-snapshot self-test PASS, parity-allowlist PASS, no ratchet ceilings raised. The 3 FAIL steps are the environmental ones (unexpanded Runtime suite: Same set I demonstrated on unmodified Might be worth an issue to run these three with |
…ew tier (bench_int_arithmetic 395 -> 149 ms) Follow-up to PerryTS#9146, which left this on the table. is_fresh_uint8array_length_expr accepted a literal or a known-length local but nothing built from them, so `new Uint8Array(SIZE * SIZE)` was never classified as a freshly allocated owned buffer. With no classification the receiver gets no buffer view, and with no view every element read falls back to js_uint8array_index_get_value no matter how well the index is proven -- which is why bench_int_arithmetic still paid 54 calls per pixel after PerryTS#9146's interval bounds proof. Changing only that benchmark's allocation to a literal length was what isolated it: 395 -> 168 ms with the calls gone. The predicate asks whether the allocation's SIZE is fixed, never what it is (length_source_from_expr resolves the value later with a FnCtx, and records no constant length when it cannot), so a sum, difference or product of literals and known-length locals qualifies on exactly the same argument as either leaf. Mac mini, against this change's exact merge base, both binaries built in one run, interleaved, min of 5, self-timed: bench_int_arithmetic 462 -> 149 ms (node 62), 7.5x node down to 2.4x, identical checksums. Both PerryTS#9146 differentials stay byte-identical to node, and the probe whose interval genuinely exceeds its buffer still declines to the checked call. Claude-Session: https://claude.ai/code/session_012Ys25ni6VwDKE71o1NTYAT
7b5b311 to
5cde4aa
Compare
|
Merged (rebased onto Verified the subject is actually live, rather than trusting the benchmark — the number moving is not by itself evidence the predicate is what moved it. IR-diffed
and a dynamic The one thing I checked hard is that the new It turns out not to matter, and I confirmed rather than reasoned it: a negative or oversized length throws One divergence surfaced and it is not yours: Validation: Renamed the changelog fragment to the PR-keyed |
Follow-up to #9146, which named this as the thing it left on the table. It turned out not to be about the index at all.
The gap
is_fresh_uint8array_length_expraccepts a literal or a known-length local, but nothing built from them — sonew Uint8Array(SIZE * SIZE)was never classified as a freshly allocated owned buffer. Without that classification the receiver gets no view, and with no view every element read falls back tojs_uint8array_index_get_value, however well its index is proven and however inline the arithmetic around it already is.That is why
bench_int_arithmeticstill paid 54 calls per pixel after #9146's interval bounds proof landed. What isolated it: changing only that benchmark's allocation to a literal length, nothing else touched, took it 395 → 168 ms with the calls gone.Why the relaxation is the same argument, not a wider one
The predicate asks whether the allocation's size is fixed, never what it is.
length_source_from_exprresolves the value later, with aFnCtxin hand, and records no constant length when it cannot — in which case the bounds proof simply declines. A sum, difference or product of literals and known-length locals is exactly as fixed as either leaf on its own.Measurements
Mac mini, against this change's exact merge base, both binaries built in one run, interleaved, min of five, self-timed:
bench_int_arithmetic7.5× Node → 2.4×, identical checksums on both binaries.
Correctness
Both differentials from #9146 stay byte-identical to Node — eight cases around the byte read (in-bounds accumulate, OOB inside
+=, OOB as a value, string concat, negative and fractional indices,Bufferreceiver, mixed accumulator) and seven around the bounds proof (exact kernel shape, interval touching the last element, counter mutated in the body, out-of-range interval, one-past-the-end, negative composite index, non-constant length). The probe whose interval genuinely exceeds its buffer still declines to the checked call rather than reading out of bounds.Note on provenance
This commit was pushed to #9146's branch shortly after that PR merged, so it never appeared under review anywhere — I found it while checking that my branches still merged cleanly against main. It is rebased onto current main here with its own changelog fragment; #9146's fragment is restored to the merged text.
https://claude.ai/code/session_012Ys25ni6VwDKE71o1NTYAT
Summary by CodeRabbit
Performance
Uint8Arrayallocations using fixed-size arithmetic expressions, helping retain efficient buffer-view optimizations.Documentation