[master] RFR: Implement self-forwarding of objects that preserves header bits
John R Rose
jrose at openjdk.java.net
Tue Jun 29 18:45:52 UTC 2021
On Mon, 28 Jun 2021 13:49:09 GMT, Roman Kennke <rkennke at openjdk.org> wrote:
> In a few places in GCs we self-forward objects to indicate promotion failures. This is problematic with Lilliput because it irreversably overrides header bits.
>
> I propose to address this problem by using the recently-free'd biased-locking bit to indicate self-forwarding, without actually writing the ptr-to-self in the header.
>
> A few notes:
> - The code in g1FullGCCompactionPoint.cpp keeps degenerating into ugly mess. This certainly warrants some rewriting.
> - We have some naked header-decodings, which get tidied-up. This could also be brought upstream.
> - cas_forward_to() kinda duplicates forward_to_atomic(), and has been replaced by the new forward_to_self_atomic(). It could be unduplicated upstream, too.
>
> An alternative *may be* to preserve the header of self-forwarded objects in a side-table (like PreservedMarksStack) instead. This may be possible but hairy: we could not access the compressed-klass* in the upper bits until the header gets restored. (This also affects calls to size(), etc).
>
> The ex-biased-locking-bit may still be used in regular operation. It only acts as self-forwarding-indicator when the lower two bits are also set. It requires the usual marks-preservation if we do this.
>
> We might want to have a discussion which project would need header bits, and how to realistically allocate them. #4522 mentions Valhalla as possible taker of the BL header bit. We may be able to free one or two bits when we compress the klass* even more. For example, we currently use 25 bits for i-hash, and 32 bits for nklass*. We usually want 32bits for i-hash instead. This would leave 25bits for nklass, which can address 268MB of Klass*-space (usual compression scheme), or 32million classes (table-lookup), or something in-between if we use fixed-size Klass (seems unrealistic though). Taking away another bit mean halving the addressable space.
>
> (It would be kinda-nice to have the BL-bit for Shenandoah, too, and for a similar purpose: indicate evacuation failure. But we do have a working solution, however that is ugly and affects performance a little.)
The Valhalla project has a strong requirement for very fast detection of references to primitive objects (the term was previously inline objects), because the behavior of the very frequent `acmp` operation differs between references to primitives and to regular identity objects. After much experiment, the prototype has settled on testing the biased-lock bit in the mark word to see if the reference points to a primitive object instead of a regular one. An extra indirection through the `klass` pointer would be too slow.
Valhalla defines three additional object header bits, for more limited purposes. (H/T to Fred Parain for reminding me of these.) For primitive objects only, there is a "larval" state which sometimes needs to be marked, on an unpublished object which is under construction. This bit is related to the "always locked" bit; it is a stronger condition. It seems likely to me that whatever provision there is for short-circuiting attempted lock operations on primitive objects will easily expand to another provision for marking larval objects, by using related state bits in the header (assuming header locking consumes more than one bit).
For arrays, there are two bits which accelerate slow paths relating to arrays whose elements are restricted to primitive classes (aka inline objects). The two bits encode whether (a) the array elements are stored as null-free references (internally boxed primitives) or (b) the array elements are stored flat as inline primitive objects (the preferred case). These bits accelerate array access operations. They are present only on 64-bit VMs; when bits are scarce they are loaded via the `klass` pointer. This would seem to be a reasonable tactic for Lilliput also, if bits are scarce. Another tactic for Lilliput might be to pack such array-specific flags into an extra field just for arrays, adjacent to the `length` field.
The relevant declarations are in `markOop.hpp`:
https://github.com/openjdk/valhalla/blob/b62a66e379fda00a5ba4622da7661c89b380ecdf/src/hotspot/share/oops/markWord.hpp#L97
-------------
PR: https://git.openjdk.java.net/lilliput/pull/10
More information about the lilliput-dev
mailing list