RFR: 8277434: tests fail with "assert(is_forwarded()) failed: only decode when actually forwarded"

Kim Barrett kim.barrett at oracle.com
Mon Nov 29 09:10:21 UTC 2021

> On Nov 29, 2021, at 3:35 AM, Thomas Schatzl <tschatzl at openjdk.java.net> wrote:
> On Mon, 29 Nov 2021 08:07:34 GMT, Aleksey Shipilev <shade at openjdk.org> wrote:
>> Ooof, so a relaxed forwardee installation comes with an odd invariant like this. I linked JDK-8204524 to this issue, to track where the forwardee installation was relaxed.
>> The fix for this particular issue looks fine to me, thanks.
>> A few follow-up questions about the general issue here. How is it not affecting the other places where G1 accesses `obj->forwardee()`, like in `G1ScanClosureBase::prefetch_and_push` or `G1ParScanThreadState::do_partial_array`? Also, it is not theoretically clear how would "All uses of a forwardee must take care to avoid reading from it without performing additional synchronization", given that the trouble had already happened on writer side, and there is little a reader can do to recover?
> Both cases examine the original object in the collection set only; for the first example there is an explicit check on `is_in_cset` before the call (`G1ScanEvacuatedObjClosure::do_oop_work` is also only ever called from the thread that copied the object too; but all `G1ScanClosureBase::prefetch_and_push` are guarded by an `is_in_cset` check). `from_obj` in `G1ParScanThreadState::do_partial_array` is always in the collection set, i.e.
>    assert(_g1h->is_in_reserved(from_obj), "must be in heap.");
> could be rephrased as `g1h->is_in_cset(from_obj)`.

The key point in the G1ScanEvacuatedObjClosure::do_oop_work case is that the
thread that copied the object is the thread doing the prefetch_and_push.  It's
buried in the obj->oop_iterate_backwards call in do_copy_to_survivor_space.

For do_partial_array, while the from_obj is in the collection set, its
forwardee is not, and might also not be up to date if not for the additional
synchronization provided by being distributed through the taskqueue.
start_partial_objarray pushes tasks onto the taskqueue, which involves a
release-store. And the thread that obtains the task does a pop-local or
pop-global from the taskqueue, which involves acquire or fence. So the
contents of the forwardee in the object in the partial-array task are
up-to-date when processing the task. That's an example of "additional
synchronization" I was referring to.

> -------------
> PR: https://git.openjdk.java.net/jdk/pull/6582

More information about the hotspot-gc-dev mailing list