Required by zig-utils/zig-js#324 and zig-utils/zig-js#325.
Problem
Binding.finalize runs inside the sweep loop. In parallel mode that loop holds alloc_lock, so an embedder cannot safely invoke reentrant external-owner callbacks from a cell finalizer. The collector already documents that finalizers must not allocate from the heap, but it has no generic point for draining work after the sweep lock is released.
Scope
- Add an optional binding post-sweep hook that runs after alloc_lock is released for full, nursery, concurrent, and parallel concurrent sweeps.
- Guarantee the hook observes completed finalization/accounting and never runs under alloc_lock or weak_lock.
- Do not invoke it for aborted cycles or heap teardown; embedders drain teardown work explicitly after heap deinit, when the heap cannot be reentered.
- Add focused binding tests proving ordering, lock state, exact invocation count, and no invocation on an aborted parallel finish.
- Document the callback contract without coupling zig-gc to any particular embedder owner type.
Acceptance
- Existing collector tests remain green.
- Focused tests cover ordinary collection, nursery collection, parallel concurrent success, and abort.
- zig-js can queue external string/buffer releases during Binding.finalize and drain them from the hook without reentering collector locks.