The synthesized -dealloc IMP now loads `state->__sx_allocator` (the
slot captured at +alloc time by M4.0a + M4.0b) and dispatches
`allocator.dealloc(state)` through the inline-protocol fn-ptr at
slot 2. Old behaviour was `free(state)` — went straight to libc,
ignoring whatever allocator the instance was constructed with.
After this commit, the per-instance allocator design from M1.2 A.5
is finally end-to-end correct:
push Context.{ allocator = arena } {
f := SxFoo.alloc(); ← arena.alloc(STATE_SIZE) + capture
// ... use f ...
}
// refcount → 0 ⇒ -dealloc:
// load state->__sx_allocator = arena
// arena.dealloc(state) ← same allocator round-trips
TrackingAllocator now sees the alloc/dealloc pair; the deferred M1.2
A.5 work is done. Closes the loop on M4.0.
The dealloc IMP passes `__sx_default_context` as the implicit __sx_ctx
when invoking the dealloc fn-ptr — the IMP itself has no caller-side
ctx (it's called by Apple's runtime at refcount-zero), and the
default GPA is the right baseline for any nested allocations the
dealloc body might perform.
Each compiler-internal lookup that "can't fail" (Context type,
__sx_default_context global) emits a loud diagnostic instead of
silent fall-through, per the silent-error budget.
184/184 example tests pass; chess on iOS-sim green.
35 KiB
35 KiB