Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8254163

Implementation of Foreign-Memory Access API (Third Incubator)

XMLWordPrintable

    • Icon: CSR CSR
    • Resolution: Approved
    • Icon: P3 P3
    • 16
    • core-libs
    • None
    • source, binary
    • low
    • Hide
      The changes described here might impact some clients; more specifically, the biggest incompatibility is in the behavior of the memory access var handle; they used to accept a `MemoryAddress` coordinate, but that has changed in this update to a `MemorySegment` coordinate. Other areas of the API, remained largely unchanged, despite getting some improvements and added functionalities.

      That said, since the API is an incubating API, and not available by default (unless the `--add-modules` flag is passed to the `java` launcher), these changes should not affect a significant portion of users.
      Show
      The changes described here might impact some clients; more specifically, the biggest incompatibility is in the behavior of the memory access var handle; they used to accept a `MemoryAddress` coordinate, but that has changed in this update to a `MemorySegment` coordinate. Other areas of the API, remained largely unchanged, despite getting some improvements and added functionalities. That said, since the API is an incubating API, and not available by default (unless the `--add-modules` flag is passed to the `java` launcher), these changes should not affect a significant portion of users.
    • Java API

      Summary

      This CSR refers to the third iteration of the Foreign Memory Access (an incubating Java API) originally targeted for Java 14 (and later re-incubated in 15), 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 remaining usability issues, listed below:

      • The API's bias towards confinement is still too prominent, despite the addition (in 15) of an API point to cooperatively change thread ownership of a given segment (serial confinement); the main issue is that, even with the new API, it is still not possible to close a memory segment from a thread other than the owner thread, and that makes memory segment hard to use with certain API idioms
      • While deterministic deallocation is one of the core foundations of the Foreign Memory Access API, users have expressed interest in having the ability to optionally register segments against a Cleaner instance, so that segment deallocation could be guaranteed regardless of whether an explicit call to MemorySegment::close is made
      • The distinction between checked and unchecked memory addresses is too subtle. Checked addresses have a reference to the owning segment, and can be safely dereferenced, whereas unchecked addresses can't. This leads to verbosity in clients attempting to dereference a MemoryAddress instance, as the client has first to query if a segment is available, and then act accordingly.
      • Forcing developers to exclusively use VarHandle when it comes to dereference memory is a bit too much; there are cases where the expressive power of var handles come in handy (e.g. in concurrent contexts, when fencing is required, or when structural access is needed), but in simpler cases it would be nice to have a ready-made collections of dereference API points which can be used in a type-safe way.
      • While a memory address and a memory segment generally represent separate concepts, it is possible to go from the latter to the former (e.g. by calling the MemorySegment::baseAddress method). Our experiments with the jextract tool revealed that the need for this explicit conversion has often a pretty big impact in the verbosity of clients interacting with the native bindings generated by jextract.

      Solution

      Here we describe the main ideas behind the API changes brought forward in this CSR:

      • First, the notion of shared memory segment is introduced. A shared memory segment is created by invoking the MemorySegment::share method that returns a new memory segment instance, which is backed by the same memory region, and has no owner thread. This means that the segment will be effectively accessible (and closeable) from multiple threads (possibly in a concurrent fashion). The safety promises of the Foreign Memory Access API are preserved by a sophisticated lock-free synchronization scheme which relies on thread-local handshakes (see JEP 312).
      • A new method is added to memory segments, MemorySegment::registerCleaner(Cleaner) that returns a new segment instance, which is backed by the same memory region, and supports implicit deallocation.
      • Memory access var handles now use memory segments as the basic dereference unit. That is, the most basic memory access var handle accepts two coordinates: the segment to be dereferenced and the offset within the segment at which the dereference should occur. All other, structural memory access var handles can be composed from this basic one. As a result, MemoryAddress has reverted back to being a dumb carrier for an object/offset unsafe addressing coordinate pair. That is, there is no way to go from an address back to a segment (except unsafely via MemoryAddress::asSegmentRestricted but that creates a new segment).
      • A new class, namely MemoryAccess is introduced. This class contains several dereference methods to get and set values in memory, with different Java carriers. There are different access modes supported: a basic one which simply takes a memory segment and dereferences it at its base address; other, more sophisticated, modes allows a byte offset or a logical index to be passed as well, to support common array-like access idioms.
      • To better capture the commonality between a memory segment and a memory address a new interface, namely Addressable has been introduced. This interface describes entities that can be mapped into a memory address. This interface is implemented, trivially, by MemoryAddress and also by MemorySegment (a memory segment can always be projected to its base address). We plan, with subsequent JEPs (e.g. JEP 389) to add more implementations of this interface.
      • The hierarchy of interface MappedMemorySegment <: MemorySegment poses issues when it comes to VarHandle invocations; since now the memory access var handle take a MemorySegment access coordinate, calling such var handles with a MappedMemorySegment coordinate will result in a non-exact var handle call, thus greatly degrading performances; we have decided to drop the MappedMemorySegment interface and instead introduce an helper class, namely MappedMemorySegments, which contains static methods which provide the same functionality as what was provided by MappedMemorySegment.

      Specification

      Here are some useful links which should help in navigating through the changes in the API.

      Javadoc:

      http://cr.openjdk.java.net/~mcimadamore/8254162_v5/javadoc

      Specdiff:

      http://cr.openjdk.java.net/~mcimadamore/8254162_v5/specdiff_out

      Pull request:

      https://github.com/openjdk/jdk/pull/548

      In addition, a specdiff of the changes as of November 9th 2020 has been attached to this CSR.

        1. specdiff__v4.zip
          252 kB
        2. specdiff_delta_v4.zip
          199 kB
        3. specdiff_delta_v5.zip
          187 kB
        4. specdiff_v1.zip
          287 kB
        5. specdiff_v3.zip
          246 kB
        6. specdiff_v5.zip
          252 kB
        7. specdiff.zip
          251 kB

            mcimadamore Maurizio Cimadamore
            mcimadamore Maurizio Cimadamore
            Paul Sandoz
            Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

              Created:
              Updated:
              Resolved: