chicken-users
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Chicken-users] [Swig-dev] Future of SWIG chicken module


From: felix
Subject: Re: [Chicken-users] [Swig-dev] Future of SWIG chicken module
Date: Mon, 09 Feb 2004 23:20:24 +0100
User-agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040113

John Lenz wrote:

One more question: does SWIG support callbacks?


Lastly, the reason swig does not allow just any scripting language function to be passed to a C/C++ function that takes a function pointer is that a callback wrapper function would need to be exported. But since chicken already supports generating this wrapper function with (define-callback-wrapper ...) it would be easy to make the swig chicken module completly support callbacks. Again, swig itself does not support exporting the callback wrapper function but we wouldn't need it to :)

Well, it's not quite that easy, I'm afraid. To perform callbacks the
_caller_ has to be treated specially, since Chicken does some weird
stuff with the C-stack. So for example:

(define-external (callback) void ...)

((foreign-lambda* void () "callback();"))

would probably crash. It would have to be

((foreign-callback-lambda* void () "callback();"))

The latter form is much less efficient, unfortunately. The reason for
this is how Chicken implements tail-call optimization and first class
continuations.

Every scripting language module in swig (including how the current chicken module is implemented) generates all the wrapping functions. This is neccissary for a lot of languages because to register a function with the interpreter it must be in the form (for python)
PyObject *_wrapWhatever(PyObject *self, PyObject *args) {...}
SWIG then sets up this function to extract the C variables from the args and self pointers and wrap up the return value into a PyObject *

The current swig chicken module does the same thing... a function like
void _wrapWhatever(int argc, C_word closure, C_word continuation, C_word arg1) {...} and then the C interface is used (like C_fix C_unfix and such). In the current swig chicken module, chicken is viewed exactly as another scripting language.

So in any case, I notice that a lot of these wrapper functions can be generated by chicken with say the (define-foreign-lambda ) or whatnot. So my idea was to not have SWIG generate any wrapper functions at all... After thinking about it this past week I am having doubts as to if this will work, but here is the idea anyway.

Swig would take as input the header files and such and would generate a . scm file that contained instructions to chicken about the interface. This way we can completly avoid generating any wrapper functions at all.

In fact, the wrapper functions will be generated anyway - only by Chicken
not by SWIG. `foreign-lambda' and friends generate wrappers themselves,
for various technical reasons.


You see, the problem really comes down to 1) How types will be converted and 2) how linkage will occur. Since chicken itself is exporting to C code, we have a lot more flexibility than a normal scripting language. By giving chicken a description of the interface, the chicken generated code can make calls directly into the functions being wrapped.

The only problem is support for more complicated types, like say std:: vector<int>. SWIG has the ability to automaticly convert a function that say returns a std::vector<int> into a scheme list (the guile swig module already does). This requires generating some wrapper function... or at least some wrapper code after the call returns to create the scheme list. SWIG has support for what are called typemaps, which allow arbitrary code to be inserted into the wrapper function to transform the types. So SWIG has a typemap that converts a std:: vector<int> to a guile scheme list.

Another problem involved with linkage is the runtime type handeling. Usually, a struct or a class is stored in say the PyObject * or a C_word as a void pointer and some type information. Thus, in the generated _wrap function we need to check is the input argument a valid type (since we will eventually cast the pointer from a void * to whatever type the function takes). This is currently where both the SWIG chicken module and the (foreign*) functions in chicken are BOTH broken. There is no type checking going on at all. I can pass a pointer of any type to any function which accepts a pointer.

Well, not quite - the type-checking for `foreign-...' is done on the Scheme 
side.
But usually pointers are untyped, as you correctly point out. But IIRC Jonah 
has used
a special undocumented feature of Chicken ("tagged pointers") for that stuff.
But, as I said before, I haven't looked at the SWIG code too hard.

SWIG has a bunch of code to do run time type checking... is the input type the same as the output type, or can the input type be converted to the output type, etc. which would also be lost. Lastly, even if the user is careful and only passes correct types to correct functions, type conversion is neccissary with multiple inheritance since the offset of the base class inside the derived class might not always be at the beginning, so a direct cast from a void * causes problems.

For both of these two things we could obviously add some support for in chicken, but we would in a sense be wasting all the time and duplicating the support already in SWIG. SWIG has an extensive amount of code dealing with run time type checking... you can have typedefs of derived classes and more typedefs and on and on and SWIG will figure it all out. SWIG has a lot of code for some of the more compilcated C++ types like std::vector and std::list as well.

So maybe a combination of the two?
Say chicken could have a directive or function or something that would allow arbitrary code to be insterted before the actuall foreign call is made? This way, SWIG would parse the interface file and SWIG would generate all the type conversion code (like the C_fix call on the return value or the C_c_pointer_or_null() call on the input. Thus, SWIG would in essense do all the Chicken<->C interface stuff but instead of dumping it all in wrapper functions, it would just tell chicken about it... That is, SWIG would give chicken the exact C code that needed to go before and after the call to the foreign function. This way we still avoid generating wrapper functions... all the code would in some sense be "inlined" right into the generated chicken c code. Optionally as well, SWIG would only need to export that code for "problem" types like pointers to foreign types, c++ types std::vector, etc. The base case like a function that takes integers and returns a float or something could stay exactly how it is.

Of course, the other option is to keep the current method of type conversion and linkage, that is, SWIG generates a bunch of wrapper functions and marshals every type from chicken->c and from c->chicken without chicken knowing anything about it.


I think the current method is fine. The code generated by SWIG is not
necessarily less efficient, than what Chicken generates. There are some
points where the current SWIG Chicken module could be improved, by supporting
specific features (like constants, etc.). Also the type-checking of numeric
arguments is not fully optimal (fixnums should be accepted for flonum arguments,
for example). And multiple values are (AFAIC) not handled.
But otherwise it works fine.


cheers,
felix




reply via email to

[Prev in Thread] Current Thread [Next in Thread]