ffi M5.A.next.5.3: delete hand-rolled __block_invoke trampolines

Removes `__block_invoke_void` / `__block_invoke_bool` and their
companion `Into(Block)` impls from
`library/modules/std/objc_block.sx`. The generic
`Into(Block) for Closure(..$args) -> $R` impl from step 5.2 now
covers both shapes (and every other closure shape) via per-mono
`#insert build_block_convert($args, $R)` source emission.

Net stdlib shrinkage: ~52 lines, two trampolines + two per-shape
impls down to zero. Adding a new block-shape consumer no longer
requires touching stdlib — the impl emits per-call-shape on
demand.

`examples/95-objc-block-noop.sx` (zero-arg closure) and
`examples/96-objc-block-multi-arg.sx` (user-declared per-shape
impl for `Closure(s32, *void) -> void`) still pass: 95 routes
through the new generic, 96 keeps its in-file impl as a
documentation example of the user-declares-their-own path.
Suite at 217/217.
This commit is contained in:
agra
2026-05-27 21:59:57 +03:00
parent 165b621ab3
commit 2eaf932fcf

View File

@@ -52,70 +52,14 @@ __sx_block_descriptor : BlockDescriptor = .{
size = 48,
};
// Per-signature invoke trampolines. Each one reads sx_env + sx_fn from
// its block_self argument and tail-calls the closure through a typed
// fn-ptr cast. One per Apple block signature we support.
//
// Adding a new signature: write a `__block_invoke_<sig>` trampoline
// matching the closure's calling convention and an
// `impl Into(Block) for Closure(<sig>)` that points its `invoke`
// field at the trampoline. The `xx closure : Block` cast finds the
// impl via `Into` protocol dispatch.
//
// Signature: `void (^)(void)` — no args, no return. The single most
// common Apple block shape (UIView animation bodies, dispatch_async, etc).
__block_invoke_void :: (block_self: *Block) callconv(.c) {
// `sx_fn` is the closure trampoline — an sx-side function with the
// implicit __sx_ctx at slot 0 and env at slot 1. We're a callconv(.c)
// entry, so the call site needs ctx prepended; the typed fn-pointer
// type stays default-conv to enable that.
typed_fn : (*void) -> void = xx block_self.sx_fn;
typed_fn(block_self.sx_env);
}
impl Into(Block) for Closure() -> void {
convert :: (self: Closure() -> void) -> Block {
.{
isa = @_NSConcreteStackBlock,
flags = 0,
reserved = 0,
invoke = xx @__block_invoke_void,
descriptor = xx @__sx_block_descriptor,
sx_env = self.env,
sx_fn = self.fn_ptr,
};
}
}
// Signature: `void (^)(BOOL)` — UIView animation completion handlers and
// similar one-arg-bool callbacks.
__block_invoke_bool :: (block_self: *Block, arg0: bool) callconv(.c) {
typed_fn : (*void, bool) -> void = xx block_self.sx_fn;
typed_fn(block_self.sx_env, arg0);
}
impl Into(Block) for Closure(bool) -> void {
convert :: (self: Closure(bool) -> void) -> Block {
.{
isa = @_NSConcreteStackBlock,
flags = 0,
reserved = 0,
invoke = xx @__block_invoke_bool,
descriptor = xx @__sx_block_descriptor,
sx_env = self.env,
sx_fn = self.fn_ptr,
};
}
}
// Generic impl: covers any closure shape not handled by the
// hand-rolled per-signature impls above. The compiler
// Single generic impl covers every closure shape. The compiler
// monomorphises this body per call shape; inside each mono,
// `$args` is the bound pack of arg types and `$R` is the bound
// return type. The `#insert` evaluates `build_block_convert` at
// comptime and substitutes the resulting source — a nested
// `callconv(.c)` trampoline + the Block literal that points its
// `invoke` slot at it.
// `invoke` slot at it. One impl in stdlib replaces every per-
// signature hand-rolled `__block_invoke_*` + `Into(Block)` pair.
impl Into(Block) for Closure(..$args) -> $R {
convert :: (self: Closure(..$args) -> $R) -> Block {
#insert build_block_convert($args, $R);