[foreign-abi] RFR: 8254260: Consider splitting binding recipe operators that serve a dual role

Maurizio Cimadamore mcimadamore at openjdk.java.net
Thu Oct 8 20:52:29 UTC 2020


On Thu, 8 Oct 2020 19:12:48 GMT, Jorn Vernee <jvernee at openjdk.org> wrote:

> Hi,
> 
> This patch splits the binding recipe operators that currently serve a dual purpose into 2 operators each:
> - MOVE -> VM_STORE and VM_LOAD
> - DEREFERENCE -> BUFFER_STORE and BUFFER_LOAD
> - CONVERT_ADDRESS -> BOX_ADDRESS and UNBOX_ADDRESS
> 
> Note that I also added a TO_SEGMENT operator which converts a MemoryAddress into a MemorySegment. This was previously
> done as part of the COPY operator, but only for upcalls, so I had to split out this functionality so that COPY could
> have only one interpretation as well. This will also enable some more optimizations down the line, such as merely
> wrapping a by-value struct passed as a pointer in a MemorySegment, instead of having to make a copy.  This also
> regularized the use of allocators by the operators. Now an allocator is always passed as an argument, and that's what
> is used to do allocations, instead of relying implicitly on MemorySegment::allocateNative. (The index of the allocator
> argument is now also always passed when specializing an operator, to indicate the dependency, and so that operator
> impls don't have to 'guess' which argument index is the allocator (see for instance the implementation of
> Copy::specialize).  The rest of the patch is more or less a mechanical renaming, and updating the tests/CallArrangers
> to use the different operator names.  Thanks, Jorn

Looks a great cleanup. Left some comments.
I also ran all tests here and everything looks good.

src/jdk.incubator.foreign/share/classes/jdk/internal/foreign/abi/Binding.java line 303:

> 301:
> 302:     // FIXME should register with scope
> 303:     private static MemorySegment toSegment(MemoryAddress operand, long size) {

This seems to be only used inside the `ToSegment` binding, so, perhaps this could should be moved there (also because
this is an interpreter function, not a binding factory - e.g. the overload with the `toSegment` binding factory is
confusing)

src/jdk.incubator.foreign/share/classes/jdk/internal/foreign/abi/Binding.java line 363:

> 361:
> 362:     @Override
> 363:     public boolean equals(Object o) {

General question - where do we use equals/hash? Just for testing purposes right?

src/jdk.incubator.foreign/share/classes/jdk/internal/foreign/abi/ProgrammableInvoker.java line 344:

> 342:                                 Map<VMStorage, Integer> retIndexMap) throws Throwable {
> 343:         boolean hasBufferCopies = bufferCopySize != 0;
> 344:         NativeScope scope = hasBufferCopies ? NativeScope.boundedScope(bufferCopySize) : null;

If Allocator had a close() method, this could be simplified a little?

src/jdk.incubator.foreign/share/classes/jdk/internal/foreign/abi/ProgrammableInvoker.java line 219:

> 217:         MethodHandle specializedHandle = leafHandle; // initial
> 218:
> 219:         int argInsertPos = -1;

The more we tweak this routine, the more I'm convinced we should just spin specialized bytecode :-) - it's becoming
increasingly hard to follow what's happening here. (not for this review - more longer term)

test/jdk/java/foreign/NativeTestHelper.java line 36:

> 34:
> 35:     public static boolean isIntegral(MemoryLayout layout) {
> 36:         return kind(layout).isIntegral();

Whoops - sorry - I guess I fixed the API and have not run the tests?

src/jdk.incubator.foreign/share/classes/jdk/internal/foreign/abi/Binding.java line 230:

> 228:
> 229:     enum Tag {
> 230:         VM_STORE,

Should these be called REG_STORE and REG_LOAD? Ah, I guess we also have stack, right? Ok, I agree with the name - these
are "moves" that only the VM can perform, makes sense.

src/jdk.incubator.foreign/share/classes/jdk/internal/foreign/abi/Binding.java line 591:

> 589:      * The [type] must be one of byte, short, char, int, long, float, or double
> 590:      */
> 591:     public static class BuffferStore extends Dereference {

Typo, there are 3 `f`

src/jdk.incubator.foreign/share/classes/jdk/internal/foreign/abi/Binding.java line 622:

> 620:         @Override
> 621:         public String toString() {
> 622:             return "BuffferStore{" +

Typo here too

src/jdk.incubator.foreign/share/classes/jdk/internal/foreign/abi/CallingSequenceBuilder.java line 93:

> 91:
> 92:         for (Binding b : bindings) {
> 93:             if (b.tag() == Binding.Tag.VM_LOAD

We could have static EnumSet for what's an box vs. unbox binding, so that you can filter by checking for presence in
the right enum set?

src/jdk.incubator.foreign/share/classes/jdk/internal/foreign/abi/CallingSequenceBuilder.java line 107:

> 105:
> 106:     private static void verifyBoxBindings(Class<?> expectedReturnType, List<Binding> bindings) {
> 107:         Deque<Class<?>> stack = new ArrayDeque<>();

I've seen in the code that the verifyUnbox method speaks about a `returnType` parameter - should it be an `outType` for
symmetry (since, I guess, we use this more than just for returns - e.g. we use it for args in upcalls).

src/jdk.incubator.foreign/share/classes/jdk/internal/foreign/abi/ProgrammableUpcallHandler.java line 102:

> 100:                                 : bufferBase.asSlice(layout.argOffset(storage));
> 101:                             return SharedUtils.read(ptr, type);
> 102:                         }, DEFAULT_ALLOCATOR);

For upcalls, couldn't we use a `NativeScope` and close at the end of the call? If the callback leaks segments
outside... well, too bad.

-------------

Marked as reviewed by mcimadamore (Committer).

PR: https://git.openjdk.java.net/panama-foreign/pull/375


More information about the panama-dev mailing list