Commit39253aa3Recorded15 Jul 2026Repositorysigil-ffi

ffi: accept native-codegen closures + route >3-arg callbacks through sigil_applyN

Message

Two callback fixes:

1. Native-closure callbacks (latent bug). nativefficallbackcreate rejected any procedure that was not a bytecode closure or native primitive. Under sigil build --backend native, every top-level procedure is a native-codegen closure (SIGILOBJNATIVECLOSURE), so c-callback rejected EVERY callback in a native-compiled program with 'c-callback: expected procedure', even though the callback handler and the sigilapply family already dispatch such closures via sigilnativebridgecall. Now accepts sigilisnative_closure too.

2. Callbacks with more than 3 arguments. The dyncall callback handler erred on any callback with >3 args ('not yet supported'). It now routes the >3-arg case through sigilapplyN (the generic-arity apply added to the VM C-API), supporting up to FFIMAX_ARGS. This enables 4-6-arg GTK/WebKit signals such as decide-policy.

Proven with a 4-arg WebKitWebView decide-policy callback firing correctly in a native-compiled binary. The >3-arg routing requires sigil_applyN in the linked VM (sigil release that adds it); the native-closure fix is independent.

Changed
 native/ffi.c | 18 +++++++++++++-----
 1 file changed, 13 insertions(+), 5 deletions(-)
Diff
native/ffi.cmodified
@@ -27,6 +27,7 @@ extern Value sigil_apply0(SigilVM *vm, Value proc);
27
extern Value sigil_apply1(SigilVM *vm, Value proc, Value arg);
28
extern Value sigil_apply2(SigilVM *vm, Value proc, Value arg1, Value arg2);
29
extern Value sigil_apply3(SigilVM *vm, Value proc, Value arg1, Value arg2, Value arg3);
+30
extern Value sigil_applyN(SigilVM *vm, Value proc, int argc, Value *argv);
31
32
/* ============================================================
33
* FFI Type System
@@ -1664,9 +1665,10 @@ static DCsigchar ffi_dyncall_callback_handler(DCCallback *cb, DCArgs *dc_args,
1665
scheme_args[2]);
1666
break;
1667
default:
1667
sigil__vm_error(vm, SIGIL_ERR_RUNTIME,
1668
"c-callback: callbacks with more than 3 arguments not yet supported");
1669
return DC_SIGCHAR_VOID;
+1668
/* >3 args: dispatch through the generic arity variant (added to the VM
+1669
* C-API alongside sigil_apply0..3). Supports up to FFI_MAX_ARGS. */
+1670
ret_val = sigil_applyN(vm, cbd->proc, cbd->arg_count, scheme_args);
+1671
break;
1672
}
1673
1674
/* Marshal return value */
@@ -1779,9 +1781,15 @@ static Value native_ffi_callback_create(SigilVM *vm, int argc, Value *args)
1781
return SIGIL_UNDEFINED;
1782
}
1783
1782
/* Procedure */
+1784
/* Procedure. Accept bytecode closures, native primitives, AND
+1785
* native-codegen closures (SIGIL_OBJ_NATIVE_CLOSURE) - the last is what
+1786
* top-level procedures become in --backend native builds, and both the
+1787
* callback handler and the sigil_applyN family already dispatch them via
+1788
* sigil_native_bridge_call. Without this, c-callback rejects every callback
+1789
* in a native-compiled program. */
1790
Value proc = args[2];
1784
if (!sigil_is_closure(proc) && !sigil_is_native_proc(proc)) {
+1791
if (!sigil_is_closure(proc) && !sigil_is_native_proc(proc) &&
+1792
!sigil_is_native_closure(proc)) {
1793
sigil__vm_error(vm, SIGIL_ERR_TYPE,
1794
"c-callback: expected procedure");
1795
return SIGIL_UNDEFINED;