Parent: #480 Related: #473 Follows: #1019
Measured problem
Current main 9453de45 retains the largest completed JSON.stringify continuation buffer until Interpreter.deinit. A focused direct FrameStack witness used the production append/deinit path and observed:
- 4,096 active frames: logical length returns to 0, capacity remains 5,900 frames, retaining 566,456 bytes including cache metadata.
- 50,000 active frames: logical length returns to 0, capacity remains 67,247 frames, retaining 6,455,768 bytes including cache metadata.
Normal Context.evaluate teardown releases the cache, but a long-running evaluation or embedding-held interpreter keeps that high-water allocation after a one-off deep stringify.
Goal
Account and bound reusable JSON.stringify continuation storage without undoing repeated-deep traversal reuse or changing JavaScript semantics.
Scope
- Add exact current/peak cache count, frame-capacity, and owned-byte gauges to the machine-readable Context memory inventory.
- Use a deterministic working-set policy: a large frame allocation is retained only after consecutive invocations demonstrate comparable occupancy; one-off high-water demand is released at invocation unwind.
- Preserve the reentrant lease boundary: nested stringify calls never alias an outer active stack.
- Keep allocation failure, abrupt completion, moving GC, no-GIL, and teardown failure-atomic.
- Version and fail-closed validate the representative memory-inventory schema.
Acceptance
- A deterministic 4,096/50,000-frame witness records the current baseline and proves one-off backing is released.
- Repeated deep calls reuse one retained buffer without repeated growth; a later shallow call releases oversized backing.
- Memory inventory exposes exact current/peak cache bytes and frame capacity and reconciles at teardown.
- Reentrant and exhaustive allocation-failure witnesses pass without stale frames, lease leaks, or allocator leaks.
- Existing 50,000-level object/array limit witnesses throw catchable
RangeErrorin tree and required-VM modes. - Moving-GC, no-GIL, and unsuppressed TSan coverage pass.
- JSON test262 remains 165/165 and the forced tree/required-VM sweep remains exact.
- Deterministic allocation/capacity evidence is published; no noisy wall-time claim is used for acceptance.
Guardrails
No reduced nesting, new semantic limit, cached final JSON, benchmark recognition, global visited set, arena-only shortcut, or rejection based on source/input identity.