On Tue, 4 Nov 2025 14:02:10 GMT, Marc Chevalier <[email protected]> wrote:
> # Analysis > ## Obervationally > ### IGVN > During IGVN, in `PhiNode::Value`, a `PhiNode` has 2 inputs. Their types are: > > in(1): java/lang/Object * (speculative=compiler/valhalla/inlinetypes/MyValue2 > (compiler/valhalla/inlinetypes/MyInterface):exact * (inline_depth=4)) > in(2): java/lang/Object * (speculative=null) > > We compute the join (HS' meet): > https://github.com/openjdk/valhalla/blob/412ec882767d3ee1792d1e0f98da54ff800c60ce/src/hotspot/share/opto/cfgnode.cpp#L1310-L1317 > > t=java/lang/Object * (speculative=compiler/valhalla/inlinetypes/MyValue2 > (compiler/valhalla/inlinetypes/MyInterface):exact *) > > But the current `_type` (of the `PhiNode` as a `TypeNode`) is > > _type=java/lang/Object * (speculative=compiler/valhalla/inlinetypes/MyValue3 > (compiler/valhalla/inlinetypes/MyInterface):exact *) > > We filter `t` by `_type` > https://github.com/openjdk/valhalla/blob/412ec882767d3ee1792d1e0f98da54ff800c60ce/src/hotspot/share/opto/cfgnode.cpp#L1332 > 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/valhalla/blob/412ec882767d3ee1792d1e0f98da54ff800c60ce/src/hotspot/share/opto/phaseX.cpp#L2150-L2164 > and > https://github.com/openjdk/valhalla/blob/412ec882767d3ee1792d1e0f98da54ff800c60ce/src/hotspot/share/opto/node.cpp#L1127-L1133 > > > ### 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/valhalla/inlinetypes/MyValue2 > (compiler/valhalla/inlinetypes/MyInterface):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 and see if something change". > > To me, the surprising fact was that the intersection > > java/lang/Object * (speculative=compiler/valhalla/inlinetypes/MyValue2 > (compiler/valhalla/inlinetypes/MyInterface):exact *) > /\ > _type=java/lang/Object * (speculative=compiler/valhalla/inlinetypes/MyValue3 > (compiler/valhalla/inlinetypes/MyInterface):exact *) > ~> > java/lang/Object * > > What happened to the speculative type? Both `MyVal... I don't think this is quite correct. At first, we have in(1): java/lang/Object * (speculative=compiler/valhalla/inlinetypes/MyValue3 [...] in(2): java/lang/Object * (speculative=null) which make `_type` to be java/lang/Object * (speculative=compiler/valhalla/inlinetypes/MyValue3 (compiler/valhalla/inlinetypes/MyInterface):exact *) (which I'm not arguing with: it seems correct at that point). Then, some incremental inlining happen, the types of inputs change to in(1): java/lang/Object * (speculative=compiler/valhalla/inlinetypes/MyValue2 (compiler/valhalla/inlinetypes/MyInterface):exact * (inline_depth=4)) in(2): java/lang/Object * (speculative=null) (`MyValue3` is replaced by `MyValue2` in the type of `in(1)`) and from this point, we run `PhiNode::Value` (since indeed, the input changed) with the previously computed `_type` involving `MyValue3`. In this invocation of `Value` (the last non-verification invocation), we compute `(typeof(in(1)) / typeof(in(2))) /\ _type` which gives `java/lang/Object *` (dropping the speculative type). This type becomes the `_type` of the `PhiNode`. After that, we do verification (so no change to the inputs anymore), and we re-call `PhiNode::Value`. We recompute `(typeof(in(1)) / typeof(in(2))) /\ _type` with this new `_type` and here we get java/lang/Object * (speculative=compiler/valhalla/inlinetypes/MyValue2 (compiler/valhalla/inlinetypes/MyInterface):exact *) It's not the same as before, so it's a verification failure. ---- As, for why the meet of in(1): java/lang/Object * (speculative=compiler/valhalla/inlinetypes/MyValue2 (compiler/valhalla/inlinetypes/MyInterface):exact * (inline_depth=4)) in(2): java/lang/Object * (speculative=null) is java/lang/Object * (speculative=compiler/valhalla/inlinetypes/MyValue2 (compiler/valhalla/inlinetypes/MyInterface):exact *) maybe there is a misunderstanding (that I had myself): null here means Java's null, not C++ nullptr. So, basically, the Phi is either null or a MyValue2 (possibly null). It seems natural that the (Hotspot's) meet is the same as `in(1)`, since `typeof(in(1)) < typeof(in(2))`. And I've double checked, this meet really happens, both Region's inputs are non-top. The lack of speculative type is displayed by simply omitting the "speculative=" part. ------------- PR Comment: https://git.openjdk.org/valhalla/pull/1717#issuecomment-3487177477
