fix(runtime): TypedArray map/filter/every/some/forEach/find/findIndex read element-typed storage - #2499
Merged
Merged
Conversation
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).
This was referenced May 30, 2026
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>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
%TypedArray%.prototypeiteration methods produced wrong results because they lowered to the genericExpr::Array*variants, whosejs_array_*helpers read the receiver as a regularArrayHeaderof NaN-boxedf64— but a TypedArray's storage is rawint/float. So on a typed array:mapreturned garbage f64s (e.g.Int32Array([1,2,3]).map(x=>x*2)→[1.016e-320, …])filterreturned[]every/somereturned the wrong booleanfind/findIndex/forEachread garbage elementsFix
Add the established
lookup_typed_array_kind(...)delegation guard — the same patternjs_array_sort/js_array_at/js_array_find_lastalready use — tojs_array_map/filter/every/some/forEach/find/findIndex, and implement the element-typedjs_typed_array_*equivalents (reading via the per-kindload_at, writing viastore_at).map/filterreturn 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
Int32ArrayandFloat64Array:Regular-array
map/filter/every/some/find/forEachover numbers, objects, and strings are unaffected (verified byte-identical to Node).cargo fmtclean.Scope / follow-ups
This fixes instance method-call correctness (
ta.map(...)), which is what real code uses. It does not by itself move the test262built-ins/TypedArrayconformance score, which is gated by the reflective/descriptor layer —TypedArray.prototype.<m>reified as a callable value,.name/.lengthown-property descriptors,Symbol.species, and spec-mandated throws (detached buffer, non-callable arg). Those, plus the still-unwiredfill/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.