- If the structure is greater than 16 bytes, it must be passed on the C stack, even if there are enough registers.
- If the structure is 16 bytes or less, it is broken up into 8 byte chunks. Each chunk is considered separately.
- If at least one of the fields in a chunk is an integer, the whole chunk is passed in an integer register.
- Otherwise, if the chunk is either two float fields, or a double field, it is passed in an SSE register. In particular, this means that if your structure consists of two floats, they must be packed into a single SSE register.
There are additional rules for C99 complex numbers and long double types, but Factor's FFI doesn't support those so I don't have to worry about that.
For a long time I didn't properly implement these semantics. They're implemented now. I don't think anybody has run into this issue, however when Mac OS X Leopard is released with 64-bit Cocoa, it would certainly come up since many Cocoa APIs rely on passing structs (assuming Apple uses the same or similar ABI as Linux on AMD64, which is likely).
I think the FFI is one of Factor's strongest points. Many popular languages have weak FFIs (or are weak in other respects). On the other hand, when implementing an obscure language, one must work twice as hard as everybody else to be taken seriously.