Re: RFR: 8254162: Implementation of Foreign-Memory Access API (Third Incubator) [v6]

2020-10-19 Thread Maurizio Cimadamore
On Mon, 12 Oct 2020 18:06:55 GMT, Maurizio Cimadamore  
wrote:

>> Build changes look good.
>
> I've just uploaded a biggie update to the foreign memory access support. 
> While doing performance evaluation, we have
> realized that mixing a multi-level hierarchy (`MappedMemorySegment extends 
> MemorySegments`) with exact invoke semantics
> of `VarHandle` and `MethodHandle` is not a good match and can lead to great 
> performance degradation for seemingly
> "correct" code.  While some of this can be attributed to the `VarHandle` API, 
> or to the fact that the so called
> "generic" invocation path should not be that slow in case where the 
> parameters are clearly related, it seems smelly
> that a primitive API such as `MemorySegment` should give raise to such 
> issues.  We have therefore decided to drop the
> `MappedMemorySegment` - this means that there's only one memory segment type 
> users can deal with: `MemorySegment` - and
> no chance for mistakes. Of course `MappedMemorySegment` has been primarily 
> introduces to allow for operations which
> were previously possible on `MappedByteBuffer` such as `force`. To support 
> these use cases, a separate class has been
> introduced, namely `MappedMemorySegments` (note the trailing `S`). This class 
> contains a bunch of static methods which
> can be used to achieve the desired effects, without polluting the 
> `MemorySegment` API.  A new method has been added on
> `MemorySegment` which returns an optional file descriptor; this might be 
> useful for clients which want to guess whether
> a segment is in fact a mapped segment, or if they need (e.g. in Windows) the 
> file descriptor to do some other kind of
> low level op.  I think this approach is more true to the goals and spirit of 
> the Foreign Memory Access API, and it also
> offers some ways to improve over the existing API: for instance, the only 
> reason why the `MemorySegment::spliterator`
> method was a static method was that we needed inference, so that we could 
> return either a `Spliterator`
> or a `Spliterator`. All of that is gone now, so the 
> method can return to be what it morally always
> has been: an instance method on `MemorySegment`.  Updated javadoc:
> http://cr.openjdk.java.net/~mcimadamore/8254162_v2/javadoc/jdk/incubator/foreign/package-summary.html
>   Updated
> specdiff: 
> http://cr.openjdk.java.net/~mcimadamore/8254162_v2/specdiff/overview-summary.html

The latest iteration addresses a comment raised during CSR review; more 
specifically, the `MemoryAccess` class has
several variants of dereference methods - e.g. `getInt`, `getInt_LE`, 
`getInt_BE`, to support different endianness. The
comment was to just have two overloads, e.g. `getInt` and `getInt(ByteOrder)` 
instead of three. I've implemented the
suggestion in this new iteration, as I think it makes the API a bit more 
compact.

-

PR: https://git.openjdk.java.net/jdk/pull/548


Re: RFR: 8254162: Implementation of Foreign-Memory Access API (Third Incubator) [v6]

2020-10-12 Thread Maurizio Cimadamore
On Mon, 12 Oct 2020 11:42:04 GMT, Magnus Ihse Bursie  wrote:

>> Maurizio Cimadamore has updated the pull request incrementally with one 
>> additional commit since the last revision:
>> 
>>   Tweak referenced to MemoryAddressProxy in Utils.java
>
> Build changes look good.

I've just uploaded a biggie update to the foreign memory access support. While 
doing performance evaluation, we have
realized that mixing a multi-level hierarchy (`MappedMemorySegment extends 
MemorySegments`) with exact invoke semantics
of `VarHandle` and `MethodHandle` is not a good match and can lead to great 
performance degradation for seemingly
"correct" code.

While some of this can be attributed to the `VarHandle` API, or to the fact 
that the so called "generic" invocation
path should not be that slow in case where the parameters are clearly related, 
it seems smelly that a primitive API
such as `MemorySegment` should give raise to such issues.

We have therefore decided to drop the `MappedMemorySegment` - this means that 
there's only one memory segment type
users can deal with: `MemorySegment` - and no chance for mistakes. Of course 
`MappedMemorySegment` has been primarily
introduces to allow for operations which were previously possible on 
`MappedByteBuffer` such as `force`. To support
these use cases, a separate class has been introduced, namely 
`MappedMemorySegments` (note the trailing `S`). This
class contains a bunch of static methods which can be used to achieve the 
desired effects, without polluting the
`MemorySegment` API.

A new method has been added on `MemorySegment` which returns an optional file 
descriptor; this might be useful for
clients which want to guess whether a segment is in fact a mapped segment, or 
if they need (e.g. in Windows) the file
descriptor to do some other kind of low level op.

I think this approach is more true to the goals and spirit of the Foreign 
Memory Access API, and it also offers some
ways to improve over the existing API: for instance, the only reason why the 
`MemorySegment::spliterator` method was a
static method was that we needed inference, so that we could return either a 
`Spliterator` or a
`Spliterator`. All of that is gone now, so the method can 
return to be what it morally always has
been: an instance method on `MemorySegment`.

Updated javadoc:
http://cr.openjdk.java.net/~mcimadamore/8254162_v2/javadoc/jdk/incubator/foreign/package-summary.html

Updated specdiff:
http://cr.openjdk.java.net/~mcimadamore/8254162_v2/specdiff/overview-summary.html

-

PR: https://git.openjdk.java.net/jdk/pull/548


Re: RFR: 8254162: Implementation of Foreign-Memory Access API (Third Incubator) [v6]

2020-10-12 Thread Magnus Ihse Bursie
On Mon, 12 Oct 2020 10:50:48 GMT, Maurizio Cimadamore  
wrote:

>> This patch contains the changes associated with the third incubation round 
>> of the foreign memory access API incubation
>> (see JEP 393 [1]). This iteration focus on improving the usability of the 
>> API in 3 main ways:
>> * first, by providing a way to obtain truly *shared* segments, which can be 
>> accessed and closed concurrently from
>>   multiple threads
>> * second, by providing a way to register a memory segment against a 
>> `Cleaner`, so as to have some (optional) guarantee
>>   that the memory will be deallocated, eventually
>> * third, by not requiring users to dive deep into var handles when they 
>> first pick up the API; a new `MemoryAccess` class
>>   has been added, which defines several useful dereference routines; these 
>> are really just thin wrappers around memory
>>   access var handles, but they make the barrier of entry for using this API 
>> somewhat lower.
>> 
>> A big conceptual shift that comes with this API refresh is that the role of 
>> `MemorySegment` and `MemoryAddress` is not
>> the same as it used to be; it used to be the case that a memory address 
>> could (sometimes, not always) have a back link
>> to the memory segment which originated it; additionally, memory access var 
>> handles used `MemoryAddress` as a basic unit
>> of dereference.  This has all changed as per this API refresh;  now a 
>> `MemoryAddress` is just a dumb carrier which
>> wraps a pair of object/long addressing coordinates; `MemorySegment` has 
>> become the star of the show, as far as
>> dereferencing memory is concerned. You cannot dereference memory if you 
>> don't have a segment. This improves usability
>> in a number of ways - first, it is a lot easier to wrap native addresses 
>> (`long`, essentially) into a `MemoryAddress`;
>> secondly, it is crystal clear what a client has to do in order to 
>> dereference memory: if a client has a segment, it can
>> use that; otherwise, if the client only has an address, it will have to 
>> create a segment *unsafely* (this can be done
>> by calling `MemoryAddress::asSegmentRestricted`).  A list of the API, 
>> implementation and test changes is provided
>> below. If  you have any questions, or need more detailed explanations, I 
>> (and the  rest of the Panama team) will be
>> happy to point at existing discussions,  and/or to provide the feedback 
>> required.   A big thank to Erik Osterlund,
>> Vladimir Ivanov and David Holmes, without whom the work on shared memory 
>> segment would not have been possible; also I'd
>> like to thank Paul Sandoz, whose insights on API design have been very 
>> helpful in this journey.  Thanks  Maurizio
>> Javadoc:   
>> http://cr.openjdk.java.net/~mcimadamore/8254162_v1/javadoc/jdk/incubator/foreign/package-summary.html
>> Specdiff:
>> 
>> http://cr.openjdk.java.net/~mcimadamore/8254162_v1/specdiff/jdk/incubator/foreign/package-summary.html
>> 
>> CSR:
>> 
>> https://bugs.openjdk.java.net/browse/JDK-8254163
>> 
>> 
>> 
>> ### API Changes
>> 
>> * `MemorySegment`
>>   * drop factory for restricted segment (this has been moved to 
>> `MemoryAddress`, see below)
>>   * added a no-arg factory for a native restricted segment representing 
>> entire native heap
>>   * rename `withOwnerThread` to `handoff`
>>   * add new `share` method, to create shared segments
>>   * add new `registerCleaner` method, to register a segment against a cleaner
>>   * add more helpers to create arrays from a segment e.g. `toIntArray`
>>   * add some `asSlice` overloads (to make up for the fact that now segments 
>> are more frequently used as cursors)
>>   * rename `baseAddress` to `address` (so that `MemorySegment` can implement 
>> `Addressable`)
>> * `MemoryAddress`
>>   * drop `segment` accessor
>>   * drop `rebase` method and replace it with `segmentOffset` which returns 
>> the offset (a `long`) of this address relative
>> to a given segment
>> * `MemoryAccess`
>>   * New class supporting several static dereference helpers; the helpers are 
>> organized by carrier and access mode, where a
>> carrier is one of the usual suspect (a Java primitive, minus `boolean`); 
>> the access mode can be simple (e.g. access
>> base address of given segment), or indexed, in which case the accessor 
>> takes a segment and either a low-level byte
>> offset,or a high level logical index. The classification is reflected in 
>> the naming scheme (e.g. `getByte` vs.
>> `getByteAtOffset` vs `getByteAtIndex`).
>> * `MemoryHandles`
>>   * drop `withOffset` combinator
>>   * drop `withStride` combinator
>>   * the basic memory access handle factory now returns a var handle which 
>> takes a `MemorySegment` and a `long` - from which
>> it is easy to derive all the other handles using plain var handle 
>> combinators.
>> * `Addressable`
>>   * This is a new interface which is attached to entities which can be 
>> projected to a `MemoryAddress`. For now, both
>> 

Re: RFR: 8254162: Implementation of Foreign-Memory Access API (Third Incubator) [v6]

2020-10-12 Thread Maurizio Cimadamore
> This patch contains the changes associated with the third incubation round of 
> the foreign memory access API incubation
> (see JEP 393 [1]). This iteration focus on improving the usability of the API 
> in 3 main ways:
> * first, by providing a way to obtain truly *shared* segments, which can be 
> accessed and closed concurrently from
>   multiple threads
> * second, by providing a way to register a memory segment against a 
> `Cleaner`, so as to have some (optional) guarantee
>   that the memory will be deallocated, eventually
> * third, by not requiring users to dive deep into var handles when they first 
> pick up the API; a new `MemoryAccess` class
>   has been added, which defines several useful dereference routines; these 
> are really just thin wrappers around memory
>   access var handles, but they make the barrier of entry for using this API 
> somewhat lower.
> 
> A big conceptual shift that comes with this API refresh is that the role of 
> `MemorySegment` and `MemoryAddress` is not
> the same as it used to be; it used to be the case that a memory address could 
> (sometimes, not always) have a back link
> to the memory segment which originated it; additionally, memory access var 
> handles used `MemoryAddress` as a basic unit
> of dereference.  This has all changed as per this API refresh;  now a 
> `MemoryAddress` is just a dumb carrier which
> wraps a pair of object/long addressing coordinates; `MemorySegment` has 
> become the star of the show, as far as
> dereferencing memory is concerned. You cannot dereference memory if you don't 
> have a segment. This improves usability
> in a number of ways - first, it is a lot easier to wrap native addresses 
> (`long`, essentially) into a `MemoryAddress`;
> secondly, it is crystal clear what a client has to do in order to dereference 
> memory: if a client has a segment, it can
> use that; otherwise, if the client only has an address, it will have to 
> create a segment *unsafely* (this can be done
> by calling `MemoryAddress::asSegmentRestricted`).  A list of the API, 
> implementation and test changes is provided
> below. If  you have any questions, or need more detailed explanations, I (and 
> the  rest of the Panama team) will be
> happy to point at existing discussions,  and/or to provide the feedback 
> required.   A big thank to Erik Osterlund,
> Vladimir Ivanov and David Holmes, without whom the work on shared memory 
> segment would not have been possible; also I'd
> like to thank Paul Sandoz, whose insights on API design have been very 
> helpful in this journey.  Thanks  Maurizio
> Javadoc:   
> http://cr.openjdk.java.net/~mcimadamore/8254162_v1/javadoc/jdk/incubator/foreign/package-summary.html
> Specdiff:
> 
> http://cr.openjdk.java.net/~mcimadamore/8254162_v1/specdiff/jdk/incubator/foreign/package-summary.html
> 
> CSR:
> 
> https://bugs.openjdk.java.net/browse/JDK-8254163
> 
> 
> 
> ### API Changes
> 
> * `MemorySegment`
>   * drop factory for restricted segment (this has been moved to 
> `MemoryAddress`, see below)
>   * added a no-arg factory for a native restricted segment representing 
> entire native heap
>   * rename `withOwnerThread` to `handoff`
>   * add new `share` method, to create shared segments
>   * add new `registerCleaner` method, to register a segment against a cleaner
>   * add more helpers to create arrays from a segment e.g. `toIntArray`
>   * add some `asSlice` overloads (to make up for the fact that now segments 
> are more frequently used as cursors)
>   * rename `baseAddress` to `address` (so that `MemorySegment` can implement 
> `Addressable`)
> * `MemoryAddress`
>   * drop `segment` accessor
>   * drop `rebase` method and replace it with `segmentOffset` which returns 
> the offset (a `long`) of this address relative
> to a given segment
> * `MemoryAccess`
>   * New class supporting several static dereference helpers; the helpers are 
> organized by carrier and access mode, where a
> carrier is one of the usual suspect (a Java primitive, minus `boolean`); 
> the access mode can be simple (e.g. access
> base address of given segment), or indexed, in which case the accessor 
> takes a segment and either a low-level byte
> offset,or a high level logical index. The classification is reflected in 
> the naming scheme (e.g. `getByte` vs.
> `getByteAtOffset` vs `getByteAtIndex`).
> * `MemoryHandles`
>   * drop `withOffset` combinator
>   * drop `withStride` combinator
>   * the basic memory access handle factory now returns a var handle which 
> takes a `MemorySegment` and a `long` - from which
> it is easy to derive all the other handles using plain var handle 
> combinators.
> * `Addressable`
>   * This is a new interface which is attached to entities which can be 
> projected to a `MemoryAddress`. For now, both
> `MemoryAddress` and `MemorySegment` implement it; we have plans, with JEP 
> 389 [2] to add more implementations. Clients
> can largely ignore this interface, which