Binding a single function symbol with [foreign]

Jorn Vernee jbvernee at
Mon Sep 10 12:24:24 UTC 2018

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

Yeah, I suppose there is not much difference if I'm using a pointer to a 
library symbol. My views on this have changed, I assumed wrapping a 
single function in a MethodHandle would be easier. But, you still need 
the same information, using an interface is just a different way of 
providing it. Though my idea might still be a good solution for when you 
have an arbitrary void Pointer that you want to make invokable, or when 
you want to 'cast' a Callback to a different type (i.e. 
Callback.entryPoint() -> void Pointer -> 
Pointer.asCallback(SomeOtherCallbackType.class)) ?

I also had another version which used the result of 
`NativeInvoker::getBoundMethodHandle` prefixed with a call to 
`Pointer::addr`, also adding a constructor to NativeInvoker that took a 
MethodType. That was working just as well, but this idea seemed more 
interesting for the average use cases, since it's a more high-level API. 
The only difference in capability I see between the two, is that the 
MethodType + Function combination can be derived dynamically, where as 
with an interface you would need the information to be statically know 
(or spin the interface, which is 'meh' for usability imho).

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

Sounds great!

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

Using -Xlog:panama I did see the first argument being put into RCX. 
Maybe that's just a coincidence? tbh I didn't know different ABIs were 
being used. For the standard library I always thought 32bit used cdecl, 
and 64bit used fastcall, which I thought would use the same registers on 
all systems. That's interesting to hear (I don't dabble in ABIs too 

> But it seems like you are taking the code for some serious spin, and
> that's some invaluable feedback to us - thanks!

Glad to be doing it! The OpenJDK code is very interesting to look at 
(though daunting at times). It's also a very cool feeling that I can 
actually change the machinery I'm running my programs on, even if it's 
just to do experiments with :)


> Maurizio

More information about the panama-dev mailing list