-
-
Notifications
You must be signed in to change notification settings - Fork 158
fix(runtime): a borrowed builtin is only an Array builtin when it IS Array.prototype[m] (#5902) #7471
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
fix(runtime): a borrowed builtin is only an Array builtin when it IS Array.prototype[m] (#5902) #7471
Changes from all commits
Commits
Show all changes
2 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| fix(runtime): a borrowed builtin only runs the array engine when it IS `Array.prototype[method]` (#5902). `classify_own_slot` (`array/generic.rs`) decides whether an own slot holding a builtin closure means "the array-like engine must run on this receiver", but it asked only "is this a non-constructable builtin closure?" — a test every builtin prototype method passes, with the owning prototype never checked. So `obj.concat = String.prototype.concat` was read as a borrowed *Array* builtin and ran the array algorithm, yielding `[obj, "two", undefined]` instead of `"onetwoundefined"` (test262 `built-ins/String/prototype/concat/S15.5.4.6_A4_T1`) — while the equivalent `String.prototype.concat.call(obj, …)` was already correct, which is the tell that this was dispatch and not coercion. The new `is_array_prototype_method_value` compares the slot against the real `Array.prototype[method]` by closure FUNCTION POINTER rather than by closure identity: reading `Array.prototype.concat` can hand back a freshly reified closure, so identity would give false negatives, while every reification of one builtin shares a single code address — and a func ptr is a code address, not a heap pointer, so nothing here becomes GC-visible and no root scanner is required. The `BOUND_METHOD_FUNC_PTR` arm is untouched and the new check gates only the raw-builtin-thunk arm, so the behavior the classification exists to protect is preserved: a genuine `obj.pop = Array.prototype.pop` borrow still runs the engine on the real receiver instead of looping on its captured `Array.prototype`. test262 `built-ins/String/prototype/concat` 20/21 → 21/21 (parity 100%); `Array/prototype/{concat,push,pop,splice,sort,shift,unshift,reverse}` zero regressions — 10 remaining failures are named in #5898's baseline (including `unshift/S15.4.4.13_A4_T1`, which itself borrows `Array.prototype.unshift` and is unchanged), and `Array/prototype/concat/S15.4.4.4_A1_T2`, absent from that snapshot, was proven pre-existing by rebuilding without the change and reproducing it identically. A differential probe matches node byte-for-byte on all 8 lines, covering both directions (the String borrow, genuine Array borrows of concat/push/pop/splice, a same-named user method, plain arrays). New per-PR-visible coverage: a `perry-runtime --lib` unit test pinning both directions of the discriminator plus the wrong-method-name and non-callable cases, which cannot pass vacuously — an always-true or always-false predicate fails one of its asserts. |
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
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
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
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
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
Oops, something went wrong.
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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🎯 Functional Correctness | 🟠 Major | 🏗️ Heavy lift
Use a stable Array builtin mapping for classification.
A slot can retain the original
Array.prototype.concatclosure after JavaScript replacesArray.prototype.concat. This lookup then compares the saved native closure with the replacement, returnsfalse, and routes the saved Array builtin through the user-method path. That path does not preserve raw Array builtin receiver dispatch.Map each supported method to its stable native thunk pointer. Add a test that saves an Array method, replaces
Array.prototype[method], and invokes the saved method from an own slot.🤖 Prompt for AI Agents
🩺 Stability & Availability | 🔴 Critical | 🏗️ Heavy lift
Root GC values before allocating.
js_string_from_bytescan collect or relocateArray.prototypeafter line 258, but line 263 still dereferences the unrootedproto_ptr. The test has the same unsafe pattern. Retrying after a collection does not prevent the stale-pointer use in that iteration.crates/perry-runtime/src/object/global_this/ctor_thunks.rs#L253-L263: Rootprotoand the generated key inRuntimeHandleScope. Reload the prototype pointer after key allocation.crates/perry-runtime/src/array/tests.rs#L1667-L1715: Rootglobal,array_proto, andstring_proto. Reload each raw pointer after allocating calls before property access.Based on learnings: raw Rust pointer locals are neither GC roots nor reliable pins across allocating operations.
📍 Affects 2 files
crates/perry-runtime/src/object/global_this/ctor_thunks.rs#L253-L263(this comment)crates/perry-runtime/src/array/tests.rs#L1667-L1715🤖 Prompt for AI Agents
Sources: Coding guidelines, Learnings