RFR: 8371716: C2: Phi node fails Value()'s verification when speculative types clash [v4]

Marc Chevalier mchevalier at openjdk.org
Thu Nov 27 10:12:51 UTC 2025


On Thu, 27 Nov 2025 09:46:23 GMT, Marc Chevalier <mchevalier at openjdk.org> wrote:

>> This bug was originally found and reported as a Valhalla problem. It quickly became apparent it has no reason to be Valhalla-specific, while I couldn't prove so. Roland managed to make a mainline reproducer. The explanation details my Valhalla investigation, but it has nothing to do with value classes anyway.
>> 
>> The proposed solution seems somewhat controversial. See https://github.com/openjdk/valhalla/pull/1717 for some previous discussion. Before polishing the PR, I'd like to reach an agreement on the way to go.
>> 
>> # Analysis
>> ## Obervationally
>> ### IGVN
>> During IGVN, in `PhiNode::Value`, a `PhiNode` has 2 inputs. Their types are:
>> 
>> in(1): java/lang/Object * (speculative=TestSpeculativeTypes$C2:NotNull:exact * (inline_depth=3))
>> in(2): null
>> 
>> We compute the join (HS' meet):
>> https://github.com/openjdk/jdk/blob/09b25cd0a24a4eaddce49917d958adc667ab5465/src/hotspot/share/opto/cfgnode.cpp#L1299-L1306
>> 
>> t=java/lang/Object * (speculative=compiler/igvn/ClashingSpeculativeTypePhiNode$C2:exact *)
>> 
>> But the current `_type` (of the `PhiNode` as a `TypeNode`) is
>> 
>> _type=java/lang/Object * (speculative=compiler/igvn/ClashingSpeculativeTypePhiNode$C1:exact *)
>> 
>> We filter `t` by `_type`
>> https://github.com/openjdk/jdk/blob/09b25cd0a24a4eaddce49917d958adc667ab5465/src/hotspot/share/opto/cfgnode.cpp#L1321
>> and we get
>> 
>> ft=java/lang/Object *
>> 
>> which is what we return. After the end of `Value`, the returned becomes the new `PhiNode`'s `_type`.
>> https://github.com/openjdk/jdk/blob/09b25cd0a24a4eaddce49917d958adc667ab5465/src/hotspot/share/opto/phaseX.cpp#L2150-L2164
>> and
>> https://github.com/openjdk/jdk/blob/09b25cd0a24a4eaddce49917d958adc667ab5465/src/hotspot/share/opto/node.cpp#L1117-L1123
>> 
>> 
>> ### Verification
>> On verification, `in(1)`, `in(2)` have the same value, so does `t`. But this time
>> 
>> _type=java/lang/Object *
>> 
>> and so after filtering `t` by (new) `_type` and we get
>> 
>> ft=java/lang/Object * (speculative=compiler/igvn/ClashingSpeculativeTypePhiNode$C2:exact *)
>> 
>> which is retuned. Verification gets angry because the new `ft` is not the same as the previous one.
>> 
>> ## But why?!
>> ### Details on type computation
>> In short, we are doing
>> 
>> t = typeof(in(1)) / typeof(in(2))
>> ft  = t /\ _type (* IGVN *)
>> ft' = t /\ ft    (* Verification *)
>> 
>> and observing that `ft != ft'`. It seems our lattice doesn't ensure `(a /\ b) /\ b = a /\ b` which is problematic for this kind of verfication that will just "try again...
>
> Marc Chevalier has updated the pull request with a new target base due to a merge or a rebase. The incremental webrev excludes the unrelated changes brought in by the merge/rebase. The pull request contains six additional commits since the last revision:
> 
>  - test
>  - Merge branch 'master' into JDK-8371716
>  - More test
>  - IgnoreUnrecognizedVMOptions
>  - Fix bug number
>  - Filter twice

I think it would be reasonable to move forward with the current solution, at the moment. It would resolve some existing failures in Valhalla (so it would be nice if it's in soon), it is on the safe side, without putting too much effort in a case that seems quite rare, or in improvements with unclear benefits.

Yet, I agree that is not fundamentally very satisfying, but this fix doesn't prevent (or make harder) a possible future broader revisit of speculative types.

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

PR Comment: https://git.openjdk.org/jdk/pull/28331#issuecomment-3585068039


More information about the hotspot-compiler-dev mailing list