A statement-position `a.splice(start, deleteCount, ...items)` built a
one-element (or n-element) items array, then scr_arr_splice_insert built
the removed-elements array that the caller released straight away: three
or more allocations per sorted insert in tsc-ts's insertType. When the
result is discarded and the items are plain evaluated values, the emitter
now evaluates receiver, start, count, and items in order and calls
scr_arr_splice_drop with the owned value slots. It applies the same
clamping and state shifts on dense receivers, releases removed values
only after the receiver is consistent again, and keeps the general
implementation for sparse receivers and sparse-sized results.
Retains stored BLACK into the cycle header so that markRoots could skip
candidates retained again after they were buffered, and every surviving
release stored PURPLE to undo that. On the tsc-ts self-check the filter
dropped almost no candidates (3.01M walked either way), while the stores
cost a header write on every retain and release of a headered object and
an instruction sequence at every inlined site. Colors now belong to the
collector alone: markRoots takes every buffered entry, scr_cyc_mark_live
and the emitted mark-live and purple stores are gone, and the release
fast path only reads `buffered`.
tsc-ts self-check (median of 7): 3.15s -> 3.06s, max RSS 614 -> 600 MB,
binary -727 KB.
Rebased onto main's three-generation collector, the series measured
with and without this commit (tsc-ts self-check, median of 7):
2.779 s -> 2.706 s, binary -660 KB, max RSS +13 MB.
After the union fix, records-sort spent most of its time in the IR merge
sort's element moves: every src[i] read retained the swapped `src` array
and the element (scr_arr_get_ref), every dst[k] write released the old
slot, and `dst` grew from an empty array.
scr_arr_sort_values runs the IR helper's exact algorithm (same comparator
call order) over borrowed slot copies of the private, compacted snapshot:
- comparator calls use the callValue ABI (owned element arguments, an
undefined `this` window, pending-exception check);
- the array keeps owning every element and is untouched while user code
runs, so the cycle collector and a throwing comparator see the original
snapshot; the sorted permutation is published only after success;
- f64 and reference-counted element types qualify (isSortValuesElement);
unions with an undefined arm and checked/island values keep the IR.
The new internal arrIntrinsic `sortValues` is validated, may throw, and
is not reference-preserving.
* Remove the large-array cliff past 2^20 elements
Arrays longer than 2^20 kept every element beyond the cutoff in a sorted
side store, and each indexed write to an existing entry deleted and
reinserted it, so fill + indexed read/write loops went quadratic
(n=1.2M: 10.4s on macOS arm64, 12.6s on Linux x64).
- Rewrite existing sparse entries in place.
- Let dense storage grow past the cutoff for contiguous extension of a
populated prefix, bulk range writes, and sparse tails that reach 3/16
density, migrating side-store entries so index < cap stays dense.
- Make the side store a deque with front slack so descending first-touch
writes and prefix migration are amortized O(1).
- Bound range-derived slice/splice capacity hints for hole runs.
scr_arr_new now reserves the live count, so a 2^20+3 element Set
converts into dense storage instead of a sparse tail; the white-box
test_lib check that pinned the old policy now asserts dense storage.
* Share immortal boolean union boxes
Maybe-undefined reads of boolean[] elements (`if (composite[i])` in a
sieve) box the element in a boolean|undefined union and free it at once:
one calloc/free pair per read, about a quarter of numeric-kernels samples
at large scales. Unions are immutable and boolean arms own no payload, so
low tags now return headerless immortal instances, the same convention as
the compiler's static unit-arm constants.
* Record preflight/order baselines for corpus 3138
- Sort primitive arrays with stable native ordering and pure conversion keys.
- Preserve sparse semantics and argument effects while avoiding callback overhead.
- Verify Unicode ordering and ownership across native and WASI paths.
- Share dense array storage and move owned ranges without rebuilding containers.
- Batch array construction and insertion while preserving evaluation order and bounded temporary storage.
- Lower indexed mutations natively and preserve typed-array reversal across numeric element types.
- Combine bounded string concatenations while preserving evaluation and ownership.
- Build array joins and raw strings directly in their final storage.
- Support literal null and undefined string conversions with preserved effects.
- Reduce allocation and reference-management overhead in native array loops.
- Enable vectorization while preserving numeric behavior.
- Preserve live tuple iteration and cover reference lifetimes and missing values.
Represent ordinary JavaScript arrays with hole, value, and explicit-undefined states; add sparse side storage and carry missing values through the frontend, native backends, runtime, and Node-facing consumers.
- Lower unshift and reverse through the C and LLVM backends.
- Preserve spread, mutation, evaluation-order, and reference-counting semantics.
- Add runtime, differential, and surface-manifest coverage.