callback-abi.md 1.5 KB

Callback ABI

Top-level V3 procedures are now C-callable:

  • no hidden static-link parameter;
  • arguments and result follow the C/QBE ABI;
  • ADR(Proc) yields a function pointer usable through a C typedef / void *;
  • short real, CBool, C strings and C-layout record pointers work in callback signatures.

Example:

PROCEDURE add (a, b : INTEGER) : INTEGER;
BEGIN
  RETURN a + b
END add;

PROCEDURE call_add (fn : ADDRESS; a, b : INTEGER) : INTEGER;
  EXTERNAL "m2_c_call_add";

...
call_add(ADR(add), 20, 22)

The C side is:

int m2_c_call_add(void *fn, int a, int b)
{
    int (*f)(int, int) = (int (*)(int, int))fn;
    return f(a, b);
}

Covered by compiler/tests/t_callback.mod.

Nested procedures

Nested procedures still take a hidden parent-frame link and are not C-callable. Keep callbacks at module level, or use a small C/Modula-2 trampoline with a context record.

GTK/GObject pattern

A GtkClosures-style design now works without a C wrapper for the V3 procedure itself:

PROCEDURE Tramp2 (instance, ctx : ADDRESS);

The C side registers Tramp2 as the signal callback and passes the ctx pointer as user data. Keep allocation, destroy handling and user_data ownership in a context object, as in the existing GtkClosures design.

Still not supported

  • V3 instance methods as direct C callbacks; they still carry a hidden receiver, so use a top-level trampoline.
  • Nested procedure values.
  • C varargs callbacks.
  • C struct-by-value callback arguments/results; use pointers or a C shim.