Binding a single function symbol with [foreign]
Maurizio Cimadamore
maurizio.cimadamore at oracle.com
Mon Sep 10 11:00:19 UTC 2018
On 09/09/18 20:45, Jorn Vernee wrote:
> Hello,
>
> It turns out I was using an older build of the branch (sorry, TIL 'hg
> pull' only works for the active branch). I also applied your recent
> Callback patch, and what I was trying to do was almost already
> possible through another route.
>
> This is the code I'm going for:
>
> @NativeCallback("(u64:i8)i32")
> public interface PutsCallback {
> int call(Pointer<Byte> message);
> }
>
> public static void main(String[] args) throws Throwable {
> Library lib = Libraries.loadLibrary(lookup(), "msvcrt");
> Symbol sym = lib.lookup("puts");
>
> Callback<PutsCallback> clbck =
> sym.getAddress().asCallback(PutsCallback.class);
> PutsCallback puts = clbck.asFunction();
>
> Scope scope = Scope.newNativeScope();
> Pointer<Byte> message = scope.toCString("Hello!");
> System.out.println(puts.call(message));
> }
>
> Instead of passing an explicit MethodType, the method type is derived
> from the SAM of a functional interface, which also solves the problem
> of missing generic type parameters.
>
> There were 2 changes I made when trying to make this work:
>
> Firstly, I had to implement asCallback, which basically just creates a
> new CallbackImpl with the pointer itself as the entry point.
That's very clever - but what's the difference, may I ask, between this and:
@NativeHeader("puts=(u64:i8)i32")
public interface PutsLib {
int puts(Pointer<Byte> message);
}
And then bind the interface with Libraries.bind ? Actually, I believe
this latter version should be more performant, as the spinned
implementation generated by the binder will just have a direct exact
method handle call to the native code; whereas in the callback case
there are some few extra checks (e.g. to check that the scope is still
alive and also to check whether the entry point is a real native
function or a synthetic stub generated by the binder, in which case we
shortcircuit and do a Java 2 Java call directly).
>
> Secondly, the CallbackImpl::asFunction method uses the Scope of it's
> entry point, but in the case of a library symbol that scope is null,
> so it fails with an NPE. As a workaround I'm creating (and leaking) a
> new native scope in case the scope is null. Maybe a longer term
> solution could be something like library symbol pointers returning a
> Scope that is tied to the lifetime of the library itself?
The idea (not implemented yet) is that each Library will have a
meaningful Scope that will stay alive as long as that library is loaded.
That Scope will also be used internally by the binder to, e.g. allocate
constants, or global variable values, etc. So your code will be able to
piggy back on that.
>
> The code half works; It prints the message, and then it crashes [1]
> but that might just be because I'm on windows which is not supported?
> At least I think this API is pretty nice. I haven't been able to build
> jextract yet, so thorough testing is difficult.
Yeah - windows is not supported - I'm actually surprised it works at
all, given that the registers used by the Windows ABI and system V ABI
are quite different; for instance, System V (the implemented one) passes
its first integer argument via the RDI register, whereas the Windows ABI
uses RCX; so the failure you are seeing is related to the fact that the
current code doesn't arrange the arguments/return values in a way that
is compatible with the underlying system ABI on your machine.
But it seems like you are taking the code for some serious spin, and
that's some invaluable feedback to us - thanks!
Maurizio
>
> You've already said you're working on other things right now, but at
> least I wanted to send this for future reference.
>
> Jorn
>
> [1] : https://gist.github.com/JornVernee/dda1d3e42158dfddddb3ba60060e25ae
More information about the panama-dev
mailing list