Binding a single function symbol with [foreign]

Maurizio Cimadamore maurizio.cimadamore at
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(;
>     }
> 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:

     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!

> 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] :

More information about the panama-dev mailing list