Goal
Make property-mode Atomics.wait / Atomics.waitAsync waiter metadata obey Context.Options.heap_limit_bytes instead of allocating from the process page allocator. This is a resource-control/security hardening follow-up from #30.
Current evidence
src/jsthread.zig currently defines:
const prop_alloc = std.heap.page_allocator;- sync property wait tickets allocate duplicated keys and
PropTicketrecords fromprop_alloc; - property
waitAsyncallocates duplicated keys,PropAsyncTicketrecords, settlement scratch, and waiter-table backing storage fromprop_alloc; gc.zigtraces liveg.prop_asynctickets underGil.prop_mutex, marking the target object and promise.
Because Context.createWith(.{ .heap_limit_bytes = n }) wraps the context allocator (context_gpa) rather than std.heap.page_allocator, property waiter metadata can grow outside the configured cap. This is separate from the current trace-sensitive-lock work: the current allocator bypass means budget recovery is not involved at all.
Implementation constraints
- Prefer a context-owned allocator for property waiter metadata, likely via
Gil, so the storage lifetime remains tied to the realm andContext.destroycan free abandoned tickets. - Preserve the current cross-thread settlement lifetime rules: async tickets may be settled by notifying or polling peers, and teardown may abandon tickets by owner.
- Be careful with allocation order/rooting. Moving allocations under
context_gpamay allow heap-cap recovery at sites that currently cannot recover; any live JS objects created before a recoverable allocation must be rooted or allocated after the native metadata. - Keep
Gil.prop_mutexlock-aware: waiter-table growth is traced under the same mutex and should either fail closed while held or prove a safe recovery point.
Acceptance criteria
- Property waiter/ticket/table allocations no longer bypass
heap_limit_bytesfor normal threaded contexts. - Focused positive/negative tests cover capped contexts and preserve existing property
Atomics.wait/waitAsyncsemantics. - Trace-sensitive/fail-closed policy is documented for property waiter table growth if recovery can be triggered there.
- Existing no-GIL,
.gil = true, and teardown/settlement tests remain green.