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
{{ message }}
Repository navigation
arr[i] = v never observes an inherited index accessor or non-writable inherited index — the strict store's fast lanes bypass array_spec_set #9220
An indexed write to an array never consults the prototype chain. arr[i] = v lowers to js_array_set_f64_extend_strict, whose fast lanes go straight to the element storage; only array_spec_set (used by push/shift/reverse) does the [[Set]] walk.
constproto={};Object.defineProperty(proto,9,{set(v){calls.push(v);},get(){return"acc9";}});consta=[1,2,3];Object.setPrototypeOf(a,proto);a[9]=5;// node: the setter runs; a has NO own property "9"// perry: no setter call; an own element 9 is created
The same gap applies to a non-writable inherited index, where ES requires the write to be rejected (silently in sloppy mode, TypeError in strict).
Not the setPrototypeOf bug
This is pre-existing and independent of #9192. It was found while fixing that issue, and the control that proves it is the point: the divergence reproduces identically when the prototype is itself an array, i.e. on the shape that has always been supported. #9192's fix (#9219) corrects the read side; this is the write side and is untouched by it.
Impact
Silent, and in the direction that matters: a program that installs an index setter to intercept writes sees nothing, and the array quietly gains an own property the author intended to be virtual. Accessor-backed array-likes and the ES5 Object.create(Array.prototype) idiom both hit it.
Fix direction
js_array_set_f64_extend_strict's fast lanes need the same recorded-prototype classification the read path now has — ArrayCustomProto::{Null, Array, Other} in crates/perry-runtime/src/array/indexing.rs, added by #9219. The cheap gate is the existing per-array "has a recorded prototype" check: an array with the default chain keeps today's lanes untouched, and only a retargeted array pays the [[Set]] walk. Note the ordering requirement — an inherited data property does not stop an own-property create, only an accessor or a non-writable one does.
There is a differential harness with controls for this in the #9219 branch (checks 085–087), so the regression instrument already exists.
Activity
perf(runtime): gate the strict lane's hole decline on the array-proto…
refactor(runtime): split the spec prototype-chain block out of indexi…
perf(runtime): gate the strict lane's hole decline on the array-proto…
refactor(runtime): split the spec prototype-chain block out of indexi…
fix(runtime): indexed writes honour a custom array prototype (from #9297
fix(runtime): a rejected array element write throws only in strict mo…
proggeramlug commentedon Sep 2, 2026
Closing: fixed by #9297, re-landed as #9370 after the #9345 revert was shown to be mis-attributed. Fragment 9220-array-prototype-index-paths.md.