RFC: Refactoring SystemABI

Maurizio Cimadamore maurizio.cimadamore at oracle.com
Fri Nov 23 13:51:29 UTC 2018


What you describe is possible, but requires a field access/method call 
on every upcall (to get the method handle), plus I'm not sure how we can 
effectively invoke a MH from native code.

I think a simple solution would be to just use some #ifdef ?

It's not the most elegant solution in the world, I know, but after all 
we'll only be using one SystemABI in a given system.

Another way would/could be to invoke a virtual method on some 
UniversalUpcallHandler superclass which is extended by SysV and Windows. 
After all the native code doing the upcall does have a receiver, so we 
could use it.

Maurizio

On 23/11/2018 12:55, Jorn Vernee wrote:
> Looks good!
>
> Now let's talk about the upcall stub a bit;
>
> If there are 2 UniversalUpcallHandlers (in separate ABI 
> implementations), that want to use the same upcall stub generation 
> code this breaks currently, since the upcall stub generation code will 
> always call the SysV implementation. This is the current code [1]:
>
>   const char* cname = 
> "jdk/internal/foreign/invokers/UniversalUpcallHandler";
>   const char* mname = "invoke";
>   const char* mdesc = 
> "(Ljdk/internal/foreign/invokers/UniversalUpcallHandler;JJJJJJ)V";
>
> But after moving the UniversalUpcallHandler to the SysV impl package 
> this will always call the the SysV implementation.
>
> I think this coupling could be reduced a bit. Instead of saving the 
> UpcallHandler in the stub, which will hold a reference to the target 
> MethodHandle , we could instead save the target MethodHandle in the 
> stub, for later retrieval, and also save a perfixed MethodHandle which 
> calls the right UpcallHandler. Then, instead of the upcall stub 
> calling into the UniversalUpcallHandler.invoke method, it would just 
> call this prefixed MethodHandle instead.
>
> Thoughts?
>
> Jorn
>
> [1] : 
> http://hg.openjdk.java.net/panama/dev/file/9f27bcd3de9c/src/hotspot/cpu/x86/universalUpcallHandler_x86.cpp#l59
>
> Maurizio Cimadamore schreef op 2018-11-23 13:19:
>> (as also observed by Jorn), Pulling even more on this string, I think
>> we can drop receiver object from the getUpcallHandle method
>> alltogether.
>>
>> The current API looks like this:
>>
>> UpcallHandle upcallStub(Object receiver, MethodHandle target,
>> NativeMethodType nmt);
>>
>> I think we can simplify to this:
>>
>> UpcallHandle upcallStub(MethodHandle target, NativeMethodType nmt);
>>
>>
>> In fact, the method already takes a MethodHandle - so we could require
>> clients to pass in a 'bound' method handle, where the receiver object
>> has already been 'attached' to the target MH. This will also make the
>> SystemABI more flexible too, because, while in the case of the binder
>> there is _always_ a receiver object (the receiver is an instance of a
>> functional interface obtained from some lambda expression passed to
>> the Scope::allocateCallback), in general this need not be the case -
>> and one could envision cases where clients would want a callback to
>> point to some static method with the right signature.
>>
>> So, I think handling the receiver on the binder side (by binding it to
>> the MH) is the right thing to do.
>>
>> So, with all the simplifications discussed in this thread, the API 
>> would become:
>>
>> Pointer<?> upcallStub(MethodHandle target, NativeMethodType nmt);
>>
>> That is, gone is the UpcallHandle abstraction.
>>
>> Additionally, we will have to add a new method to SystemABI:
>>
>> void freeUpcallStub(Pointer<?>)
>>
>> Which is used by Scope::close.
>>
>>
>> As mentioned in an earlier message, the downcall logic in SystemABI
>> will have to special case the case where a stub entry point is passed.
>> In such cases, the ABI will recover the method handle associated with
>> the stub (we currently do so by saving a Java object in the stub
>> itself - but other ways are possible too, e.g. global hashmap), and
>> return the (already bound) method handle, which will already feature
>> the right signature.
>>
>>
>> This will eliminate code paths duplication in CallbackImplGenerator
>> and also CallbackImpl - where currently we do different things
>> depending on whether the underlying pointer is a stub.
>>
>> I think this looks good?
>>
>> Maurizio
>>
>>
>> On 23/11/2018 02:06, Maurizio Cimadamore wrote:
>>>
>>> On 23/11/2018 01:47, Maurizio Cimadamore wrote:
>>>> What is it that bothers you about this approach?
>>>
>>> Let me clarify - I like that you are thinking of ways to reduce the 
>>> surface of the API - but it seems that moving a method (getReceiver) 
>>> from UpcallHandle to SystemABI doesn't buy all that much.
>>>
>>> I personally prefer having a simple UpcallHandle lookup method in 
>>> the ABI, and then a way to get form the Handle to the receiver as it 
>>> seems more composable this way. Right now, true, we always need to 
>>> do both things at the same time (to speed up things in the upcall 
>>> machinery), but maybe having a 'are you a stub' predicate will turn 
>>> out handy even on its own (in case the user wants to write some 
>>> pointer-walking code).
>>>
>>> But, if we really wanted to save some API estate, I think a better 
>>> approach (if viable) would be to completely hide the stub detection 
>>> logic. As you said very clearly yourself, we have this issue:
>>>
>>> "There is a shortcut being taken when native code gives us a Pointer 
>>> back to one of our upcall stubs, and we want to call it from Java. 
>>> In that case we don't really need to call into native, to call our 
>>> own upcall stub to then call back into Java to call our target method."
>>>
>>> This is the reason behind the 'isStub/getReceiver' logic. But let's 
>>> analyze this use case more in detail: we have a pointer to function, 
>>> and we want to do a downcall using that pointer as the entry point. 
>>> But this means that, in order to do the downcall, we will call 
>>> SystemABI.downcallHandle (again). So, I think it is theoretically 
>>> possible that the ABI would say: "hey, I know this guy!" and instead 
>>> of giving you a MethodHandle that 'goes down' it gives you a 
>>> MethodHandle that stays in Java-land. And the binder would not even 
>>> know.
>>>
>>> If my conjecture is correct, then we just need your minimal 
>>> UpcallHandle interface (pointer + free) and no 
>>> getReceiver/getFunctorObject at all. And, if you pull on this some 
>>> more, you realize that UpcallHandle is not even needed: just use a 
>>> Pointer, and add a 'freeUpcallHandle(Pointer<?>)' to the SystemABI. 
>>> That'd be sweet.
>>>
>>> Thoughts?
>>>
>>> Maurizio
>>>


More information about the panama-dev mailing list