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
Browse filesBrowse the repository at this point in the historyBrowse files
Ralph Küpper
committed
perf(codegen): version stable packed array loops
Lands #8719 with its soundness blocker fixed.
The blocker was NOT where the emitted IR first suggested. The symptom was
an unguarded `fptosi` + `xor i32` consuming a phi that merged a proven
number (the string arm of a guarded `charCodeAt`) with an arbitrary user
method's result (the generic arm) -- so an `any` receiver returning a
BigInt yielded garbage where the spec requires BigInt xor or a TypeError.
The cause is one lever in `expr/literals_vars.rs`. The PR's new
`explicit_numeric_toint32` disjunct bypassed
`can_lower_expr_as_i32_in_current_region`, which correctly answers false
for `(h ^ recv.charCodeAt(i)) | 0`, and called into the
`lower_expr_as_i32` family without its documented precondition.
`lower_expr_native_i32`'s i32-chain arm then recursed structurally,
`fptosi`-ing every operand it could not lower natively -- so `binary.rs`,
which already applies `is_provably_not_bigint` per operand, was bypassed
entirely rather than mishandling the join.
`expr_produces_canonical_raw_f64` is a claim about the VALUE the ordinary
lowering produces, not a licence to re-evaluate its operands natively.
The fix lowers through `lower_expr` and applies `toint32_fast`, so an
unproven tree keeps `js_dynamic_bitxor` while a proven one still gets the
inline `xor i32`. The i32-slot store the lever exists for is preserved,
so this remains an improvement over main, which took neither branch here.
House precedent settles the alternative: `lower_guarded_numeric_add`'s
doc block records that sinking arithmetic into the arms was already tried
and is worse -- per-node diamonds make the outer add consume a phi that
LLVM cannot prove canonical, and that shape went 86 ms -> 119 ms.
The negative control passes UNMODIFIED (blob hash identical to main), and
both positive tests still fire the fast path for proven receivers.
No version bump.
- Loop-version stable counted iteration over packed `Array` and `Array` subclasses, with fallback-free direct reads and mutation-safe current-index side exits.
4
+
5
+
### Fixed
6
+
7
+
- The `x | 0` canonical-ToInt32 store lever no longer re-evaluates its operand
8
+
tree as native i32. `expr_produces_canonical_raw_f64` vouches for the RESULT
9
+
of `x | 0`, not for `x`'s operands, so consuming it as a licence to call
10
+
`lower_expr_native(_, I32)` violated that path's documented precondition
11
+
(`can_lower_expr_as_i32_in_current_region`). The i32-chain arm `fptosi`s
12
+
every operand it cannot lower natively, which turned
13
+
`h ^ recv.charCodeAt(i)` on an `any` receiver into an inline `xor i32` over
14
+
whatever that method returned — a BigInt silently produced garbage instead
15
+
of the spec's `TypeError`. The lever now lowers through `lower_expr`, which
16
+
applies `is_provably_not_bigint` per operand, and takes one trailing
17
+
`toint32_fast` to feed the i32 slot; `x | 0` always lowers to `sitofp i32`,
18
+
so that pair folds away. A proven tree still gets the inline `xor i32` and
19
+
keeps the i32-slot store. Pinned by the pre-existing negative control
0 commit comments