[cc: vm-dev to see if anyone has some good ideas] I was thinking about
how one would move between FFI and Alien more freely and one thing that
seemed interesting is to have the compiler simply generate Alien call
code for FFI specs. E.g., when the compiler encounters, say:
"Register this method to be flushed on shutdown"
Alien registerMethod: thisContext method.
"Lookup the call if it isn't cached"
AlienCall := Alien lookup: 'system' inLibrary: 'libc'.
"Result can use a cached Alien since it never changes"
AlienResult := Alien new: 4.
"Arg1 needs to be reloaded every time we call"
Arg1 := Alien fromString: aString.
AlienCall primFFICallResult: AlienResult with: Arg1.
Arg1 free. "or however one frees those"
"XXXX: Would need some success indication here"
success ifFalse:[^AlienResult asUnsignedLong].
The "globals" in the above (AlienCall, AlienResult, AlienArg1) are all
method literals to cache the information (have you ever considered
adding a <static: foo> directive to the compiler to mark temp foo as a
temp stored in the literal frame?).
There are two advantages and a major disadvantage to this approach. The
good news is that this would allow one to continue to use existing FFI
specs with Alien (i.e., ease migration). Plus, some optimizations (like
caching lookups and args) can be done by the compiler now and don't
require people to write code themselves.
The obvious disadvantage is that you need to change the code to adjust
for changes in the ABI. Which sucks. I really wish Alien could take a
descriptor and deal with the ABI details itself. I wonder if it's
feasible to have subclasses of Alien function calls that implement the
different ABIs and pass enough information along that the ABI dependent
parts could be done there?