← back to index

wasthon — handle scopes A/B proof

One page, two phases on the same module, identical workload — a tight loop of _pickle.dumps(obj) on a rich object graph. Each dumps() makes dozens of internal wrap() calls (borrowed wraps, temporaries, args) — the JS-side sentinel handle-map leak that tp_dealloc structurally couldn't touch.

Phase A: handle scopes active — every JS→C entry pushes a scope; sentinel handles die at return unless C took a reference. Phase B: runtime.noScopeFree = true — wraps are never scope-tracked, reproducing the bridge before handle scopes existed.

The deterministic, GC-independent signal is handles.size (live entries in the handle table). Phase A ⇒ flat; Phase B ⇒ climbs by tens per dumps(). Tune with ?iters=5000.

Loading…

Phase A — handle scopes enabled

iterhandles.sizeΔ handles refcounts.sizescopes depth

Phase B — handle scopes disabled (noScopeFree=true)

iterhandles.sizeΔ handles refcounts.sizescopes depth