<div dir="ltr">Hi,<div><br></div><div>This looks like a good and simple API overall, with a clear path on how each individual use case is solved.</div><div><br></div><div>I found that details of the behavior of Arena.close() were lacking in the API description, now that we are back to having close methods on things that can't be closed:</div><div>It is not described what happens when you call close() on global and auto scoped arenas. I also see no mechanism for querying if an arena has one of these scopes.</div><div>The document says it's unclear what isCloseable() should return for an arena where close() always throws. I'm not so sure.</div><div>I think the query could be framed as "if I were to call close(), is it likely to succeed?" (I use "likely" here since shared scopes could race).</div><div><br></div><div>To illustrate where this might be relevant, suppose we have web application with a component A in charge of formulating responses to clients, and another component B in charge of doing IO.</div><div>Component A sends MemorySegments and Arenas to B, and these could be a mix of shared or confined scopes, and auto-scoped for cached data like images and CSS files.</div><div>Lifetimes start in A, but only conditionally end in B. This will need to be tracked, since the arenas and scopes can't be queried for this information.</div><div>While this is certainly possible, it seems like a wasteful step, as the arena ought to have this knowledge in order to implement close() itself.</div><div><br></div><div>This is the only thing I'm wondering about. The rest of the API looks very good.</div><div><br></div><div>Cheers,</div><div>Chris</div></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Tue, Jan 31, 2023 at 10:46 AM Maurizio Cimadamore <<a href="mailto:maurizio.cimadamore@oracle.com">maurizio.cimadamore@oracle.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex">Hi,<br>
as discussed here [1], it is not clear as to whether Java 20 iteration <br>
of the Foreign Function & Memory API (FFM API) has yet reached bottom, <br>
especially when it comes to managing the lifetime of the regions of <br>
memory backing memory segments. After collecting some rounds of internal <br>
and external feedback, it was clear that while the Java 20 API has all <br>
the functionalities we require for writing efficient and robust native <br>
interop code, some of the concepts in the API were made a bit harder to <br>
grok, as users had to choose between two toplevel abstractions, namely <br>
`SegmentScope` and `Arena`. This choice is made even more difficult, as <br>
some of the functionalities (e.g. allocation) is duplicated in both API <br>
points. As a result, we have been busy exploring different ways to <br>
restack the FFM API in search of something more approachable.<br>
<br>
The results of our findings are described in this document:<br>
<br>
<a href="http://cr.openjdk.java.net/~mcimadamore/panama/scoped_arenas.html" rel="noreferrer" target="_blank">http://cr.openjdk.java.net/~mcimadamore/panama/scoped_arenas.html</a><br>
<br>
Here, we propose a possible simplification of the FFM API, where we make <br>
`Arena` the true star of the show, which results in the following changes:<br>
<br>
* factories such as `SegmentScope::auto` are now moved to `Arena`;<br>
* all segment-producing methods (such as `FileChannel::map`) now accept <br>
an `Arena` parameter;<br>
* static factories such as `MemorySegment::allocateNative` have been <br>
dropped;<br>
* scopes are made less prominent, and moved to a nested class <br>
(`MemorySegment.Scope`).<br>
<br>
This gives us a remarkably simple API, which brings together the best <br>
aspects of the Java 19 and Java 20 FFM API iterations. On the one hand, <br>
`Arena` is now the most important abstraction that users of the FFM API <br>
have to deal with (in a way, `Arena` is the new `MemorySession`); at the <br>
same time, we still have a way to model the lifetime of an `Arena` (and <br>
all the segments allocated by it) using a `MemorySegment.Scope` - which <br>
is desirable both in terms of debugging (e.g. inspecting whether two <br>
segments/arenas have the same lifetime) and, more importantly, in terms <br>
of allowing the definition of custom arenas via simple delegation (as in <br>
Java 20).<br>
<br>
As always, feedback is welcome. While this proposal does not <br>
significantly alter the expressiveness of the FFM API, the proposed API <br>
comes with some limitations. For instance, since all allocation routines <br>
are now `Arena`-centric (see above), it is no longer possible to <br>
allocate a new segment if a corresponding arena is not available (we <br>
call this co-allocation). As explained in the document, while it would <br>
be possible to add back the missing co-allocation functionality, <br>
extensive analysis of the code using the FFM API has shown co-allocation <br>
to be _extremely_ rare (**) - and of dubious value. For these reasons, <br>
we would like to aim for a more principled approach which avoids <br>
co-allocation altogether, and allows for more encapsulation of the <br>
capabilities associated with an `Arena` object.<br>
<br>
Maurizio<br>
<br>
(**) We have only found _one_ usage [2] in over 10K Java files and more <br>
than 11M LoC analyzed. Moreover, this usage is only present in the Java <br>
19 branch of the project, and removed in the "main" branch (which tracks <br>
the Java 20 FFM API). We suspect that this use of co-allocation has been <br>
made irrelevant after the unification of `MemoryAddress` and <br>
`MemorySegment`.<br>
<br>
[1] - <br>
<a href="https://mail.openjdk.org/pipermail/panama-dev/2022-December/018182.html" rel="noreferrer" target="_blank">https://mail.openjdk.org/pipermail/panama-dev/2022-December/018182.html</a><br>
[2] - <br>
<a href="https://github.com/boulder-on/JPassport/blob/Java_19/jpassport/src/main/java/jpassport/Utils.java#L418" rel="noreferrer" target="_blank">https://github.com/boulder-on/JPassport/blob/Java_19/jpassport/src/main/java/jpassport/Utils.java#L418</a><br>
<br>
<br>
<br>
<br>
<br>
<br>
</blockquote></div>