Problem
Stringifier.serializeArray currently calls std.fmt.allocPrint(self.arena, "{d}", .{i}) for every serialized index. The key is consumed synchronously by [[Get]]; when toJSON or a replacer must observe it, serializeLoaded already materializes its own JavaScript String value before the callback.
Each frozen 2,200 x 90 representative JSON row stringifies one three-element values array per round: 198,000 array serializations and exactly 594,000 arena-backed decimal-key allocations. Those bytes stay in Context backing rather than following the invocation-scoped snapshot/output lifetimes fixed in #993/#996/#997.
Change boundary
Format each usize index into bounded stack storage and pass that borrowed slice through the synchronous SerializeJSONProperty call. Preserve exact decimal spelling for toJSON/replacer callbacks, sparse holes, inherited indices, accessors, proxies, abrupt completion, and deep/OOM behavior. This change does not authorize direct dense-element reads; that is a separate descriptor/locking decision.
Completion
Add callback/key and sparse/accessor witnesses, retain JSON Test262 and required VM/tree agreement, and rerun OOM/deep/cycle/GC plus no-GIL TSan gates. Compare exact-parent alternating samples on both frozen JSON rows and an array-heavy stringify control with exact checksums. Land only on a measured non-regression.