On 13/01/2016 14:19, Phil Clayton wrote:
I looked at the code for FFI runtime call 55 (create a CIF) and there's not a huge amount in there so it's not much overhead. I couldn't see where the memory allocated for a CIF is freed though. (Probably not an issue as the number of callback functions in an application is likely to bounded, assuming that they are built only once by correct use of buildClosure<N>.)
The CIF is built the first time it is used and then cached for the rest of the execution.
I have a long-term plan to turn the buildCallN and buildClosureN functions into something that is almost a mini-compiler that will produce an interface function when it is applied. It may only be possible to do that in certain cases and fall back to libffi in the other cases. It's complicated because there are different ABIs for the various combinations of X86-32/X86-64 and Unix/Windows.
Interesting - is that to make the FFI faster? I wonder if the experiences of MLton would be useful for creating such an interface.
The idea is that the current buildCallN/buildClosureN functions together with the conversions would be sufficient for the interface. The only difference would be what would happen when they were called. The aim would be to improve the efficiency of calling a foreign function at the cost of the extra time "compiling" the function call.
A case in point is the mechanism for calling in X64/Unix. It looks from the code and a quick glance at the ABI documentation that this involves putting the first 6 fixed point values into general registers and the first 8 floating point registers into SSE registers. There are some complicated rules for small structures. LibFFI works all this out on every call so there is a significant overhead. I would rather have expected that it might have encoded some of this in the CIF but it doesn't seem to. By compiling an interface function the arguments could be moved directly from ML into the appropriate registers.
David