RFR: 8261492: Shenandoah: reconsider forwardee accesses memory ordering

Aleksey Shipilev shade at openjdk.java.net
Thu Feb 11 13:43:40 UTC 2021


On Thu, 11 Feb 2021 13:32:00 GMT, Zhengyu Gu <zgu at openjdk.org> wrote:

>> Shenandoah carries forwardee information in object's mark word. Installing the new mark word is effectively "releasing" the object copy, and reading from the new mark word is "acquiring" that object copy.
>> 
>> For the forwardee update side, Hotspot's default for atomic operations is memory_order_conservative, which emits two-way memory fences around the CASes at least on AArch64 and PPC64. This seems to be excessive for Shenandoah forwardee updates, and "release" is enough.
>> 
>> For the forwardee load side, we need to guarantee "acquire". We do not do it now, reading the markword without memory semantics. It does not seem to pose a practical problem today, because GC does not access the object contents in the new copy, and mutators get this from the JRT-called stub that separates the fwdptr access and object contents access by a lot. It still should be cleaner to "acquire" the mark on load to avoid surprises.
>> 
>> Additional testing:
>>  - [x] Linux x86_64 `hotspot_gc_shenandoah`
>>  - [x] Linux AArch64 `hotspot_gc_shenandoah`
>>  - [x] Linux AArch64 `tier1` with Shenandoah
>
> src/hotspot/share/gc/shenandoah/shenandoahForwarding.inline.hpp line 43:
> 
>> 41:   // fwdptr. That object is still not forwarded, and we need to return
>> 42:   // the object itself.
>> 43:   markWord mark = obj->mark_acquire();
> 
> We also need the acquire barrier in fast path in generated code, right?

Dang. I thought the beauty of self-fixing barriers is that we moved all fwdptr accesses to C++ (either GC or LRB), and all of them end up in this file. But there is `ShenandoahBarrierSetAssembler::cmpxchg_oop` that accesses the fwdptr directly. I shall see what can be done there.

> src/hotspot/share/gc/shenandoah/shenandoahForwarding.inline.hpp line 89:
> 
>> 87:   // (would be paired with acquire in forwardee accessors). Acquire on failed update
>> 88:   // would get the updated object after the forwardee load.
>> 89:   markWord prev_mark = obj->cas_set_mark(new_mark, old_mark, memory_order_acq_rel);
> 
> You have obj->mark_acquire() above, I don't think you need leading acquire here.

A bit different: we want to acquire `prev_mark` (failure witness) here, if we lose the update race. So the `old_mark` acquire does not really help us.

-------------

PR: https://git.openjdk.java.net/jdk/pull/2496


More information about the shenandoah-dev mailing list