Summary
This CSR refers to second iteration of the Foreign Memory Access (an incubating Java API) originally targeted for Java 14, with the goal of refining some of the API rough edges, as well as addressing the feedback received so far from developers.
Problem
Real-world use of the Foreign Memory Access API revealed some usability issues, listed below:
- converting
MemoryAddress
to/fromlong
values is too hard - The API's bias towards confinement would benefit from an API point to cooperatively change thread owership of a given segment (serial confinement)
- The
MemorySegment::acquire
is too complex, as it leads to trees of segments where the enclosing segment cannot be closed before the nested ones are; at the same time, this API fails to provide enough support for clients that wish for a truly unconfined memory segment - While the API supports mapped memory segments via its
MemorySegment::mapFromPath
factory, the support is partial, since there's no way to force the mapped segment contents back into the mapped file. - When implementing frameworks on top of memory access var handle, it is often handy to be able to perform deep adaptation of the var handles so that e.g. additional access coordinates can be inserted, dropped, or bound
- An unsafe API point is required to create a native segment out of an existing
MemoryAddress
instance; this is the moral equivalent of the JNI NewDirectByteBuffer function.
Solution
Here we describe the main ideas behind the API changes brought forward in this CSR:
- not all
MemoryAddress
instances are created equal; some addresses are checked --- that is, they are associated with an underlyingMemorySegment
, some are unchecked e.g. they are just wrappers around some native address. Dereference on aMemoryAddress
instance can only be considered safe if the address being dereferenced is checked - since the associated segment would provide enough context (spatial, temporal, thread confinement bounds) to validate the access. With this distinction in mind, it is then possible to add API points to e.g. safely create aNULL
address (which would be unchecked) or an address wrapping a given long value. - Remove the
MemorySegment::acquire
method, whose complexity was ultimately not helping the use cases for which it was created. In its place, to allow for parallel processing of a segment content, we instead offer the ability to slice and dice a memory segment using a segmentSpliterator
. - To make serial thread confinement more useful in producer/consumer use cases, a new API point
MemorySegment::withOwnerThread
is added so that one thread can give up ownership on a given segment and transfer ownership to a second thread. - A new interface, namely
MappedMemorySegment
(which extends fromMemorySegment
) is provided, which adds functionalities equivalent toMappedByteBuffer::force
andMappedByteBuffer::load
. - The new API also provides a number of new
VarHandle
adapters; while these are temporarily defined in theMemoryHandles
class, in reality these adapters are general (pretty much like method handle adapters in theMethodHandles
class) and will be moved into theMethodHandles
class when the API exits incubation. - A new memory segment factory has been added, namely
MemorySegment::ofNativeRestricted
which allows developers to take an existing memory address and create a segment out of it. Since an address is not guaranteed to have any associated spatial and temporal bounds (as is the case for unchecked addresses) such an operation is inherently unsafe. To limit the exposure of this API point, we have opted to guard calls to this method with a read-only JDK property, namely-Dforeign.restricted
; this property can assume several values - the default value isdeny
, which will trigger an hard exception each time such a method is called. Developers can override this property value from the command line, to e.g.permit
, which will allow calls to this method to succeed. Note: this way of accessing restricted foreign functionalities through a runtime property is a pragmatic compromise, which will be replaced by a more robust mechanism (perhaps based on the module system) by the time the API exits the incubation stage.
Specification
Here are some useful links which should help in navigating through the changes in the API.
Webrev:
http://cr.openjdk.java.net/~mcimadamore/8243491_v3/webrev
Javadoc:
http://cr.openjdk.java.net/~mcimadamore/8243491_v3/javadoc
Specdiff:
http://cr.openjdk.java.net/~mcimadamore/8243491_v3/specdiff/overview-summary.html
In addition, a specdiff of the changes as of May 1st 2020 has been attached to this CSR.
- csr of
-
JDK-8243491 Implementation of Foreign-Memory Access API (Second Incubator)
- Resolved
- relates to
-
JDK-8234050 Implementation of Memory Access API (Incubator)
- Closed
-
JDK-8246053 Add a mask for default access modes
- Resolved