RFR: 8275610: C2: Object field load floats above its null check resulting in a segfault

Christian Hagedorn chagedorn at openjdk.java.net
Fri Dec 3 14:09:31 UTC 2021


In the test case, a field load of an object floats above the object null check due to a `CastPP` that gets separated from its null check `If` node. C2 then schedules the field load before the object null check which results in a segfault.

The problem can be traced back to the elimination of identical back-to-back ifs [(JDK-8143542)](https://bugs.openjdk.java.net/browse/JDK-8143542). This is done in split-if where we detect identical back-to-back ifs in `PhaseIdealLoop::identical_backtoback_ifs()`. We then replace the boolean node of the dominated `If` by a phi to use the split-if optimization to nicely fold away the dominated `If` later in IGVN. This, however, does not update any data nodes that were dependent on the dominated `If` projections. 

In the test case, we have the following graph right before splitting `313 If` (`NC 2`) through `190 Region`:

![Screenshot from 2021-12-03 14-08-31](https://user-images.githubusercontent.com/17833009/144608863-a1185bf8-dfa3-4bd5-a0c2-284ea2b27606.png)
`313 If` is dominated by the identical (= both share `308 Bool`) `309 If` (`NC 1`). The bool input for `313 If` is replaced by a phi and the split-if optimization is applied. However, the data nodes dependent on the out projections of the dominated `313 If` (`261 CastPP` in this case) are not processed separately and just end up at the newly inserted regions in split-if. In the test case, we get the following graph where `261 CastPP` ends up at the new `334 Region`:

![Screenshot from 2021-12-03 14-08-59](https://user-images.githubusercontent.com/17833009/144608891-48adf7a3-9b04-4e6d-bc26-310757b3d596.png)
Loopopts are applied and can remove the `325 CountedLoop` and we find that the `171 RangeCheck` (`RC 2`) is applied on a constant array index 1.

Now at IGVN, the order in which the nodes are processed is important in order to trigger the segfault:
1. `334 Region` with `332 If` and `333 If` are removed because of the special split-if setup we used to remove the identical `313 If`. The control input of `261 CastPP` is therefore updated to `172 IfTrue`.
2. Applying `RangeCheck::Ideal()` for `171 RangeCheck` finds that `305 RangeCheck` (`RC 1`) already covers it and we remove `171 RangeCheck`. In this process, we rewire `261 CastPP` to the dominating `305 RangeCheck` and we have the following graph:

![Screenshot from 2021-12-03 14-09-21](https://user-images.githubusercontent.com/17833009/144608917-f5159b21-40b2-41c8-afab-fa495433217a.png)
`261 CastPP` - and also the field `263 LoadI` - have now `306 IfFalse` as early control. GCM is then scheduling `263 LoadI` before the null check `309 If` and we get a segfault.

An easy fix is not straight forward. What we actually would want to do is rewiring `261 CastPP` from `334 Region` to `311 IfTrue` in the second graph after split-if to not separate it from the null check. But that's not possible because we would create a bad graph: The early control `311 IfTrue` of `261 CastPP` does not dominate its late control further down after `334 Region` because of the not yet removed `334 Region`. We would need to already clean the regions up and then do the rewiring. But then the question arises why to use the split-if optimization in the first place when we do not want to rely on IGVN to clean it up.

I therefore suggest to go with an easy bailout fix for JDK 18 where we do not apply this identical back-to-back if removal optimization if there are data dependencies and rework this in an RFE for JDK 19. Roland already has some ideas how to do that.

I ran some standard benchmarks and did not see any performance regressions with this fix.

Thanks,
Christian

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

Commit messages:
 - 8275610: C2: Object field load floats above its null check resulting in a segfault

Changes: https://git.openjdk.java.net/jdk/pull/6701/files
 Webrev: https://webrevs.openjdk.java.net/?repo=jdk&pr=6701&range=00
  Issue: https://bugs.openjdk.java.net/browse/JDK-8275610
  Stats: 112 lines in 2 files changed: 112 ins; 0 del; 0 mod
  Patch: https://git.openjdk.java.net/jdk/pull/6701.diff
  Fetch: git fetch https://git.openjdk.java.net/jdk pull/6701/head:pull/6701

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


More information about the hotspot-compiler-dev mailing list