Parent #465; discovered while validating #824.\n\nThe moving-GC test for a borrowed foreign Array.prototype.map failed even after native realm tracing was corrected: the method held raw receiver/callback/result cells across ArraySpeciesCreate and callbacks. #824 is adding an invocation-rooted map implementation and moving probes at constructor/species lookup, length, HasProperty/Get, callback, and result definition.\n\nFollow-up audit scope: the remaining arrayMethod branches and helpers (filter, slice, concat, splice, flat/flatMap, iteration/search/reduce, sorting/copying) and Array.of/from native saved environments. Source inspection shows raw locals reused after user-observable calls in several of these paths. Those additional paths are an audit finding, not yet individually reproduced failures.\n\nAcceptance:\n- Use the existing precise temporary roots, reloading operands after every user callback; no GC disabling, pinning, stale-cell fallback, or new lifecycle machinery.\n- Preserve algorithm ordering, holes, live property mutations, custom species/proxy result definitions, abrupt completions, bounded scratch ownership, and dense fast paths when their guards remain valid.\n- Add deterministic moving-safepoint probes in forced tree-walker and required-bytecode modes for each affected callback boundary, plus OOM and no-GIL/TSan coverage where shared state is involved.\n- Compare the nonzero Array test262 subtree census and run the full native sharded unit suite before landing.\n\nThis is synchronous built-in operand ownership, not the separately owned stacks/queues/jobs or Promise/Worker lifecycle work.
Array: retain callback operands across moving collection in remaining methods
#827The map portion is now landed in fix(array): retain realm intrinsics across callbacks (#824). Its moving length/has/get/callback/species/result-definition probes pass both forced modes, including unsuppressed TSan and the full Debug suite. This issue continues to track the remaining methods/static saved-environment audit described above.
Landed the synchronous callback-method ownership checkpoint in fix(array): retain synchronous callback operands (#827).
This covers filter, forEach, some, every, find, findIndex, findLast, findLastIndex, reduce, reduceRight, and flatMap, including result/element retention and recursive flattening ownership. Receivers, callbacks, thisArg, results, and accumulators are reloaded from precise roots after observable callbacks.
Validation:
- New 11-method moving-GC witness passes both forced tree-walker and required-bytecode modes.
- Unsuppressed ReleaseSafe TSan focus: 1 pass, 0 failures/leaks/races.
- Exact ReleaseFast Array test262 comparison: 3,081/3,081 before -> 3,081/3,081 after; 0 flips, 0 regressions.
- Full native Debug suite: 2,195 pass, 1 skip, 0 fail, 0 leak across 2,196 discovered tests.
Validation also caught and rejected an intermediate no-GC reduce/reduceRight regression before landing: precise root slots are deliberately inactive without GC, so the final implementation keeps the ordinary accumulator synchronized as the no-GC source of truth.
Keeping #827 open for the remaining Array method audit, including sort/copy and slice/concat/splice/flat families.
Landed the static native-realm checkpoint in fix(array): restore Array.from caller realms (#827).
The audit used escaped functions from a managed caller realm invoking foreign Array natives directly, with moving collection inside the constructor/iterator boundary:
Array.ofalready preserved the caller realm and required no production change.Array.fromrestored a stale raw caller Environment after its iterator safepoint; the exact pre-fix witness resumed withReferenceError: Can't find variable: proxySubject.- The fix roots the saved caller Environment before entering the defining native realm and reloads it on exit.
Validation:
- Moving witnesses: pre-fix 1/2 pass -> candidate 2/2 pass in both forced tree-walker and required-bytecode modes.
- Unsuppressed ReleaseSafe TSan: 2/2 pass, 0 failures/leaks/races.
- Exact ReleaseFast Array test262 comparison: 3,081/3,081 before -> 3,081/3,081 after; byte-for-byte identical logs, 0 flips, 0 regressions.
- Full native Debug suite: 2,197 pass, 1 skip, 0 fail, 0 leak across 2,198 discovered tests.
Isolation also produced two separate exact findings, now tracked rather than folded into this change:
- #830: raw caller-realm restores in adjacent native wrappers.
- #831: child-realm native graph teardown leaks after an active moving call.
Keeping #827 open for the remaining slice/concat/splice/flat and sorting/copying audit.
Implemented and pushed the next Array moving-GC checkpoint:
a17a7046fix(array): retain species method operands (#827)- Covers
slice,concat,flat, andsplice. - Roots receivers, all retained arguments, and species-created results; reloads them after coercion, property, proxy, species, and indexed-access callbacks.
- Keeps the ordinary packed/dense paths while dynamically falling back when an exposed species result becomes exotic.
Evidence:
- Exact parent baseline fails the first moving witness (
sliceafter the borrowed receiver'slengthgetter). - Candidate passes all 8 moving scenarios in both forced execution modes.
- Unsuppressed TSan: 1/1 pass, 0 fail, 0 leak, no race report.
- Array test262: 3,081/3,081 before → 3,081/3,081 after; byte-identical census, 0 regressions.
- Full Debug: 2,198 pass, 1 skip, 0 fail, 0 leak across 2,199 tests.
Keeping this issue open for the remaining Array method families.
Landed the copy/mutation checkpoint in 4d047a36 fix(array): retain copying method operands (#827).
This covers reverse, toReversed, with, toSpliced, fill, and copyWithin. Receivers, arguments, copied elements, and result arrays are rooted and reloaded across coercion, indexed get/set/delete, proxy, and accessor boundaries.
Evidence:
- The exact parent aborts in the managed write barrier during the moving
reversegetter witness. - The candidate passes all 7 moving scenarios in both forced execution modes.
- Unsuppressed TSan: 1/1 pass, 0 fail, 0 leak, no race report.
- Array test262: 3,081/3,081 before → 3,081/3,081 after; byte-identical census, 0 regressions.
- Full Debug: 2,199 pass, 1 skip, 0 fail, 0 leak across 2,200 tests.
The push raced with an unrelated test262 CLI tooling commit; the rebased source files retained the exact tested SHA-256 values before landing. Keeping this issue open for sorting and the remaining mutator/search audit.
Landed the sorting checkpoint in f61bacd2 fix(array): root values through sorting callbacks (#827).
sort and toSorted now stable-sort integer indices while every gathered JavaScript value remains in a relocatable temporary-root slot. Receivers, comparators, comparison operands/results, default ToString results, output arrays, and generic write-back values are reloaded after observable callbacks. The obsolete raw-Value merge helper was removed.
Evidence:
- The exact parent aborts in the managed write barrier during the moving
sortgetter/write-back witness. - The candidate passes all 5 moving scenarios in both forced execution modes.
- Unsuppressed TSan: 1/1 pass, 0 fail, 0 leak, no race report.
- Array test262: 3,081/3,081 before → 3,081/3,081 after; byte-identical census, 0 regressions.
- Full Debug: 2,200 pass, 1 skip, 0 fail, 0 leak across 2,201 tests.
Keeping this issue open while I complete the remaining mutator/search ownership audit.
Completed the remaining arrayMethod ownership scope in 8bf70f5c fix(array): retain remaining method operands (#827).
This final checkpoint covers:
- mutators:
push,pop,shift,unshift; - searches:
indexOf,includes,at,lastIndexOf; - stringification:
join,toLocaleString, ArraytoString; - iterator creation:
values,keys,entries, including the shared cursor helper.
Receivers, arguments, copied values, separators, locale results, join callables, and iterator sources are rooted and reloaded across observable boundaries. Array iterator creation and Array toString now dispatch before LengthOfArrayLike, so neither performs an eager length read.
Evidence:
- The exact parent aborts while binding the moving
pushproxy set trap's arguments. - The candidate passes all 11 moving scenarios in both forced execution modes.
- The separate iterator/toString ordering witness passes with zero eager
lengthreads. - Unsuppressed TSan: 1/1 pass, 0 fail, 0 leak, no race report.
- Array test262: 3,081/3,081 before → 3,081/3,081 after; byte-identical census, 0 regressions.
- Full Debug: 2,202 pass, 1 skip, 0 fail, 0 leak across 2,203 tests.
Together with 8e1e441d, f63d5c5f, 256a3afc, a17a7046, 4d047a36, and f61bacd2, this completes the source and acceptance scope described in this issue. The separate native-wrapper and child-realm teardown findings remain tracked in #830 and #831.
Sign in to comment on this issue.