[foreign-abi] On invokers

Maurizio Cimadamore maurizio.cimadamore at oracle.com
Thu Oct 3 13:24:25 UTC 2019


Thanks Jorn,
I plan to take a look at SysV in the next week or so.

Maurizio

On 03/10/2019 13:30, Jorn Vernee wrote:
> Hi,
>
> I've finished the work for upcall support. Here is the patch: 
> http://cr.openjdk.java.net/~jvernee/prog-back/webrev.02/
>
> This includes both the downcall support I did earlier and now also 
> upcall support for Windows, and should give a good picture of the 
> final state of things we want to get to. That is, have a single 
> backend, so this removes the code for the other backends.
>
> I've also improved the testing for upcalls, by now saving each 
> argument that is passed to the upcall into an array, and then checking 
> that array against the input arguments at the end of the test (that is 
> what the changes to TestUpcall.java are about). Sadly, the old 
> CallingSequenceBuilderTests were not compatible with the new API, so 
> I've removed them for now, but maybe we can bring these back again 
> later on.
>
> The API is pretty much finalized. The only thing I foresee changing is 
> the Binding IR, with things like different operators where they are 
> needed to support new ABIs. So, now is a good time to start looking at 
> porting to other ABIs.
>
> For x86 this is a little simpler since the support for that particular 
> architecture is already there. The only thing that would have to be 
> done is taking the old CallingSequenceBuilderImpl, and also have it 
> generate the new type of Bindings, as well as handle in memory 
> returns. A good example of the latter would be 
> CallArranger::arrangeDowcall/arrangeUpcall in the new patch.
>
> For adding support for another architecture there are a few extra steps;
> - Add an architecture descriptor, like X86_64Architecture.java does. 
> This is basically a set of VMStorage constants that map the different 
> registers defined in register_x86.hpp, as well as a set of integer 
> constants defining the different storage types (see 
> X86_64Architecture::StorageClasses).
> - In foreign_globals_XXX.hpp/cpp add an architecture specific version 
> of the Java ABIDescriptor/BufferLayout, and a way to translate from 
> the Java version to the native version using JNI (see 
> foreign_globals_x86.cpp/hpp).
> - Change the stub generation code for upcalls and downcalls to use the 
> registers and offsets defined by this ABIDescriptor/BufferLayout, 
> instead of the ones defined globally for the C ABI (see 
> universalNativeInvoker_x86.cpp/universalUpcallHandler_x86.cpp).
>
> Jorn
>
> On 23/09/2019 13:43, Jorn Vernee wrote:
>> Hi,
>>
>> I've been looking into the current set of invokers we have on the 
>> foreign-abi branch for the past few weeks. There is still work to be 
>> done in this area, both in terms of performance, and in terms of 
>> programmability. In this email I will focus on the latter.
>>
>> The UniversalNativeInvoker (UNI) API is currently the most 
>> programmble invoker that we have, so if we want to increase the 
>> programmability of our backend to cover more and more ABIs, this 
>> seems like a good place to start. UNI goes a ways in being 
>> programmable with the CallingSequence, ShuffleRecipe and 
>> ArgumentBinding APIs, being able to select in which registers to pass 
>> values, but there are still some aspects that could be polished:
>>
>> 1.) If you look into the VM code that processes the shuffle recipe, 
>> you'll notice that the eventual argument buffer that's being fed to 
>> the stub has a fixed set of registers it can work with on a given 
>> platform [1], namely the ones that are used by the C ABI. This works 
>> when we have only one ABI (C), but for different ABIs we'd probably 
>> want a different set of registers. We can change the stub generation 
>> code to take an 'ABIDescriptor' from which we derive the stub and 
>> argument buffer layout instead. This will also provide a place to put 
>> other ABI details that need to be customized, like stack alignment, 
>> and argument shadow space (Windows), as well as a set of volatile 
>> registers, which will be a super set of the argument registers. We 
>> would end up generating 1 generic downcall stub for each ABI. Also, 
>> note that we would need to create architecture definitions on the 
>> Java side to be able to specify the ABIDescriptors there (since ABIs 
>> are defined in terms of architecture).
>>
>> 2.) There is a need to pass meta arguments to a function sometimes. 
>> For instance, we need to pass in a pointer to a return buffer for 
>> in-memory-returns, and e.g. on SysV we need to pass in the number of 
>> float arguments in RAX (or rather AL) for variadic functions. The 
>> former is handled automatically by CallingSequenceBuilder, and the 
>> latter is hard-coded in the VM code. Since these are both ABI 
>> details, I believe they should be handled by the ABI implementations. 
>> Ideally we'd have an invoker API that let's us say: "add a Java 
>> argument with this carrier type, and this MemoryLayout, and then 
>> shuffle it into this register.", and then the ABI implementation can 
>> handle the further adaptation from the ABI-level signature (e.g. an 
>> additional MemoryAddress passed in as first argument), to the C-level 
>> signature (allocate a buffer as first argument and also return it). 
>> This is mostly a refactoring move in UNI::invoke and 
>> CallingSequenceBuilder that removes the handling for in memory 
>> returns, and replaces it with a more general way of passing those 
>> kinds of arguments.
>>
>> 3.) The unboxing/boxing is currently handled by calling into the 
>> various ABI implementations. We can make this code shared by 
>> extending the current ArgumentBinding 'recipe' to include other 
>> operations, besides moving from a pointer to a register, that cover 
>> the things that are currently handled by the ABI boxing/unboxing 
>> implementations. The various CallingSequenceBuilder implementations 
>> can then specify these additional binding operations when generating 
>> bindings. This means that we only need one shared piece of code that 
>> interprets this 'binding recipe'. The other advantage of doing this 
>> is that we would eventually be able to use these binding recipes + 
>> ABIDescriptor to generate a specialized stub for a particular call site.
>>
>> 4.) We are currently shuffling the arguments for a down call into a 
>> long[], and then in the VM we shuffle the arguments from the long[] 
>> into an argument buffer (ShuffleDowncallContext). We can merge these 
>> steps together, by directly shuffling the arguments into an argument 
>> buffer on the Java side (since we have an off-heap API). This 
>> decreases the overall complexity of the invoker implementation 
>> significantly, since we can drop all the code relating to shuffle 
>> recipes.
>>
>> I've been experimenting with these ideas, and have a prototype for 
>> downcalls on Windows [2]. For this I copied the relevant UNI classes 
>> to a separate `programmable` package and made the relevant changes 
>> there, since some of the code was shared with UniversalUpcallHandler. 
>> I've also preemptively removed the old UNI code (for x86) to show 
>> roughly how much code would be removed by switching to the new 
>> invoker API. I want to continue the experiment for upcalls as well, 
>> after which more old code could be removed; namely Argument, 
>> ArgumentBinding, CallingSequence (old), CallingSeqeunceBuilder (old), 
>> Storage, StorageClass, SharedUtils (mostly) and UniversalAdapter.
>>
>> How do these ideas sound? I'm mostly interested if this is flexible 
>> enough to support AArch64 and SysV. After the upcall support, I can 
>> look into porting the other 2 ABIs as well.
>>
>> Thanks,
>> Jorn
>>
>> [1] : 
>> https://github.com/openjdk/panama/blob/foreign-abi/src/hotspot/cpu/x86/universalNativeInvoker_x86.cpp#L73
>> [2] : 
>> https://github.com/openjdk/panama/compare/foreign-abi...JornVernee:prog-back-no-old
>>


More information about the panama-dev mailing list