RFR: 8346280: C2: implement late barrier elision for G1

Roberto Castañeda Lozano rcastanedalo at openjdk.org
Wed Jan 22 15:30:35 UTC 2025


G1 barriers can be safely elided from writes to newly allocated objects as long as no safepoint is taken between the allocation and the write. This changeset complements early G1 barrier elision (performed by the platform-independent phases of C2, and limited to writes immediately following allocations) with a more general elision pass done at a late stage.

The late elision pass exploits that it runs at a stage where the relative order of memory accesses and safepoints cannot change anymore to elide barriers from initialization writes that do not immediately follow the corresponding allocation, e.g. in conditional initialization writes:


o = new MyObject();
if (...) {
    o.myField = ...;  // barrier elided only after this changeset
                      // (assuming no safepoint in the if condition)
}


or in initialization writes placed after exception-throwing checks:


o = new MyObject();
if (...) {
    throw new Exception("");
}
o.myField = ...;  // barrier elided only after this changeset
                  // (assuming no safepoint in the above if condition)


These patterns are commonly found in Java code, e.g. in the core libraries:

- [conditional initialization](https://github.com/openjdk/jdk/blob/25fecaaf87400af535c242fe50296f1f89ceeb16/src/java.base/share/classes/java/lang/String.java#L4850), or

- [initialization after exception-throwing checks (in the superclass constructor)](https://github.com/openjdk/jdk/blob/master/src/java.base/share/classes/java/nio/X-Buffer.java.template#L324).

The optimization also enhances barrier elision for array initialization writes, for example eliding barriers from small array initialization loops (for which safepoints are not inserted):


Object[] a = new Object[...];
for (int i = 0; i < a.length; i++) {
    a[i] = ...;  // barrier elided only after this changeset
}


or eliding barriers from array initialization writes with unknown array index:


Object[] a = new Object[...];
a[index] = ...;  // barrier elided only after this changeset


The logic used to perform this additional barrier elision is a subset of a pre-existing ZGC-specific optimization. This changeset simply reuses the relevant subset (barrier elision for writes to newly-allocated objects) by extracting the core of the optimization logic from `zBarrierSetC2.cpp` into the GC-shared file `barrierSetC2.cpp`. The functions `block_has_safepoint`, `block_index`, `look_through_node`, `is_{undefined|unknown|concrete}`, `get_base_and_offset`, `is_array_allocation`, and `is_allocation` are simply moved from one file to the other. The function `analyze_dominating_barriers_impl` is moved and renamed to `elide_dominated_barriers` for clarity.

#### Testing

##### Functionality

- tier1-5, stress testing (linux-x64, windows-x64, macosx-x64, linux-aarch64, macosx-aarch64; release and debug mode).

##### Performance

- Tested performance on a set of standard benchmark suites (DaCapo, Renaissance, SPECjbb2015, SPECjvm2008). No significant change was observed, besides a slight positive overall trend for Renaissance.

- Profiled dynamic count of writes with barriers elided by this changeset using DaCapo on linux-x64. Late elision manages to elide around 15% of all executed barriers for the `jython` and `kafka` benchmarks, almost 10% for `xalan`, and less than 5% for the remaining benchmarks.

- Measured execution overhead of late elision using DaCapo on linux-x64. The new optimization takes, on average, less than 0.2% of the total C2 execution time.

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

Commit messages:
 - Add new test case (store after exception)
 - Remove unused includes
 - Remove temporary UseNewCode guard
 - Use clearer names and document access API interface
 - Move ZGC-specific barrier elision code to BarrierSetC2
 - Set UseNewCode to true temporarily
 - Make elide_mach_barrier virtual
 - Move late barrier elision analysis from G1BarrierSetC2 to BarrierSetC2
 - Initial implementation
 - Add more G1 barrier elision tests, expect G1-specific memory accesses with no barrier data as an alternative to generic memory accesses

Changes: https://git.openjdk.org/jdk/pull/23235/files
  Webrev: https://webrevs.openjdk.org/?repo=jdk&pr=23235&range=00
  Issue: https://bugs.openjdk.org/browse/JDK-8346280
  Stats: 773 lines in 9 files changed: 492 ins; 262 del; 19 mod
  Patch: https://git.openjdk.org/jdk/pull/23235.diff
  Fetch: git fetch https://git.openjdk.org/jdk.git pull/23235/head:pull/23235

PR: https://git.openjdk.org/jdk/pull/23235


More information about the hotspot-gc-dev mailing list