JDK-8295045 : Implementation of Foreign Function and Memory API (Second Preview)
  • Type: CSR
  • Component: core-libs
  • Priority: P3
  • Status: Closed
  • Resolution: Approved
  • Fix Versions: 20
  • Submitted: 2022-10-10
  • Updated: 2023-08-29
  • Resolved: 2022-12-04
Related Reports
CSR :  
Relates :  
Relates :  
Relates :  
Relates :  
Description
Summary
-------

This CSR refers to the second preview iteration of the Foreign Function & Memory (FFM) API originally targeted for Java 19, with the goal of further refining and consolidating the FFM API.

Problem
-------

Feedback on the incubating API revealed the following issues:

 * The separation between `MemorySegment` and `MemoryAddress` can be confusing, as a `MemoryAddress` effectively acts as a zero-length memory segment;
 * The `MemorySession` interface has some issues:
  - Not all sessions are closeable, despite the interface implements `AutoCloseable`;
  - APIs sometimes need to use non-closeable session views to protect against clients closing sessions using the `MemorySegment::session` accessor;
  - Some of the predicates in `MemorySession` are leaking too much information (e.g. `MemorySession::ownerThread`).
 * The memory layout hierarchy is not exhaustive, which leads to problem when used in combination with pattern matching;
 * The naming of the method `SymbolLookup::lookup` is unfortunate, as the same word `lookup` is used both in the noun form (class name) and the verb form (method name).
 * There is no way to allow restricted operations on a module in a custom layer, as the command line option only works for modules in the boot layer;
 * The Linker API needs ways for clients to customize the properties of the downcall method handles. Some examples of this:
  - Mark a downcall method handle as "trivial" - that is, a method handle that performs little computation, does not block and does not upcall to Java (e.g. `getpid`);
  - Request that the Linker saves the state of certain native variables, such as `errno` or `LastError` (as these might get overwritten during normal JVM operation);
  - Request that one or more by-reference parameters in a downcall might be *pinned* heap segments. That is, memory segments backed by on-heap region of memory which should not be moved for the duration of the call;
  - Specify custom calling conventions (e.g. `fastcall`);
  - Tweak the safety parameters of the API, to achieve different safety vs. performance trade-offs (e.g. avoid keeping alive by-reference parameters).

Solution
-------

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

 *  `MemoryAddress` and `Addressable` are removed from the FFM API. Instead, zero-length memory segments are used whenever the FFM API needs to model "raw" addresses coming from native code. This simplifies the FFM API, removing an ambiguous abstraction as well as some duplication in the API (see accessor methods in `MemoryAddress`). The rationale behind these changes is described in [1].

 * `MemorySession` has been replaced with `SegmentScope`, a pure lifetime abstraction which does not implement `AutoCloseable` and `SegmentAllocator`. A `SegmentScope` controls *which* threads have access to a memory segment and *when*. A scope that can be used to allocate segments that are never allocated is the *global scope* (`SegmentScope::global`). Or, clients can obtain a scope, the *automatic scope* (`SegmentScope::auto`) that can be used to allocate segments that are deallocated automatically, by the garbage collector. Clients requiring deterministic deallocation must use the new `Arena` abstraction. An `Arena` provides a scope - the *arena scope* (`Arena::scope`). When the arena is closed, the arena scope becomes not alive, thus invalidating all the segments associated with the arena scope. This allows us to remove support for non-closeable memory session views (`MemorySession::asNonCloseable`, `MemorySession::isCloseable`, `MemorySession::equals`, `MemorySession::hashCode`). The rationale behind these changes is described in [2].

 * The `MemorySession::ownerThread()` method has been replaced with a more focussed predicate `SegmentScope:isOwnedBy(Thread)`

 * The `SegmentAllocator::newNativeArena` factory methods have been replaced with a more basic `SegmentAllocator::slicingAllocator(MemorySegment)` factory. The new slicing allocator is less powerful than the allocator it replaces, but also simpler to understand, and also much easier to build upon.

 * To allow for "unsafe" access of zero-length memory segments, a new method has been added to `ValueLayout.OfAddress`, namely `asUnbounded`. This new restricted method takes an address layout and creates a new _unbounded_ address layout. When using an unbounded layout to dereference memory, or construct downcall method handles, the FFM API will create memory segments with maximal length (i.e. `Long.MAX_VALUE`, rather than zero-length memory segments, which can therefore be accessed.

 * Several changes to the `MemoryLayout` hierarchy:
  - The hierarchy is now defined in terms of sealed interfaces
  - Three new types have been added: `PaddingLayout`, `StructLayout` and `UnionLayout` (the latter two are a subtype of `GroupLayout`);
  - Several predicate methods (`isPadding`, `isStruct`, `isUnion`) have been dropped in favor of pattern matching (which now works as expected).
 * The `SymbolLookup::lookup` method has been renamed to `SymbolLookup::find`;
 * A new method, on `ModuleLayer.Controller` has been added to enable native access on a module in a custom layer;
 * The new interface `Linker.Option` has been introduced. This is a tag interface accepted in `Linker::downcallHandle`. At the moment, only a single option is provided, to specify variadic function calls (because of this, the `FunctionDescriptor` interface has been simplified, and is now a simple carrier of arguments/return layouts). More linker options will follow.

Specification
-------------

A specdiff and javadoc of the changes as of November 30th, 2022 are available below:

 * http://cr.openjdk.java.net/~mcimadamore/jdk/8295044/v4/javadoc/java.base/module-summary.html
 * http://cr.openjdk.java.net/~mcimadamore/jdk/8295044/v4/specdiff_out/overview-summary.html

A delta of the specdiff between what has been previously submitted is available here:

 * (v2 vs. v1) http://cr.openjdk.java.net/~mcimadamore/jdk/8295044/v2/specdiff_out_delta/overview-summary.html
 * (v3 vs. v2) http://cr.openjdk.java.net/~mcimadamore/jdk/8295044/v3/specdiff_out_delta/overview-summary.html
 * (v4 vs. v3) http://cr.openjdk.java.net/~mcimadamore/jdk/8295044/v4/specdiff_out_delta/overview-summary.html

References
-------------

 1. http://cr.openjdk.java.net/~mcimadamore/panama/segment_address.html
 2. http://cr.openjdk.java.net/~mcimadamore/panama/session_arenas.html
Comments
Thanks - we will consider targeted javadoc improvements as separate PRs (as for the Linker, we already knew that the current doc is a bit lacking, especially when compared with the JEP). I have filed some JBS issues to keep track of these comments (see linked issues).
05-12-2022

Moving to Approved, with comments. For the implSpec tags in SegmentAllocator, besides stating "the default implementation for this method calls this.allocate(layout)", I'd expect some mention of use of the value argument in the default implementation. In the layout hierarchy, I agree it is simpler overall to *not* use an F-bounded type variable to define the return type for the withName and withBitAlignment methods. For the nativeLinker, I think it may be helpful to say more about platform-specific mappings of C types, perhaps even defining a future programmatic interface. For example, the package-level docs discuss getting a MethodHandle around C's strlen using FunctionDescriptor.of(ValueLayout.JAVA_LONG, ValueLayout.ADDRESS). At a C level, strlen is defined as having a signature of "size_t strlen(const char *str)" it isn't surprising a linker would map the unsigned size_t to a Java long, but it isn't obvious either, or necessarily the only choice all all the platform a JVM would be run on (such as 32-bit).
04-12-2022

Finalizing with v4 javadoc/specdiff. The only changes are very minor cosmetic javadoc improvements.
30-11-2022

Per previous discussions (e.g. https://bugs.openjdk.org/secure/EditComment!default.jspa?id=5069031&commentId=14484031) good to see the Closeable session issue addressed. Moving to Provisional.
30-11-2022

Attachment <v1.tar.gz> could not be scanned. The system has removed attachment. Please check the file before attempting to upload it again
19-10-2022

Attachment <javadoc.zip> could not be scanned. The system has removed attachment. Please check the file before attempting to upload it again
11-10-2022

Attachment <specdiff_out.zip> could not be scanned. The system has removed attachment. Please check the file before attempting to upload it again
11-10-2022

At the moment we don't accept linker options for upcall stubs yet, because we don't have any.
10-10-2022