RFR: 8370405: C2: mismatched store from MergeStores wrongly scalarized in allocation elimination
    Quan Anh Mai 
    qamai at openjdk.org
       
    Wed Oct 29 15:36:17 UTC 2025
    
    
  
On Wed, 29 Oct 2025 15:03:40 GMT, Emanuel Peter <epeter at openjdk.org> wrote:
>> I'm not following. Can you spell it out with a bit more detail? I'm not very familiar with how we deal with oops and interfaces in general, so I still need to read up a bit more now.
>> 
>> Just to make clear: we are not talking about a regular store here, but rather capturing the value that would be stored, and instead pass it to the deopt SafePoint. But you probably are aware of that ;)
>
> @rwestrel Do you have an idea how to strip away the interface information? Or would you follow another idea?
> 
> I can also take the simple route here, and for now only assert for primitive types. Because the bug comes from MergeStores, and that only works for primitive types. And then I can file a follow-up RFE for someone to strengthen the assert, and possibly fix up other things.
A `TypeInstPtr` has a `_klass` and an `_interfaces`. The `_klass` is a non-interface `ciInstanceKlass` and the `_interfaces` contains the list of interfaces that `TypeInstPtr` must satisfy. For example, a `String` object would have the type (accessed by `PhaseGVN::type`) being `String (all the interfaces that String satisfies transitively)`, an `Enumeration` would have the type being `Object (Enumeration)`, a `List` object would have the type being `Object (List, Iterable, Collection)`.
A `TypeInstPtr` is a subtype of another `TypeInstPtr` iff the `_klass` of the first one is a subtype of the `_klass` of the second one, and the `_interfaces` of the first `TypeInstPtr` is a superset of the `_interfaces` of the second `TypeInstPtr`. The logic is very convoluted because the implementation of `join` is very confusing, but that is the spirit.
In the type system, the thing that is present is the thing that is trusted. As a result, because we don't trust the return type of `parent.getResources(name)`, we strip the interface part and the type of the result is `Object`. In contrast, we trust the type of a value returned by `anewarray`, so the type of `tmp` is an array of `Object (Enumeration)`.
When executing the `aastore` bytecode. The compiler first does `Parse::array_store_check`, this, in turns, calls `GraphKit::gen_checkcast`. It can be seen that `obj` is of type `Object` while `a_e_klass` is the klass pointer of `Object (Enumeration)`. Since `Object` is not a subtype of `Object (Enumeration)`, we should have generate a check cast, then `obj` would be casted to `Object (Enumeration)` with a `CheckCastPP`. This `CheckCastPP` is then used as the input of the `EncodePNode`, then to the `StoreNNode`. So the type being stored should not be `Object`, but `Object (Enumeration)`.
That is the spirit, I wonder what is unexpected here.
-------------
PR Review Comment: https://git.openjdk.org/jdk/pull/27997#discussion_r2473840361
    
    
More information about the hotspot-compiler-dev
mailing list