Hi,
on looking at CFFI from a porters point of view, I find what I consider a design failure. Namely, C functions are used without declaring them or even with fake declarations.
First of all, every time you call a function with foreign-funcall you have to supply the types of the arguments. The aliasing of all pointer types to :pointer means that type information is lost. Not all pointer type are equivalent, because some types have alignment restrictions.
Supplying the argument types is extremely tricky in some cases and might not be enough type information. For example, int f1(int i, ...) is not the same function as int f2(int i, int j) even though when we invoke f1(1, 2) the (2) is coerced to type int.
The information about "..." is taken cared of by DEFCFUN, but not by FOREIGN-FUNCALL. That may seem useless but really, it is not the same thing to call f1 and f2, because the C compiler does produce different assembly code. For instance, using AMD64, in the first case it has to push the arguments on the stack, while in the second case everything goes into registers Similar things happen with a PPC backend.
My current approach to coerce all functions to the first form is really a hack. And I wonder whether this design will survive newer architectures to come.
Regards,
Juanjo
-- Max-Planck-Institut für Quantenoptik Hans-Kopfermann-Str. 1, Garching, D-85748, Germany Phone: +49 89 32905 345 Fax: +49 89 32905 336 http://www.mpq.mpg.de/Theorygroup/CIRAC/
On 10/12/06, Juan Jose Garcia-Ripoll jjgarcia@users.sourceforge.net wrote:
First of all, every time you call a function with foreign-funcall you have to supply the types of the arguments. The aliasing of all pointer types to :pointer means that type information is lost. Not all pointer type are equivalent, because some types have alignment restrictions.
Can you give me an example?
Supplying the argument types is extremely tricky in some cases and might not be enough type information. For example, int f1(int i, ...) is not the same function as int f2(int i, int j) even though when we invoke f1(1, 2) the (2) is coerced to type int.
On all platforms I have access too they seem to behave the same since we manage to call varargs functions and the various Lisps don't know anything about their varargs-ness. I hear that might not always be true, so see below.
The information about "..." is taken cared of by DEFCFUN, but not by FOREIGN-FUNCALL. That may seem useless but really, it is not the same thing to call f1 and f2, because the C compiler does produce different assembly code. For instance, using AMD64, in the first case it has to push the arguments on the stack, while in the second case everything goes into registers Similar things happen with a PPC backend.
See my comment in src/functions.lisp about foreign-funcall-varargs:
;;; ATM, the only difference between this macro and FOREIGN-FUNCALL is that ;;; it does argument promotion for that variadic argument. This could be useful ;;; to call an hypothetical %foreign-funcall-varargs on some hypothetical lisp ;;; on an hypothetical platform that has different calling conventions for ;;; varargs functions. :-)
If ECL can do something special about varargs, we can go ahead and use that!
On Thu, 2006-10-12 at 23:20 +0100, Luís Oliveira wrote:
On 10/12/06, Juan Jose Garcia-Ripoll jjgarcia@users.sourceforge.net wrote:
Supplying the argument types is extremely tricky in some cases and might not be enough type information. For example, int f1(int i, ...) is not the same function as int f2(int i, int j) even though when we invoke f1(1, 2) the (2) is coerced to type int.
On all platforms I have access too they seem to behave the same since we manage to call varargs functions and the various Lisps don't know anything about their varargs-ness. I hear that might not always be true, so see below.
I think a key difference is that in ECL's case, we are compiling via the C compiler which does actually know whether a function is varargs or not. The Lisp implementations that compile to native code have to set up the call arguments such that they work with both varargs and non-varargs functions.
What if, instead of using FOREIGN-FUNCALL-VARARGS, we added an extra keyword argument that could be placed in the FOREIGN-FUNCALL arguments as a marker for the boundary between the required and variadic arguments? Something like:
(foreign-funcall "printf" :string "%d" :varargs :int 42)
It's not exactly pretty (and we still can't force people to use it on the Lisps that don't require it), but there is less loss of information for the C compiler...
James
2006/10/13, Luís Oliveira luismbo@gmail.com:
On 10/12/06, Juan Jose Garcia-Ripoll jjgarcia@users.sourceforge.net wrote:
First of all, every time you call a function with foreign-funcall you have to supply the types of the arguments. The aliasing of all pointer types to :pointer means that type information is lost. Not all pointer type are equivalent, because some types have alignment restrictions.
Can you give me an example?
I have no longer access to this machine, but my interpreter of lisp at some point broke because I was using converting (char*) pointers to (short *) pointers, where "short" was the right size of the bytecodes and "char" was the pointer to the buffer. Now it turns out that I was not careful enough and the pointers in the buffer were not aligned on 32-bit boundary and reading the short cause a signal. There are other examples like this.
Supplying the argument types is extremely tricky in some cases and might not be enough type information. For example, int f1(int i, ...) is not the same function as int f2(int i, int j) even though when we invoke f1(1, 2) the (2) is coerced to type int.
On all platforms I have access too they seem to behave the same since we manage to call varargs functions and the various Lisps don't know anything about their varargs-ness. I hear that might not always be true, so see below.
These lisps play a trick which is to copy all arguments onto the stack, no matter what the function signature is. I am still learning PPC and AMD64 ABIs to understand how to implement a dynamic FFI on those platforms, but those solutions seem to be very fragile.
If ECL can do something special about varargs, we can go ahead and use that!
It is not that it can do something special, it is rather that such information is required. See the post by James Bielman.
Juanjo