ANN: H98 FFI Addendum 1.0, Release Candidate 10

Fergus Henderson fjh at cs.mu.OZ.AU
Mon Jun 2 13:00:52 EDT 2003


On 02-Jun-2003, Alastair Reid <alastair at reid-consulting-uk.ltd.uk> wrote:
> 
> > The Mercury compiler will generate appropriate glue code to marshal and
> > unmarshal values of that type.
> 
> How does it figure out what concrete type to use?  Does it use trial 
> compilations a la autoconf?

No.  We don't try to second-guess the C compiler.  We just let the C
compiler figure it out.  The Mercury compiler generates a small amount
of glue code in C, and invokes the C compiler on that code.

The glue code consists of a wrapper around every foreign function
(although if you wanted to optimize things, you might note that this is
only really needed for foreign functions whose arguments or result are
foreign types).  The glue code interface uses only known types such as
WORD, so it can be called in a straight-forward manner from the assembly
code that the Mercury compiler's assembly-language back-end generates.
The glue code for each function calls the function, boxing or unboxing
the arguments and/or results if needed, i.e. if they have a foreign type
which doesn't fit in a word.

This approach of boxing all foreign types has the major advantage that
these foreign types can be passed to polymorphically typed Mercury
procedures or inserted in polymorphically typed Mercury data structures.

Generating a wrapper for every foreign function also means that it is
possible to interface to C macros as well as to C functions.
In fact, we also allow interfacing with arbitrary C code fragments,
not just macros or functions, so you can use this feature to write
inline asm, for example.

To illustate how the wrappers work, here's what the glue code for a
function "foo :: T -> T", where "T" is a foreign type implemented by
the C type "CT", could look like:

	WORD foo_glue(WORD boxed_x) {
		WORD boxed_y;
		CT x, y;

		/* maybe unbox the function's input argument */
		x = *(CT *)(sizeof(CT) > sizeof(WORD) ? boxed_x : &boxed_x);

		/* call the function or macro foo() */
		y = foo(x);

		/* maybe box the function's result */
		if (sizeof(CT) > sizeof(WORD)) {
			boxed_y = (WORD) GC_malloc(sizeof(CT));
			*(CT *)boxed_y = y;
		} else {
			*(CT *)&boxed_y = y;
		}

		return boxed_y;
	}

Note that if compiling to C, such wrappers can be inlined.

-- 
Fergus Henderson <fjh at cs.mu.oz.au>  |  "I have always known that the pursuit
The University of Melbourne         |  of excellence is a lethal habit"
WWW: <http://www.cs.mu.oz.au/~fjh>  |     -- the last words of T. S. Garp.



More information about the FFI mailing list