And don't forget to make the primitive declaration automatic, nobody can 
remember that cryptic string :)


On 2012-11-25, at 18:20, Igor Stasenko <[email protected]> wrote:

> On 25 November 2012 21:59, Stéphane Ducasse <[email protected]> wrote:
>> Igor your proposal looks nice.
>> 
> it's not a proposal anymore..
> i already made the changes :)
> 
>> Stef
>> 
>> On Nov 22, 2012, at 2:47 PM, Igor Stasenko wrote:
>> 
>>> Hi,
>>> 
>>> i am thinking about redesign of FFI top-level api, because it not very good.
>>> 
>>> First thing is that NBFFICallout referenced in too many places (187 in
>>> my image).
>>> So, from one side, we should encourage using a convenience syntax, using
>>> 
>>> self nbCall: ..
>>> instead of
>>> NBFFICallout ...
>>> 
>>> but there's one more thing:
>>> - a code generator has many different ways of use, and i actually
>>> going to add another one,
>>> but i see that it will explode the protocol(s) without make it
>>> convenient to use.
>>> 
>>> Imagine that you want to generate a callout to function, which address
>>> cannot be obtained directly from external library.
>>> This is actually a real issue, which Esteban met when implementing
>>> bindings to Chipmunk library:
>>> - some functions are not exposed directly by dynamic library, but 
>>> indirectly:
>>> the symbol(s) which library exports is not direct pointer(s) to
>>> functions but instead
>>> a pointers to variable, where the function pointer is stored.
>>> So, in order to get function pointer , one needs first to get a
>>> pointer to symbol, and then read the pointer value at that address.
>>> 
>>> So, i thought that i would simply add new protocol to NBFFICallout:
>>> 
>>> call: anonFunctionSignature convention: callConvention
>>> functionAddress: aFunctionAddressBlock
>>> 
>>> Then, one could use it like:
>>> 
>>>      myMethod
>>>              <primitive: #primitiveNativeCall module: #NativeBoostPlugin 
>>> error: errorCode >
>>> 
>>>              ^ NBFFICallout
>>>                        call: #( int () )
>>>                       convention: #cdecl functionAddress: [ self
>>> getPointerTo: 'functionname' ]
>>> 
>>> but it is too elaborate..
>>> you can imagine that if one would like to implement a more convenient
>>> form, he could just do:
>>> 
>>>      myMethod
>>>              <primitive: #primitiveNativeCall module: #NativeBoostPlugin 
>>> error: errorCode >
>>> 
>>>              ^ self indirectCall: #( int () ) name: 'functionname'
>>> 
>>> or even:
>>> 
>>>      myMethod
>>>              <primitive: #primitiveNativeCall module: #NativeBoostPlugin 
>>> error: errorCode >
>>> 
>>>              ^ self indirectCall: #( int functionname () )
>>> 
>>> now the problem is that you cannot wrap the NBFFICallout method in
>>> order to implement convenience method, because of use of thisContext.
>>> 
>>> I also concerned about exploding NBFFICallout public API.. which imo
>>> doesn't makes much sense, because we should encourage the use of
>>> convenience methods.
>>> 
>>> So, i looking for improving public API:
>>> 
>>> - First thing is getting rid of direct references to NBFFICallout..
>>> - second thing is avoid tying public API with thisContext (so you can
>>> create own convenience methods without much hassle).
>>> 
>>> So, lets imagine what and how we can do it:
>>> 
>>> 
>>> foo
>>>      <primitive: 'primitiveNativeCall' module: 'NativeBoostPlugin'>
>>> 
>>>      ^ NBFFICallout cdecl: #(  int foo() ) module: 'bar'
>>> 
>>> 1. getting rid of global:
>>> 
>>> foo
>>>      <primitive: 'primitiveNativeCall' module: 'NativeBoostPlugin'>
>>> 
>>>      ^ self nbCallout cdecl: #(  int foo() ) module: 'bar'
>>> 
>>> 2. separating the call convention from signature:
>>> 
>>> foo
>>>      <primitive: 'primitiveNativeCall' module: 'NativeBoostPlugin'>
>>> 
>>>      ^ self nbCallout cdecl call: #( int foo() ) module: 'bar'
>>> 
>>> 3. as a bonus, since cdecl is most used, we can assume it is default:
>>> 
>>> foo
>>>      <primitive: 'primitiveNativeCall' module: 'NativeBoostPlugin'>
>>> 
>>>      ^ self nbCallout call: #( int foo() ) module: 'bar'
>>> 
>>> 4. avoid hardcoding module:
>>> 
>>> foo
>>>      <primitive: 'primitiveNativeCall' module: 'NativeBoostPlugin'>
>>> 
>>>      ^ self nbCallout call: #( int foo() ) module: self module
>>> 
>>> 5. pass code generation options as a separate message, instead of
>>> additional keyword:
>>> 
>>> foo
>>>      <primitive: 'primitiveNativeCall' module: 'NativeBoostPlugin'>
>>> 
>>>      ^ self nbCallout
>>>            options: #( +optFoo - optBar);
>>>            call: #( int foo() ) module: self module
>>> 
>>> 6. finally users would want to do it in most convenient way:
>>> 
>>> foo
>>>      <primitive: 'primitiveNativeCall' module: 'NativeBoostPlugin'>
>>> 
>>>      ^ self call: #( int foo() )
>>> 
>>> Which means that #call: is convenience method which they implement by
>>> themselves.
>>> Here how i think it should look like:
>>> 
>>> call: fnSpec
>>> 
>>>   ^ (self nbCalloutIn: thisContext sender)
>>>      cdecl;
>>>      options: #(+optFoo - optBar);
>>>      call: fnSpec module: self module.
>>> 
>>> If you look at current implementation of Object>>nbCall:
>>> 
>>> nbCall: fnSpec
>>>      " you can override this method if you need to"
>>> 
>>>      | sender |
>>>      sender := thisContext sender.
>>> 
>>>      ^ NBFFICallout
>>>              handleFailureIn: sender
>>>              nativeCode: [ :gen |
>>>                      gen
>>>                              sender: sender;
>>>                              callType: self nbCallingConvention;
>>>                              generateCall: fnSpec module: self 
>>> nbLibraryNameOrHandle]
>>> 
>>> it is almost the same, except from cryptic use of blocks, and private
>>> internal NBFFICallout methods which doing the job.
>>> 
>>> So, basicly, i want to get rid of NBFFICallout class >>
>>>  [cdecl/stdcall]: module: [options:]
>>>  [cdecl/stdcall]: emitCall: [options:]
>>> 
>>> and replace them with #call:module: and #call: emit:
>>> and also add new one:
>>> #call:address:
>>> 
>>> which can be used for passing a function pointer directly.
>>> 
>>> And any future extensions to public API will be a single method. Not
>>> 2,3 or more, like today..
>>> 
>>> 
>>> --
>>> Best regards,
>>> Igor Stasenko.
>>> 
>> 
>> 
> 
> 
> 
> -- 
> Best regards,
> Igor Stasenko.
> 


Reply via email to