Interaction between Panama and Valhalla

Glavo zjx001202 at gmail.com
Tue Mar 15 05:42:05 UTC 2022


Thank you for your reply, but I still have some concerns.

I understand that MemoryAddress[] is not commonly used, so I'm not
particularly worried about it.
And we can also provide something like this as a substitute:

public primitive class MemoryAddressArray implements List<MemoryAddress> {
    private final long[] values;
    public MemoryAddressArray(int size) { this.values = new long[size]; }

    public int size() { return values.length; }
    public MemoryAddress get(int index) { return
MemoryAddress.ofLong(values[index]); }
    public MemoryAddress set(int index, MemoryAddress element) {
        MemoryAddress oldValue = get(index);
        values[index] = element.toRawLongValue();
        return oldValue;
    }

    // ...
}

Relatively speaking, I am more concerned that it cannot be flattened as a
*field*.
As far as I know, the current Hotspot doesn't have the ability to inline
fields.
Even in Valhalla, flattening fields whose type is a value class seems
difficult to do due to null.
I checked Valhalla's current progress and it doesn't seem to have this
ability so far:


I compiled the latest Valhalla repository and compiled the following code
with it:

value record Data(long value) {}

public record Test(Data data) {}


I used the  PrintFieldLayout option to print out the runtime layout of the
object:

Layout of class Test
Instance fields:
 @0 12/- RESERVED
 @12 "data" LData; 4/4 REGULAR
Static fields:
 @0 120/- RESERVED
Instance size = 16 bytes


Here, the field data is not inlined.
But when I modify the Data class to primitive record, the layout of Test is
as follows:

Layout of class Test
Instance fields:
 @0 12/- RESERVED
 @12 4/1 EMPTY
 @16 "data" QData; 8/8 INLINED
Static fields:
 @0 120/- RESERVED
Instance size = 24 bytes


Obviously, data can be easily inlined in this case.

Based on this status quo, I am concerned about whether MemoryAddress is
suitable for storing as a field.
I'm worried that if MemoryAddress can't be a primitive class, I'll have to
use long instead of MemoryAddress for storage in performance-sensitive
situations.
It's a depressing ending, since this requires a lot of unnecessary
conversion code, the semantics will be less clear.
More importantly, the conversion between long and MemoryAddress requires
native access, which may prevent many third-party libraries from performing
such optimizations and bring unnecessary overhead.

Another concern I have is that the interpreter and C1 compiler are far less
optimized than C2.
If in the future Panama is used more internally in the standard library
instead of JNI, and the interpreter and C1 lack the ability to eliminate
allocations, I'm concerned that this will slow down the cold start of
programs.

Sorry to bother you with my confusion, but I sincerely hope my confusion is
answered. Thank you very much.

On Wed, Mar 2, 2022 at 7:08 PM Maurizio Cimadamore <
maurizio.cimadamore at oracle.com> wrote:

> Hi,
> as you point out, there is a deep connection between Valhalla and
> Panama, both for the Vector and the Foreign API.
>
> In the Foreign API, which is what you refer to here, there are few
> possible candidates for the Valhalla treatment that we have considered:
>
> 1) MemoryAddress - as you say, this is a wrapper on a `long` so it's
> almost a slamdunk;
>
> 2) MemorySegment - since segments are also immutable, it would be
> possible, in principle to make these value classes too. This is harder
> though, as memory segments currently need to use a complex class
> hierarchy so that the optimizing compiler can see their on-heap vs.
> off-heap state. While it is possible that _some day_ the JVM might give
> us more power to flatten hierarchies like MemorySegment (by speculating
> on one or more memory segment fields, instead that on the memory segment
> concrete type), this is not something that will happen quickly. So
> opportunties to take advantage of Valhalla are, IMHO, somewhat limited,
> especially in the short term.
>
> 3) MemoryLayout - these are immutable too.  That said, layouts are
> almost always (if used correctly) stored in some static final constant.
> Removing allocations for layouts is not where the gains are.
>
> 4) ResourceScope/MemorySession. This is a stateful abstraction, Valhalla
> makes no sense here.
>
> Now (1) is the most obvious candidate for a primitive class. In the
> current API, MemoryAddress is defined as an interface. This gives us
> freedom to tweak the implementation under the hood (e.g. and make it a
> primitive class) as we see fit. This also creates issues: to apply some
> of the more advanced optimizations, the JVM would need to "see through"
> the fact that MemoryAddress is a _sealed_ interface with only one known
> implementation. And maybe, even that won't be enough to fully achieve
> the primitive class Nirvana (e.g. flattening an array of MemoryAddress):
> the MemoryAddress interface type is nullable, and that might well
> perturb some of the analysis/optimizations.
>
> That said, after having worked with the API for quite some time, I
> honestly think that doing (2), while harder, will produce much better
> returns in terms of performance. The MemoryAddress class is so simple
> that in 90% of cases Hotspot can already eliminate the allocation
> _today_, w/o any extra help from Valhalla. MemorySegments are a
> different story though, as they embed more state, and scalarization
> doesn't always happen (see [1]). As for (2), making MemorySegment a
> primitive class makes less sense, as memory segments have several
> fields, so it's not clear that having a flattened MemorySegment[] would
> be better, and tearing will probably be unacceptable here (as it can
> have the potential of breaking lifetime invariants). So I think for (2)
> value classes are just fine.
>
> Decisions such as these have always to be taken in a context. Of course
> if, by the time Panama is about to exit preview, primitive classes are
> ready, I'm more than available to keep Panama previewing for a little
> longer, so that we can sprinke primitive class treatment where it
> belongs. But it's always a cost vs. benefit analysis. Value classes (JEP
> 401) gives us better scalarization and better calling conventions, as
> well as limited flattening in some cases (esp. if value classes are
> nested inside other classes) and those improvements might, alone,
> provide a decent enough boost. While I agree that, in an ideal world,
> MemoryAddress would be a primitive class, I'm not so sure that holding
> back the entire Foreign API so that we can make MemoryAddress fully
> flattenable is the best option. The only real added bonus this option
> would provide is better flattening for MemoryAddress[] - which is
> something I have not encountered frequently when using the API; it is a
> lot more common, in my experience, to have an opaque MemorySegment
> filled with MemoryAddress, than having an heap array of MemoryAddress.
>
> P.S.
> Another area which will greatly benefit from Valhalla is jextract: value
> classes will give us a way to "box" a memory segment into an higher
> level abstraction (a struct view) without performance loss. Since
> Jextract bindings are not covered by compatibility guarantees (if you
> want old bindings, just run an old version of jextract), I think we do
> have more freedom in that space.
>
> Maurizio
>
> [1] - https://bugs.openjdk.java.net/browse/JDK-8281387
>
>
> On 02/03/2022 03:55, Glavo wrote:
> > Can someone answer my question?  Many thanks.
> >
> > On Thu, Jan 27, 2022 at 12:50 AM Glavo <zjx001202 at gmail.com> wrote:
> >
> >> I noticed that some Panama features seem to benefit from Valhalla's
> >> features. A notable example is MemoryAddress, which has been marked as
> >> value based and should be able to migrate to value classes in the
> future.
> >>
> >> However, this is not enough to satisfy me. MemoryAddress can be more
> than
> >> just a value class (identity-free reference type), but also a perfect
> >> candidate for the primitive class (JEP 401).
> >> It would be perfect if it could become a primitive class: Eliminates the
> >> possibility that Java's `null` being its value, we just need
> >> `MemoryAddress.NULL`;
> >> Such a small primitive class should almost always be flattened, storing
> it
> >> in a field or array is as simple as a long
> >> (According to the description of JEP draft 8280173, when value class is
> >> stored in arrays and fields, it may not be flattened, and additional
> >> objects still need to be created)...
> >>
> >> However, what worries me is that the current Valhalla prototype does not
> >> seem to provide a way to migrate a class to a primitive class while
> >> maintaining compatibility.
> >> I'm worried that if Panama can't make it a primitive class before ending
> >> the preview, it will become a permanent regret.
> >> I don't know whether the two JDK preview functions can interact with
> each
> >> other, so here I want to ask if it is possible for Panama to have closer
> >> contact with Valhalla when Valhalla starts previewing at the same time?
> >>
>


More information about the panama-dev mailing list