You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
After #9360 the read itself is an inline guarded byte load, and the guard is free — forcing it to always hit moves 216 ms to 218 ms. The per-element cost that remains is the accumulator:
%acc.rs4p = loadptraddrspace(1), ptr%slot; accumulator, from the GC shadow frame
... guarded_add.numeric / guarded_add.dynamic diamond ...
storeptraddrspace(1) null, ptr%slot
plus a js_write_barrier_root_nanbox per iteration. The equivalent top-level loop, whose receiver IS a tracked view, has none of it: bare fadd, register accumulator, 49 ms vs node's 44.
Why
lower_guarded_numeric_add roots every leaf that expr_produces_canonical_raw_f64 will not vouch for, because the cold arm can call js_dynamic_string_or_number_add. That predicate admits IndexGet under exactly one condition — stable_packed_loop::has_numeric_index_fact — and does not match Uint8ArrayGet at all. It cannot: the node's value is a byte or undefined for an out-of-range index (#6884, correct ECMAScript semantics — not the registry-miss bug #9342 fixed; those are two different undefineds that happen to share a tag).
So the read has to become vouchable, which needs both halves:
A numeric fact for the region, the way the stable-packed tier already produces one — that is what makes the read vouchable and, inductively, the accumulator's Binary node numeric.
With both, the diamond disappears: no rooting, no shadow-frame traffic, no per-element barrier, plain fadd.
Why this is worth more than one row
This is a statement about a predicate, not about Uint8Array. Any accumulate-over-reads loop whose read is not served by a proven tier pays the same per-element shadow-frame load + store + write barrier + tag-test diamond. The u8 case is just where it was measured.
Also here
function f(b: Uint8Array) — a typed-parameter receiver — never admits the inline lane at all (576 ms, unchanged by #9360): the class proof comes back empty for a declared-type parameter, where a module-global gets one from module_global_proven_types.
Caution
expr_produces_canonical_raw_f64's soundness contract is load-bearing and scarred: its doc records a case where skipping the accumulator leaf summed 16zw1113151719 down to 16zw. Any widening needs the #9303 treatment — peel-as-contract at match time, then post-verify every write with the lowering's own collector — not a static type check.
Fixture and harness: buf_ctx.ts shape in #9342; measurement discipline and the forced-guard discriminator are recorded there.
Split out of #9342, where it is measured and the wrong attribution is ruled out.
The shape
After #9360 the read itself is an inline guarded byte load, and the guard is free — forcing it to always hit moves 216 ms to 218 ms. The per-element cost that remains is the accumulator:
plus a
js_write_barrier_root_nanboxper iteration. The equivalent top-level loop, whose receiver IS a tracked view, has none of it: barefadd, register accumulator, 49 ms vs node's 44.Why
lower_guarded_numeric_addroots every leaf thatexpr_produces_canonical_raw_f64will not vouch for, because the cold arm can calljs_dynamic_string_or_number_add. That predicate admitsIndexGetunder exactly one condition —stable_packed_loop::has_numeric_index_fact— and does not matchUint8ArrayGetat all. It cannot: the node's value is a byte orundefinedfor an out-of-range index (#6884, correct ECMAScript semantics — not the registry-miss bug #9342 fixed; those are two differentundefineds that happen to share a tag).So the read has to become vouchable, which needs both halves:
Binarynode numeric.undefinedbox and yield a genuine canonical raw f64. Value context keepsundefined.With both, the diamond disappears: no rooting, no shadow-frame traffic, no per-element barrier, plain
fadd.Why this is worth more than one row
This is a statement about a predicate, not about
Uint8Array. Any accumulate-over-reads loop whose read is not served by a proven tier pays the same per-element shadow-frame load + store + write barrier + tag-test diamond. The u8 case is just where it was measured.Also here
function f(b: Uint8Array)— a typed-parameter receiver — never admits the inline lane at all (576 ms, unchanged by #9360): the class proof comes back empty for a declared-type parameter, where a module-global gets one frommodule_global_proven_types.Caution
expr_produces_canonical_raw_f64's soundness contract is load-bearing and scarred: its doc records a case where skipping the accumulator leaf summed16zw1113151719down to16zw. Any widening needs the #9303 treatment — peel-as-contract at match time, then post-verify every write with the lowering's own collector — not a static type check.Fixture and harness:
buf_ctx.tsshape in #9342; measurement discipline and the forced-guard discriminator are recorded there.