8202377: Modularize C2 GC barriers

Erik Österlund erik.osterlund at oracle.com
Wed May 9 14:32:22 UTC 2018


I have rebased ZGC on top of these changes. In the process, I found a 
few more hooks that will be needed for ZGC. I added them, so here is an 
incremental update:

Full webrev:

Each new hook is a no-op for existing GCs. I am merely adding them to 
pave way for ZGC.
Also made a few members public that need to be accessible by the ZGC 
barrier set backend.

Nils has helped me look at this all day. So big thanks to Nils for 
taking the time to look at these changes.


On 2018-05-01 15:32, Erik Österlund wrote:
> Hi,
> The GC barriers for C2 are not as modular as they could be. It 
> currently uses switch statements to check which GC barrier set is 
> being used, and call one or another barrier based on that, in a way 
> that it can only be used for write barriers.
> My proposed solution is to follow the same pattern that has been used 
> by C1 (and the rest of HotSpot), which is to provide a GC barrier set 
> code generation helper for C2. Its name is BarrierSetC2. Each barrier 
> set class has its own BarrierSetC2, following a mirrored inheritance 
> hierarchy to the BarrierSet hierarchy. You generate the accesses using 
> some access_* member functions on GraphKit, which calls into 
> BarrierSetC2.
> A lot of the design looks very similar to BarrierSetC1. In C1, there 
> was a wrapper object called LIRAccess that wrapped a bunch of context 
> parameters that were passed around in the barrier set hierarchy. There 
> is a similar wrapper for C2 that I call C2Access. Users of the API do 
> not see it. They call, e.g. access_load_at, in GraphKit during 
> parsing. The access functions wrap the access in a C2Access object 
> with a bunch of context parameters, and calls the currently selected 
> BarrierSetC2 backend accessor with this context. For the atomic 
> accesses, there is a C2AtomicAccess, inheriting from C2Access. It 
> contains more context, as required by the atomic accesses (e.g. 
> explicit alias_idx, whether the node needs pinning with an SCM 
> projection, and a memory node).
> Apart from the normal shared decorators, C2 does use its own 
> additional decorators for its own use:
> * C2_MISMATCHED and C2_UNALIGNED (describing properties of unsafe 
> accesses)
> * C2_WEAK_CMPXCHG: describing if a cmpxchg may have false negatives
> * C2_CONTROL_DEPENDENT_LOAD: use when a load should have control 
> dependency
> * C2_PINNED_LOAD: use for loads that must be pinned
> * C2_UNSAFE_ACCESS: Used to recognize this is an unsafe access. This 
> decorator implies that loads have control dependency and need pinning, 
> unless it can be proven that the access will be inside the bounds of 
> an object.
> * C2_READ_ACCESS and C2_WRITE_ACCESS: This denotes whether the access 
> reads or writes to memory. Or both for atomics. It is useful for for 
> figuring out what fencing is required for a given access and ordering 
> semantics, as well as being useful for Shenandoah to figure out what 
> type of barrier to use to ensure memory consistency.
> The accesses go through a similar process as they do in C1. Let's take 
> BarrierSetC2::store_at for example. It uses the the C2AccessFence 
> scoped object helper to figure out what membars are required to 
> surround the access, resolve the address (no-op for all GCs with a 
> to-space invariant, which is all GCs except Shenandoah in HotSpot at 
> the moment), and then calls store_at_resolved. The store_at_resolved 
> member function generates the access and the barriers around it. The 
> abstract ModRefBarrierSetC2 barrier set introduces the notion of 
> pre/post write barriers, and lets concrete barrier sets do sprinkle 
> their GC barriers in there. It calls BarrierSetC2::store_at_resolved 
> to generate the actual access. For example CardTableBarrierSet only 
> needs to override its post barrier for this to work as expected. The 
> other accesses follow a similar pattern.
> The Compile class now has a type erase (void*) per compilation unit 
> state that is created for each compilation unit (with 
> BarrierSetC2::create_barrier_state). For the GCs in HotSpot today, 
> this is always NULL. But for GCs that have their own macro nodes, the 
> compilation unit can be used for, e.g. lists of barrier-specific macro 
> nodes, that should not pollute the Compile object. Such macro nodes 
> can be expanded during macro expansion using the 
> BarrierSetC2::expand_macro_nodes member function.
> There are a few other helpers that may be good for a GC to have, like 
> figuring out if a node is a GC barrier (for escape analysis), whether 
> a GC barrier can be eliminated (for example using 
> ReduceInitialCardMarks), whether array_copy requires GC barriers, how 
> to step over a GC barrier. There is also a helper for loop optimizing 
> GC barrier nodes.
> This work will help to pave way for a new class of collectors 
> utilizing load barriers (ZGC and Shenandoah) for concurrent compaction.
> Webrev:
> http://cr.openjdk.java.net/~eosterlund/8202377/webrev.00/
> Bug:
> https://bugs.openjdk.java.net/browse/JDK-8202377
> Thanks,
> /Erik

More information about the hotspot-compiler-dev mailing list