Igor your proposal looks nice. 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. >
