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. >
