[foreign-memaccess] API refinements

Maurizio Cimadamore maurizio.cimadamore at oracle.com
Wed Dec 18 18:41:33 UTC 2019


Hi,
during the code review for the foreign memory access API (see [1]), 
several issues were raised; these are now tracked in [2].

Before doing any code change, I'd like to get some shared consensus on 
the direction we should take. Here is a list of the issues:

* Should MemoryAddress implement Comparable?

I believe the answer here should be NO. In general comparing addresses 
is tricky - and it seems to me that, given that MemoryAddress has a 
well-defined equals() behavior, you can still implement e.g. loops where 
you want to keep offsetting an address until you reach a certain limit.

As to whether MemorySegment should implement Comparable, I believe 
answer should also be NO. I know that ByteBuffer implements Comparable, 
and it has method to compare the contents, and to find the first index 
at which two byte buffers mismatch. But I think this is a very marginal 
use case for the memory access API, and there's always an escape hatch: 
project segments down to a byte buffer and take it from there.

* should we merge MemoryLayouts and MemoryLayout?

I'm on the fence on this one. The fact that we have a MemoryLayouts is 
very much driven by the fact that the API lives in an incubating module, 
and that some layouts cannot live where they should (e.g. JAVA_INT 
should really be Integer::LAYOUT). Since we also have a MemoryHandles 
(which will be replaced by some methods inside MethodHandles), I really 
don't see a big reason as to why we should refactor the API at this 
point. E.g. this seems to be more a question that we should ask again 
when the API is finalized, and exits incubation.

* MemorySegment::acquire() -- replace with MemorySegment::fork?

I came up with that - and I think I still like it. Acquire seems to 
suggest that it has something to do with threads and ownership - which 
it does, but in reality you can acquire a segment even from same owner. 
Fork seems a more neutral term, and, to me helps better visualizing 
what's really going on (e.g. a tree of segments is being created).

* should we have a way to ask a Layout if its size is specified ?

This is a tricky one. On the one hand, if not all layouts have a size, 
one could argue that Layout::bitSize should return an optional. But that 
seems excessively punitive for the vast majority of layouts that are 
never going to use unbound sequences. This might leads down to two 
conclusions:

- maybe unbound sequences do not carry enough weight - perhaps replace 
them with a zero-length sequence, and be done - or even get rid of 
zero-length sequences and let layout only be for things whose size is 
defined. (and maybe come back with a better mechanism to speak about 
"size holes" later, and variable-length layouts in general)

- if we keep unbound sequences, let's just add an hasSize() predicate

Of the two I'm warming up with just ditch unbound sequences period (e.g. 
all layouts must have a well-defined size).

* There doesn't seem to be a predicate for "can I call close without an 
exception?" (isAlive && isAccessible) isn't sufficient.

I think the answer here is - and that's FINE. I'm of the opinion that if 
an exception occurs when calling close(), 90% it signals a bug in the 
code, not just something that you want to proactively check against. 
E.g. somebody else forked your segment w/o you knowing. On top of that, 
I don't think that, even if we wanted to, there would be a way to do a 
'canClose()' check which would mean anything - that is, the predicate 
could return true, but then, what if, just before you call close() 
another thread re-acquires the segment? I think this is a lost cause.

* MemoryAddress::offset() vs. MemoryAddress::offset(long) -- not much 
distance between these two semantically different operations

I think the solution that I like here is to drop MemoryAddress::offset() 
completely, and to provide a new functionality to create a slice based 
on a given address (which is the primary motivation for having the 
offset() method). Here we have two options:

- MemoryAddress::asSlice(long bytes) -> MemorySegment
- MemorySegment::asSlice(MemoryAddress base, long bytes)

The former leads to more compact code, but it feels a bit dirtier - 
anyway, I don't feel too strongly here.

* MemorySegment::isAccessible() -- as the A* word is overloaded, some 
other name should be found?

Yes, the A-word is a mess - but some of the proposals I've see (e.g. 
"isOwnedByCurrentThread") look equally terrible. If somebody has a 
better alternative I'd be happy to hear it - if not, I think keeping the 
A-word is tolerable.


Thoughts?

Maurizio

[1] - 
https://mail.openjdk.java.net/pipermail/core-libs-dev/2019-December/063836.html
[2] - https://bugs.openjdk.java.net/browse/JDK-8235837



More information about the panama-dev mailing list