Interaction between Panama and Valhalla
Maurizio Cimadamore
maurizio.cimadamore at oracle.com
Wed Mar 2 11:08:34 UTC 2022
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