A case where G1/Shenandoah satb barrier is not optimized?
Roberto Castaneda Lozano
roberto.castaneda.lozano at oracle.com
Tue Mar 5 10:19:40 UTC 2024
Hi Yude Yin (including hotspot-compiler-dev mailing list),
>From what I read in the original JBS issue [1], the g1_can_remove_pre_barrier/g1_can_remove_post_barrier optimization targets writes within simple constructors (such as that of Node within java.util.HashMap [2]), and seems to assume that the situation you describe (several writes to the same field) is either uncommon within this scope or can be reduced by the compiler into a form that is optimizable. In your example, one would hope that the compiler proves that 'ref = a' is redundant and optimizes it away (which would lead to removing all barriers), but this optimization is inhibited by the barrier operations inserted by the compiler in its intermediate representation. These limitations will become easier to overcome with the "Late G1 Barrier Expansion" JEP (in draft status), which proposes hiding barrier code from the compiler's transformations and optimizations [3]. In fact, our current "Late G1 Barrier Expansion" prototype does optimize 'ref = a' away, and removes all barriers in your example.
Cheers,
Roberto
[1] https://bugs.openjdk.org/browse/JDK-8057737
[2] https://github.com/openjdk/jdk/blob/e9adcebaf242843fe2004b01747b5a930b62b291/src/java.base/share/classes/java/util/HashMap.java#L287-L292
[3] https://bugs.openjdk.org/browse/JDK-8322295
________________________________________
From: hotspot-gc-dev <hotspot-gc-dev-retn at openjdk.org> on behalf of Yude Lin <yude.lyd at alibaba-inc.com>
Sent: Monday, March 4, 2024 11:32 AM
To: hotspot-gc-dev
Subject: A case where G1/Shenandoah satb barrier is not optimized?
Hi Dear GC devs,
I found a case where GC barriers cannot be optimized out. I wonder if anyone could enlighten me on this code:
> G1BarrierSetC2::g1_can_remove_pre_barrier (or ShenandoahBarrierSetC2::satb_can_remove_pre_barrier)
where there is a condition:
> (captured_store == nullptr || captured_store == st_init->zero_memory())
on the store that can be optimized out. The comment says:
> The compiler needs to determine that the object in which a field is about
> to be written is newly allocated, and that no prior store to the same field
> has happened since the allocation.
But my understanding is satb barriers of any number of stores immediately (i.e., no in-between safepoints) after an allocation can be optimized out, same field or not.
The "no prior store" condition confuses me.
What's more, failing to optimize one satb barrier will prevent further barrier optimization that otherwise would be done (maybe due to control flow complexity from the satb barrier).
An example would be:
public static class TwoFieldObject {
public Object ref;
public Object ref2;
public TwoFieldObject(Object a) {
ref = a;
}
}
public static Object testWrite(Object a, Object b, Object c) {
TwoFieldObject tfo = new TwoFieldObject(a);
tfo.ref = b; // satb barrier of this store cannot be optimized out, and because of its existence, post barrier will also not be optimized out
tfo.ref2 = c; // because of the previous store's barriers, pre/post barriers of this store will not be optimized out
return tfo;
}
More information about the hotspot-compiler-dev
mailing list