Oredering of fields in inline types and records

John Rose john.r.rose at oracle.com
Fri Mar 6 20:24:51 UTC 2020

On Mar 6, 2020, at 8:53 AM, Stephen Colebourne <scolebourne at joda.org> wrote:
> Does the JVM still have this flexibility with records?
> Will the JVM still have this flexibility with inline types?

Yes, as others have said.  I might as well explain the larger
principle, that the JVM controls these things, FTR.

The JVM uses this flexibility to sort fields by kind, where
“kinds” are primitive-of-some-size-N (N in {1,2,4,8}), plus
reference as a distinct kind.  And now “value struct”.

The differing alignments of different primitive kinds means
there's an easy win in compactness from putting all the bytes
in one place, rather than (say) alternating bytes and longs,
with 7 bits of padding for each byte.  Doing this for values
requires compromises since value structs come in many
kinds, but we can roughly classify them by size and alignment,
just like C structs.

The GC makes use of the fact that references tend to be grouped
in object layouts, rather than scattered at random.  There’s even
some logic to try to put the references from a subclass and a
superclass next to each other (deeper hierarchies defeat this).
The result is that the GC can use a few fast loops through
a contiguous array, rather than some bitmask-driven traversal,
for typical objects.

Note also that new vector types (when the Vector API starts
to use inline classes) might (or not) be given their own “kinds”
under the covers, extending the pattern of byte/short/int/long
to larger sizes.  (Yes, double and char and boolean and float lose
their separate status.)

For inline fields, the JVM even reserves the right (in theory) to
break up a value and merge its fields into the kind-based sort of
the containing object, although this would complicate various
parts of the JVM, including the Unsafe API which supports peek
and poke of value instances.

It is an interesting thought exercise to apply such value field
merging to groups of array elements as well, with the goal of
avoiding cache line crossing (on platforms where that matters).
My point there is that each cache line could be filled with as
many values as possible, and then padded out to the next cache
line.  The array indexing arithmetic is more complicated but not
terrible, and affine loops are easy as long as they are unrolled
by the right amount.

So, yes, the JVM asserts sole authority over the layouts of the
data in the managed heap.  For primitive data, you can use
Panama APIs (or the equivalent) to overlay C-style structs on
Java arrays.  For structs with managed pointers, there is no
way, currently, to direct the JVM what to do in detail.  If
we ever do what I’ve called “non-periodic arrays”, then
we will need more flexibility in the location of managed
pointers, and at that point (if we get there) it will be
natural to consider APIs by which the user can direct
the JVM about the placement of managed pointers in
a larger object.  Loom is starting to knock on this door
today, since they have a natural need to store stack frames
in the heap, and a stack frame is (if you look at it the
right way) a non-periodic array.

FTR, a non-periodic array is “worse” than a merely
heterogeneous array, because its elements might be of
differing sizes.  You parse them stream-wise, or if you
need to address them with dead-reckoning, you get
extra help.

— John

More information about the valhalla-dev mailing list