on non-static field layout

Peter B. Kessler Peter.B.Kessler at Oracle.COM
Mon Feb 16 23:46:13 UTC 2015


With respect to your original proposal (http://mail.openjdk.java.net/pipermail/hotspot-dev/2015-February/017141.html): for an "Object[] foo" are you really proposing that foo[0] would be 1 word before the pointer to foo, and that foo[1] would be two words before the pointer to foo, etc.?  That's going to be interesting to explain to debuggers, etc.  One could make an exception for Object[].

With respect to David Holmes's comment about word-tearing on https://bugs.openjdk.java.net/browse/JDK-8024912: if I pass an instance of a subtype of Foo that has packed something into the padding at the end of a Foo instance, but the callee thinks of its argument as a plain Foo, does the callee have to worry about data that is packedinto the padding?

			... peter

On 02/16/15 12:04 AM, Dmytro Sheyko wrote:
> Hello,
>
> The proposed field layouting algorithm is related to following bug reports
> https://bugs.openjdk.java.net/browse/JDK-8024912
> https://bugs.openjdk.java.net/browse/JDK-8024913
>
> Adding explicitly aleksey.shipilev at oracle.com because it seems he
> worked on field layout (when he worked on @Contended).
>
> Thanks,
> Dmytro
>
> --------
>> From: dmytro_sheyko at hotmail.com
>> To: hotspot-dev at openjdk.java.net
>> Subject: on non-static field layout
>> Date: Thu, 12 Feb 2015 17:53:47 +0200
>
> Hello,
>
> I would like to share a couple of thoughts-proposals about non-static
> field layout and get feed back from you.
>
> 1. about reference fields
>
> I can see that reference fields are tried to be laid out together.
> Moreover reference fields of subclass can be appended to the pack of
> reference fields of its superclass, reducing number of oop_map entries
> (especially when -XX:FieldsAllocationStyle=2). However reference
> fields can still be scattered throughout the object and oop_map can
> have more than 1 entry.
>
> What about if reference fields were allocated BEFORE header (with
> negative offset)? In this case they all would form single solid
> cluster. Maybe we wouldn't need oop_map at all, knowing just number of
> reference fields would be enough.
>
> 2. about filling gaps
>
> Current approach of field layout tries to allocate fields densely by
> sorting them by their sizes and placing them from largest
> (long/double) to shortest (byte/boolean). Gap that may appear before
> long/double fields due to alignment is tried to be filled by shorter
> fields of the same class (-XX:+CompactFields). But this approach is
> still not perfect because it does not fill gaps between fields in
> superclasses.
>
> I believe we can allocate fields more densely (i.e. without
> unnecessary gaps in superclasses) with one pass (i.e. without
> sorting). When fields are aligned and packed densely, there can be
> zero or one 1-byte gap, zero or one 2-bytes gap and zero or one
> 4-bytes gap. So we can just keep track of these gaps and use them when
> occasion offers. E.g. when we need to allocate 2-byte field, first we
> try to use 2-bytes gap, otherwise we try to use 4-bytes gap (actually
> only the first half of it, the second half becomes 2-bytes gap),
> otherwise we append field to the end.
>
> Finally the algorithm of nonstatic field layout may look something like below:
>
> int oops_count;    // number of oop fields
> int descent_size;  // 8b aligned size of those part of object that is
> below header (header and primitive fields, but not oop fields)
> int vacant_4b_off; // offset of vacant 4 bytes space (always 4b
> aligned), 0 if there is no such space
> int vacant_2b_off; // offset of vacant 2 bytes space (always 2b
> aligned), 0 if there is no such space
> int vacant_1b_off; // offset of vacant 1 byte  space, 0 if there is no
> such space
>
> // Before laying out nonstatic fields, copy this information (i.e.
> oops_count, descent_size, vacant_?b_off) from super class
> // for java.lang.Object they have following values
> //                 | 32 bit | 64 bit                 | 64 bit                 |
> //                 |        | -XX:+UseCompressedOops | -XX:-UseCompressedOops |
> //   --------------+--------+------------------------+------------------------+
> //   *header size* |      8 |                     12 |                     16 |
> //   oops_count    |      0 |                      0 |                      0 |
> //   descent_size  |      8 |                     16 |                     16 |
> //   vacant_4b_off |      0 |                     12 |                      0 |
> //   vacant_2b_off |      0 |                      0 |                      0 |
> //   vacant_1b_off |      0 |                      0 |                      0 |
>
>
> for (AllFieldStream fs(_fields, _cp); !fs.done(); fs.next()) {
>
>     int real_offset;
>     FieldAllocationType atype = (FieldAllocationType) fs.allocation_type();
>
>     switch (atype) {
>     ...
>     case NONSTATIC_OOP: {
>        // just prepend
>        oops_count += 1;
>        real_offset = -(oops_count * BytesPerHeapOop);
>        break;
>     }
>     case NONSTATIC_DOUBLE: { // 8 bytes: long or double
>        // just append
>        real_offset   = descent_size;
>        descent_size += BytesPerLong;
>        break;
>     }
>     case NONSTATIC_WORD: { // 4 bytes: int or float
>        if (vacant_4b_off != 0) {
>           // use vacant 4b space if possible
>           real_offset   = vacant_4b_off;
>           vacant_4b_off = 0;
>        } else {
>           // otherwise append...
>           real_offset   = descent_size;
>           // ... and the second half of appended 8 bytes becomes vacant 4b space
>           vacant_4b_off = descent_size + BytesPerInt;
>           descent_size += BytesPerLong;
>        }
>        break;
>     }
>     case NONSTATIC_SHORT: { // 2 bytes: short or char
>        if (vacant_2b_off != 0) {
>           // use vacant 2b space if possible...
>           real_offset   = vacant_2b_off;
>           vacant_2b_off = 0;
>        } else if (vacant_4b_off != 0) {
>           // then try to use the first half of vacant 4b space...
>           real_offset   = vacant_4b_off;
>           // ... and the second half becomes vacant 2b space
>           vacant_2b_off = vacant_4b_off + BytesPerShort
>           vacant_4b_off = 0;
>        } else {
>           // otherwise append
>           real_offset   = descent_size;
>           // the rest becomes vacant
>           vacant_2b_off = descent_size + BytesPerShort;
>           vacant_4b_off = descent_size + BytesPerInt;
>           descent_size += BytesPerLong;
>        }
>        break;
>     }
>     case NONSTATIC_BYTE: { // 1 byte: byte or boolean
>        if (vacant_1b_off != 0) {
>           real_offset   = vacant_1b_off;
>           vacant_1b_off = 0;
>        } else if (vacant_2b_off != 0) {
>           real_offset   = vacant_2b_off;
>           vacant_1b_off = vacant_2b_off + 1
>           vacant_2b_off = 0;
>        } else if (vacant_4b_off != 0) {
>           real_offset   = vacant_4b_off;
>           vacant_1b_off = vacant_4b_off + 1
>           vacant_2b_off = vacant_4b_off + BytesPerShort
>           vacant_4b_off = 0;
>        } else {
>           real_offset   = descent_size;
>           vacant_1b_off = descent_size + 1;
>           vacant_2b_off = descent_size + BytesPerShort;
>           vacant_4b_off = descent_size + BytesPerInt;
>           descent_size += BytesPerLong;
>        }
>        break;
>     }
>     fs.set_offset(real_offset);
> }
>
> // ascent_size: 8b aligned size of those part of object that is above header
> int ascent_size = align_size_up(oops_count * BytesPerHeapOop, BytesPerLong);
>
> // when class instance is allocated, the pointer to allocated space is
> to be advanced by ascent_size to get pointer to object
> //
> // pointer to allocated space--> [ ref field m  ] <-+
> //                               ...                | -- ascent size
> //                               [ ref field 1  ] <-+
> // pointer to object ----------> [ header       ] <-+
> //                               [ prim field 1 ]   |
> //                               [ prim field 2 ]   + -- descent size
> //                               ...                |
> //                               [ prim field n ] <-+
>
> int total_size = accent_size + descent_size;
>
> Regards,
> Dmytro
>


More information about the hotspot-runtime-dev mailing list