[foreign-memaccess] RFR 8227394: Add MemorySegment::asByteBuffer convenience method

Maurizio Cimadamore maurizio.cimadamore at oracle.com
Thu Jul 11 14:31:53 UTC 2019


On 11/07/2019 13:57, Jorn Vernee wrote:
>> What do you think?
>
> I have felt for a while that asByteBuffer morally belongs on 
> MemorySegment, since a MemoryAddress models a cursor, so 'treating a 
> cursor as a span of memory', as the name asByteBuffer implies feels 
> odd, and indeed we still have to supply the size separately.

This is a more convincing argument - e.g. moving the method from one 
place to another is something we can consider - the fact that the 
conversion method lives on MA is, in a way, a result of past design 
choices where MA was also modelling a segment. Now we have both MA and 
MS and it's a  fair question to ask where does this belong.

The advantages of having the conversion on MemorySegment are, IMHO, 
symmetry with creation (MemorySegment.ofByteBuffer) and, as you mention, 
a cleaner abstraction mapping: a segment is a range, a byte buffer is 
also a range. On the other hand, having the conversion on MemoryAddress 
caters better to those use cases where you have a big memory segment 
(size greater than 32 bits) and then create sliced buffer views of it. 
To support something like this with MemorySegment::asByteBuffer you 
would need to create many segment slices upfront, and then create the 
buffer views from there. But this is also probably a wash:

e.g.

segment.slice(i, 100).asByteBuffer();

vs.

segment.baseAddress().offset(i).asByteBuffer(100);

With respect to loss of totality, as you point out, converting an MA has 
the issue that the provided size might exceed that of the segment; 
converting a MS has the problem that the MS might be too big. So again, 
a wash.


So, on second thought, maybe just moving the method from MA to MS is all 
we need? (in the name of a better abstraction mapping)


As for sliceAt - I'm not sure. You can always get to the base address of 
a segment of any given memory address. To solve the cases you are 
thinking of, you can go two ways: add sliceAt - which allows you to 
remain in the MA world - or add a MemoryAddress::offset() method which 
returns a long (this should be a safe operation, as the offset is 
relative to the segment anyway), and then feed that back into 
MemorySegment::slice

Of the two, the latter feels simpler?

Maurizio


>
> Like you say, by adding a MemorySegment::asByteBuffer we introduce a 
> problem because some segments are too large, but this seems pretty 
> similar to being able to pass a size to MemoryAddress::asByteBuffer 
> that is too large, which is still possible even if it's an `int`. At 
> the same time we have one less problem because we can no longer use a 
> MemoryAddress that is out of bounds of the segment.
>
> It feels like a pretty much even trade.
>
>> I'm less convinced on the
>> usefulness of turning an entire memory segment into a bytebuffer: if
>> you really wanted to view the entire memory segment as a BB, maybe you
>> just wanted to create a (direct) BB in the first place?
>
> By that same line of thought, do we need MemoryAddress::asByteBuffer? 
> This is meant as an interop thing, where you just have a MemorySegment 
> that is given to you, and would like to turn it into a ByteBuffer.
>
> I agree with the concern of the API explosion. I was also looking at 
> removing the asByteBuffer method from MemoryAddress, and replacing it 
> with a more general 'sliceAt' method, that slices the underlying 
> MemorySegment at the offset denoted by the MemoryAddress itself 
> (instead of having to pass that manually as the offset to 
> MemorySegment::slice). I could imagine cases where a user has a 
> MemoryAddress and wants to do an offset and then slice, e.g. I have a 
> pointer to some struct, returned by some third party allocator API, 
> and want to give someone else a pointer to access just a single field, 
> I can try and call `address.segment().slice(...)`, but the problem 
> would be that I don't know what to pass as offset (after all, the 
> MemoryAddress I have might not be the base address of the segment).
>
> With a `sliceAt` method, the current use of asByteBuffer(int) could be 
> replaced with `address.sliceAt(newSize).asByteBuffer()`.
>
> Prototype: 
> http://cr.openjdk.java.net/~jvernee/panama/webrevs/8227394/webrev.01/
>
> What do you think? Of course, if you'd rather hold off on fiddling 
> with the API too much at this time that's fine with me :) (I'm 
> guessing we're trying to target JDK 14 as an incubating feature?)
>
> Jorn
>
> On 2019-07-11 14:00, Maurizio Cimadamore wrote:
>> Hi Jorn,
>> I gave some thought about this in the past, and my conclusion was
>> mixed - and I filed this in the "you ain't gonna need it" bucket
>> (YAGNI).
>>
>> The motivations are that (i) it is really simple to emulate the API
>> with the existing methods (as the implementation of the new method
>> shows), and that (ii) the new API is, by necessity, a partial API -
>> not all segments can be mapped onto a byte buffer - some are too
>> large; while the existing API on memory address is total (thanks to
>> the explicit int parameter).
>>
>> In other words, the existing API on MemoryAddress supports what I
>> believe to be the most important interop idiom: slicing a big memory
>> segment into multiple < 32bits buffer views. I'm less convinced on the
>> usefulness of turning an entire memory segment into a bytebuffer: if
>> you really wanted to view the entire memory segment as a BB, maybe you
>> just wanted to create a (direct) BB in the first place?
>>
>> The current model is kind of easy to explain - the moves we allow are:
>>
>> * ByteBuffer -> MemorySegment
>>
>> * MemoryAddress + int -> ByteBuffer
>>
>> This feels minimal. If we add another dimension, as per your patch:
>>
>> * MemorySegment -> ByteBuffer
>>
>> Then the next question is - should we allow also:
>>
>> * ByteBuffer -> MemoryAddress? (e.g. create a big segment from the
>> byte buffer and then have a memory address point at the BB offset)
>>
>> Which feels a bit like a slippery slope. I'd be more confident in
>> adding a facility like this after some real world validation.
>>
>> What do you think?
>>
>> Maurizio
>>
>> On 11/07/2019 12:28, Jorn Vernee wrote:
>>> Hi,
>>>
>>> Please review this small patch that adds an asByteBuffer convenience 
>>> method to MemorySegment that returns a buffer the size of the segment.
>>>
>>> Bug: https://bugs.openjdk.java.net/browse/JDK-8227394
>>> Webrev: 
>>> http://cr.openjdk.java.net/~jvernee/panama/webrevs/8227394/webrev.00/
>>>
>>> (note that the javadoc is largely taken from 
>>> MemoryAddress::asByteBuffer).
>>>
>>> My reason for adding this is that I wanted to reach for this method 
>>> a few times when playing with the API, but it didn't exist. So, I 
>>> thought it would be useful to have.
>>>
>>> (Also, I originally wanted to upload this to GitHub [1] to test out 
>>> the Skara [2] tools, but apparently that's not operational yet :) )
>>>
>>> Thanks,
>>> Jorn
>>>
>>> [1] : https://github.com/openjdk/panama/pull/1
>>> [2] : https://github.com/openjdk/skara#openjdk-project-skara


More information about the panama-dev mailing list