1. Callbacks with floats
- Posted by petelomax Dec 06, 2021
- 1110 views
I believe this is fundamentally unsolveable, I just wanted to check.
(Specifically here, I am asking whether this is solvable in Open Euphoria.)
(And of course I don't mean never ever, just not with what we have right now.)
In C, the ACTION (redraw) callback on an IupCanvas is defined as:
int function redraw_cb(Ihandle *ih, float posx, float posy)
which would naturally translate to the Phix code
function redraw_cb(Ihandle ih, atom posx, posy) constant cb_redraw = Icallback("redraw_cb")
Note that Ihandle is effectively an atom, and Icallback() is just a call_back() wrapper.
The thing is that on 32bit ih is just an address whereas posx and posy are passed as
32-bit floats and could in theory be converted via float32_to_atom(int_to_bytes(posx/y)),
whereas on 64 bit, again ih is just an address (in rcx) but posx/y would be passed in
xmm1/2 and they would end up with whatever garbage happened to be in rdx/r9.
Unfortunately no extra type info is/can be specified in a call_back() call, and it is
that specific fact which makes this a fundamentally unsolveable problem.
Ultimately we cannot treat atom ih one way but atom posx another, cmiiw.
For sure, if I really really wanted to I could write a block of inline assembly and use
the address of that as the callback instead of a call_back() result, but, yuk.
Thankfully in the specific case this just cropped up in (IupCanvas ACTION callback)
there is a trivial workaround of fetching posx/y via IupGetDouble() instead.
Update: Again, just double!-checking, there isn't any way to sort this out via something like
define_c_func({},call_back(),{C_FLOAT/C_DOUBLE,...), is there?
2. Re: Callbacks with floats
- Posted by ghaberek (admin) Dec 06, 2021
- 1106 views
Note that Ihandle is effectively an atom, and Icallback() is just a call_back() wrapper. The thing is that on 32bit ih is just an address whereas posx and posy are passed as 32-bit floats and could in theory be converted via float32_to_atom(int_to_bytes(posx/y)), whereas on 64 bit, again ih is just an address (in rcx) but posx/y would be passed in xmm1/2 and they would end up with whatever garbage happened to be in rdx/r9. Unfortunately no extra type info is/can be specified in a call_back() call, and it is that specific fact which makes this a fundamentally unsolveable problem. Ultimately we cannot treat atom ih one way but atom posx another, cmiiw.
You're correct in that floats and ints are passed via different registers so either you'd receive garbage or, if there were ints after the floats, you'd read the later ints too early. And yes, from inside call_back() we just assume we're being passed ints (really uintptr_t) for each parameter. Internally there's no way to know the type coming in; this is something a compiler usually takes care of setting up based on a function signature.
For sure, if I really really wanted to I could write a block of inline assembly and use the address of that as the callback instead of a call_back() result, but, yuk.
Agreed. Very yucky and not portable. It probably would work though. But you still have to specify type information somewhere.
Update: Again, just double!-checking, there isn't any way to sort this out via something like define_c_func({},call_back(),{C_FLOAT/C_DOUBLE,...), is there?
I think you're barking up the right tree here. Speaking strictly for Euphoria's backend, it's possible to accommodate this but there are some caveats.
Add support for an optional sequence types={} parameter to call_back() that takes a matching number of C_ constants to specify the required type of each argument. This would currently only be possible on 64-bit and 32-bit CDECL callbacks since the 32-bit STDCALL callbacks uses a series of hard-coded 0-9 parameter functions. Although the CDECL function could probably be adapted to be a CDECL-or-STDCALL handler. We'd just have to store the routine pointer, type information, and calling convention alongside the function itself.
function myfunc( atom handle, atom posx, atom posy ) return 0 end function atom cb = call_back( routine_id("myfunc"), {C_POINTER,C_FLOAT,C_FLOAT} )
Or, we drop the custom-built internal callback handler altogether and move to something like libffi, which I've already considered to better support more platforms like 64-bit ARM and OS X on M1 (ARM). I'd still need to take the time to understand how libffi even works before I could begin integrating.
-Greg
3. Re: Callbacks with floats
- Posted by petelomax Dec 06, 2021
- 1056 views
Add an optional sequence types={} parameter to call_back()
Yeah, thanks, I agree that's exactly what's missing - should I or anyone else ever genuinely need it, that is.