Downstream: zig-utils/zig-js#97
Related: #15, #25, #26, #27
Evidence
On zig-js's shared-realm object_churn row, #26's test-and-test-and-set allocation lock reduced the exact eight-lane median from 1,319.888 ms to 1,164.047 ms (-11.8%). A post-change sample shows allocation wait is now deliberate handoff/yield; libc allocation and backing chunk growth are negligible.
The remaining serialized work under alloc_lock is global metadata publication: prepend every batch into Heap.all, initialize/index every header, update live/byte/nursery counters, and append born-concurrent cells. Increasing batch size (#25), tuning the lock (#26), and replacing the lock with one global pending-stack CAS plus an active-publisher gate (#27) have all been measured. #27 passed the full normal and TSan suite but regressed exact downstream 4/8-lane medians by 17.0%/12.6%, demonstrating that moving the convoy to one global CAS word is not sufficient.
Design direction
Add explicitly registered, stable per-mutator allocation metadata shards. A mutator should privately publish its allocated batches to its own chain/counters without touching a heap-wide write hotspot. Collection, finish/abort, and teardown may fold or walk registered shards only under an existing world-stopped/quiescent ownership boundary.
This is an ownership change, not another lock-spin experiment:
- shard registration/unregistration must be serialized and cannot race allocation, collection, or heap teardown;
- a thread exit must transfer or leave discoverable every published cell before its shard storage can disappear;
- collectors must visit all shard chains exactly once and preserve the authoritative live-cell walk;
- concurrent marking must preserve born-grey/born-concurrent behavior without tracing half-initialized payloads;
- nursery prefix/accounting, payload classification, sweeping/unlinking, OOM recovery, and finalization order must remain exact;
- bindings that do not opt in retain the current
create/createBatch behavior.
Acceptance criteria
Downstream: zig-utils/zig-js#97
Related: #15, #25, #26, #27
Evidence
On zig-js's shared-realm
object_churnrow, #26's test-and-test-and-set allocation lock reduced the exact eight-lane median from 1,319.888 ms to 1,164.047 ms (-11.8%). A post-change sample shows allocation wait is now deliberate handoff/yield; libc allocation and backing chunk growth are negligible.The remaining serialized work under
alloc_lockis global metadata publication: prepend every batch intoHeap.all, initialize/index every header, update live/byte/nursery counters, and append born-concurrent cells. Increasing batch size (#25), tuning the lock (#26), and replacing the lock with one global pending-stack CAS plus an active-publisher gate (#27) have all been measured. #27 passed the full normal and TSan suite but regressed exact downstream 4/8-lane medians by 17.0%/12.6%, demonstrating that moving the convoy to one global CAS word is not sufficient.Design direction
Add explicitly registered, stable per-mutator allocation metadata shards. A mutator should privately publish its allocated batches to its own chain/counters without touching a heap-wide write hotspot. Collection, finish/abort, and teardown may fold or walk registered shards only under an existing world-stopped/quiescent ownership boundary.
This is an ownership change, not another lock-spin experiment:
create/createBatchbehavior.Acceptance criteria
object_churnA/B, do not regress 1/2 lanes and materially improve both 4 and 8 lanes; reject the implementation otherwise.