Hi,

Looks good. I have seen almost all of this in reviews on panama-dev hence the 
lack of substantial comments here.

I suspect we are not gonna need the drop argument VH combinator, dropping 
coordinates feels a little suspicious to me, but I can see why it's there for 
completeness.

Paul.

> On Apr 23, 2020, at 1:33 PM, Maurizio Cimadamore 
> <maurizio.cimadam...@oracle.com> wrote:
> 
> Hi,
> time has come for another round of foreign memory access API incubation (see 
> JEP 383 [3]). This iteration aims at polishing some of the rough edges of the 
> API, and adds some of the functionalities that developers have been asking 
> for during this first round of incubation. The revised API tightens the 
> thread-confinement constraints (by removing the MemorySegment::acquire 
> method) and instead provides more targeted support for parallel computation 
> via a segment spliterator. The API also adds a way to create a custom native 
> segment; this is, essentially, an unsafe API point, very similar in spirit to 
> the JNI NewDirectByteBuffer functionality [1]. By using this bit of API,  
> power-users will be able to add support, via MemorySegment, to *their own 
> memory sources* (e.g. think of a custom allocator written in C/C++). For now, 
> this API point is called off as "restricted" and a special read-only JDK 
> property will have to be set on the command line for calls to this method to 
> succeed. We are aware there's no precedent for something like this in the 
> Java SE API - but if Project Panama is to remain true about its ultimate goal 
> of replacing bits of JNI code with (low level) Java code, stuff like this has 
> to be *possible*. We anticipate that, at some point, this property will 
> become a true launcher flag, and that the foreign restricted machinery will 
> be integrated more neatly into the module system.
> 
> 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.
> 
> Thanks
> Maurizio
> 
> Webrev:
> 
> http://cr.openjdk.java.net/~mcimadamore/8243491_v1/webrev
> 
> Javadoc:
> 
> http://cr.openjdk.java.net/~mcimadamore/8243491_v1/javadoc
> 
> Specdiff:
> 
> http://cr.openjdk.java.net/~mcimadamore/8243491_v1/specdiff/overview-summary.html
> 
> CSR:
> 
> https://bugs.openjdk.java.net/browse/JDK-8243496
> 
> 
> 
> API changes
> ===========
> 
> * MemorySegment
>   - drop support for acquire() method - in its place now you can obtain a 
> spliterator from a segment, which supports divide-and-conquer
>   - revamped support for views - e.g. isReadOnly - now segments have access 
> modes
>   - added API to do serial confinement hand-off 
> (MemorySegment::withOwnerThread)
>   - added unsafe factory to construct a native segment out of an existing 
> address; this API is "restricted" and only available if the program is 
> executed using the -Dforeign.unsafe=permit flag.
>   - the MemorySegment::mapFromPath now returns a MappedMemorySegment
> * MappedMemorySegment
>   - small sub-interface which provides extra capabilities for mapped segments 
> (load(), unload() and force())
> * MemoryAddress
>   - added distinction between *checked* and *unchecked* addresses; 
> *unchecked* addresses do not have a segment, so they cannot be dereferenced
>   - added NULL memory address (it's an unchecked address)
>   - added factory to construct MemoryAddress from long value (result is also 
> an unchecked address)
>   - added API point to get raw address value (where possible - e.g. if this 
> is not an address pointing to a heap segment)
> * MemoryLayout
>   - Added support for layout "attributes" - e.g. store metadata inside 
> MemoryLayouts
>   - Added MemoryLayout::isPadding predicate
>   - Added helper function to SequenceLayout to rehape/flatten sequence 
> layouts (a la NDArray [4])
> * MemoryHandles
>   - add support for general VarHandle combinators (similar to MH combinators)
>   - add a combinator to turn a long-VH into a MemoryAddress VH (the resulting 
> MemoryAddress is also *unchecked* and cannot be dereferenced)
> 
> Implementation changes
> ======================
> 
> * add support for VarHandle combinators (e.g. IndirectVH)
> 
> The idea here is simple: a VarHandle can almost be thought of as a set of 
> method handles (one for each access mode supported by the var handle) that 
> are lazily linked. This gives us a relatively simple idea upon which to build 
> support for custom var handle adapters: we could create a VarHandle by 
> passing an existing var handle and also specify the set of adaptations that 
> should be applied to the method handle for a given access mode in the 
> original var handle. The result is a new VarHandle which might support a 
> different carrier type and more, or less coordinate types. Adding this 
> support was relatively easy - and it only required one low-level surgery of 
> the lambda forms generated for adapted var handle (this is required so that 
> the "right" var handle receiver can be used for dispatching the access mode 
> call).
> 
> All the new adapters in the MemoryHandles API (which are really defined 
> inside VarHandles) are really just a bunch of MH adapters that are stitched 
> together into a brand new VH. The only caveat is that, we could have a 
> checked exception mismatch: the VarHandle API methods are specified not to 
> throw any checked exception, whereas method handles can throw any throwable. 
> This means that, potentially, calling get() on an adapted VarHandle could 
> result in a checked exception being thrown; to solve this gnarly issue, we 
> decided to scan all the filter functions passed to the VH combinators and 
> look for direct method handles which throw checked exceptions. If such MHs 
> are found (these can be deeply nested, since the MHs can be adapted on their 
> own), adaptation of the target VH fails fast.
> 
> 
> * More ByteBuffer implementation changes
> 
> Some more changes to ByteBuffer support were necessary here. First, we have 
> added support for retrieval of "mapped" properties associated with a 
> ByteBuffer (e.g. the file descriptor, etc.). This is crucial if we want to be 
> able to turn an existing byte buffer into the "right kind" of memory segment.
> 
> Conversely, we also have to allow creation of mapped byte buffers given 
> existing parameters - which is needed when going from (mapped) segment to a 
> buffer. These two pieces together allow us to go from segment to buffer and 
> back w/o losing any information about the underlying memory mapping (which 
> was an issue in the previous implementation).
> 
> Lastly, to support the new MappedMemorySegment abstraction, all the memory 
> mapped supporting functionalities have been moved into a common helper class 
> so that MappedMemorySegmentImpl can reuse that (e.g. for 
> MappedMemorySegment::force).
> 
> * Rewritten memory segment hierarchy
> 
> The old implementation had a monomorphic memory segment class. In this round 
> we aimed at splitting the various implementation classes so that we have a 
> class for heap segments (HeapMemorySegmentImpl), one for native segments 
> (NativeMemorySegmentImpl) and one for memory mapped segments 
> (MappedMemorySegmentImpl, which extends from NativeMemorySegmentImpl). Not 
> much to see here - although one important point is that, by doing this, we 
> have been able to speed up performances quite a bit, since now e.g. 
> native/mapped segments are _guaranteed_ to have a null "base". We have also 
> done few tricks to make sure that the "base" accessor for heap segment is 
> sharply typed and also NPE checked, which allows C2 to speculate more and 
> hoist. With these changes _all_ segment types have comparable performances 
> and hoisting guarantees (unlike in the old implementation).
> 
> * Add workarounds in MemoryAddressProxy, AbstractMemorySegmentImpl to special 
> case "small segments" so that VM can apply bound check elimination
> 
> This is another important piece which allows to get very good performances 
> out of indexes memory access var handles; as you might know, the JIT compiler 
> has troubles in optimizing loops where the loop variable is a long [2]. To 
> make up for that, in this round we add an optimization which allows the API 
> to detect whether a segment is *small* or *large*. For small segments, the 
> API realizes that there's no need to perform long computation (e.g. to 
> perform bound checks, or offset additions), so it falls back to integer 
> logic, which in turns allows bound check elimination.
> 
> * renaming of the various var handle classes to conform to "memory access var 
> handle" terminology
> 
> This is mostly stylistic, nothing to see here.
> 
> Tests changes
> =============
> 
> In addition to the tests for the new API changes, we've also added some 
> stress tests for var handle combinators - e.g. there's a flag that can be 
> enabled which turns on some "dummy" var handle adaptations on all var handles 
> created by the runtime. We've used this flag on existing tests to make sure 
> that things work as expected.
> 
> To sanity test the new memory segment spliterator, we have wired the new 
> segment spliterator with the existing spliterator test harness.
> 
> We have also added several micro benchmarks for the memory segment API (and 
> made some changes to the build script so that native libraries would be 
> handled correctly).
> 
> 
> [1] - 
> https://docs.oracle.com/en/java/javase/14/docs/specs/jni/functions.html#newdirectbytebuffer
> [2] - https://bugs.openjdk.java.net/browse/JDK-8223051
> [3] - https://openjdk.java.net/jeps/383
> [4] - 
> https://docs.scipy.org/doc/numpy/reference/generated/numpy.reshape.html#numpy.reshape
> 
> 

Reply via email to