Skip to content

fix(runtime): TypedArray map/filter/every/some/forEach/find/findIndex read element-typed storage - #2499

Merged
proggeramlug merged 1 commit into
mainfrom
fix/typedarray-methods
May 29, 2026
Merged

fix(runtime): TypedArray map/filter/every/some/forEach/find/findIndex read element-typed storage#2499
proggeramlug merged 1 commit into
mainfrom
fix/typedarray-methods

Conversation

@proggeramlug

Copy link
Copy Markdown
Contributor

Summary

%TypedArray%.prototype iteration methods produced wrong results because they lowered to the generic Expr::Array* variants, whose js_array_* helpers read the receiver as a regular ArrayHeader of NaN-boxed f64 — but a TypedArray's storage is raw int/float. So on a typed array:

  • map returned garbage f64s (e.g. Int32Array([1,2,3]).map(x=>x*2)[1.016e-320, …])
  • filter returned []
  • every / some returned the wrong boolean
  • find / findIndex / forEach read garbage elements

Fix

Add the established lookup_typed_array_kind(...) delegation guard — the same pattern js_array_sort / js_array_at / js_array_find_last already use — to js_array_map / filter / every / some / forEach / find / findIndex, and implement the element-typed js_typed_array_* equivalents (reading via the per-kind load_at, writing via store_at). map / filter return a same-kind TypedArray per spec.

The guard only fires for genuine TypedArray pointers, so the regular-array hot path is byte-for-byte unchanged.

Testing

Byte-identical to Node for Int32Array and Float64Array:

map [ 2, 4, 6, 8, 10 ]      filter [ 3, 4, 5 ]      every true   some true
find 4   findIndex 3   forEach (value, index)   Float64Array.map [ 2, 3, 4 ]

Regular-array map/filter/every/some/find/forEach over numbers, objects, and strings are unaffected (verified byte-identical to Node). cargo fmt clean.

Scope / follow-ups

This fixes instance method-call correctness (ta.map(...)), which is what real code uses. It does not by itself move the test262 built-ins/TypedArray conformance score, which is gated by the reflective/descriptor layer — TypedArray.prototype.<m> reified as a callable value, .name/.length own-property descriptors, Symbol.species, and spec-mandated throws (detached buffer, non-callable arg). Those, plus the still-unwired fill/copyWithin/reduce/join/indexOf/includes, are the follow-ups.

Version bump + CHANGELOG entry intentionally omitted — please fold in at merge to avoid patch-version collisions with fast-moving main.

These %TypedArray%.prototype iteration methods lowered to the generic
Expr::Array* variants, whose js_array_* helpers read the receiver as a
regular ArrayHeader of NaN-boxed f64 — but TypedArray storage is raw
int/float, so map returned garbage, filter returned [], and every/some
returned wrong results.

Add the established lookup_typed_array_kind delegation guard (same pattern
js_array_sort / at / findLast already use) to js_array_map/filter/every/
some/forEach/find/findIndex, and implement the js_typed_array_* element-
typed equivalents. map/filter return a same-kind TypedArray per spec.

Verified byte-identical to Node for Int32Array and Float64Array; regular
array map/filter/every/some/find/forEach unaffected (guard only fires for
genuine TypedArray pointers).
@proggeramlug
proggeramlug merged commit 2051232 into main May 29, 2026
11 checks passed
@proggeramlug
proggeramlug deleted the fix/typedarray-methods branch May 29, 2026 16:22
proggeramlug added a commit that referenced this pull request May 31, 2026
…anceof (#3148) (#3538)

Follow-up to PR #2499. Adds the still-missing %TypedArray%.prototype
methods (reduce/reduceRight/copyWithin/findIndex/set were already landed
on main; this fills the rest) by routing them through the generic
js_array_* helpers, which delegate to element-typed js_typed_array_*
impls via lookup_typed_array_kind:

- join (default + custom separator), reverse (in-place), fill / fill(value,start,end)
- slice / subarray — return a same-kind TypedArray
- copyWithin — js_array_copy_within now delegates to js_typed_array_copy_within
  (the existing immutable.rs path was unguarded; the broadened is_array_expr
  routes TA receivers through it, so the guard is required to avoid reading
  the element-typed buffer as boxed f64)
- keys / values / entries — materialize element-typed before building the
  iterator object so iteration yields numbers, not raw f64 bytes
- set(source, offset?) — codegen "set"/"subarray" arms + extern decls

indexOf / lastIndexOf / includes already delegate (pre-existing, #2457).

instanceof: reserved per-kind class ids (0xFFFF0030..3A) for all kinds
through BigUint64Array, resolved at runtime via class_id_for_kind so
`x instanceof Int32Array` is true (false for the wrong kind / non-TA).

Codegen routing: is_array_expr recognizes Named TA receivers so their
not-already-folded methods reach lower_array_method; the local_array_methods
slice arm folds TA receivers to ArraySlice.

Byte-matches `node --experimental-strip-types` for Int32Array and
Float64Array (test-files/test_gap_typed_array_proto_methods.ts). Plain
arrays and the already-landed TA methods (map/filter/at/with/sort) are
unaffected (guards only fire for genuine TA pointers).

Co-authored-by: Ralph Küpper <ralph@skelpo.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant