RFR: 8370405: C2: mismatched store from MergeStores wrongly scalarized in allocation elimination
    Emanuel Peter 
    epeter at openjdk.org
       
    Wed Oct 29 16:23:34 UTC 2025
    
    
  
On Wed, 29 Oct 2025 15:53:10 GMT, Emanuel Peter <epeter at openjdk.org> wrote:
>> 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.
>
> Ah, I see. You are wondering if there should be a `Parse::array_store_check`, why is there not a checkcast so that we cast from `Object` -> `Object (Enumeration)`. Great question. I'll investigate.
Quick summary of investigation:
The `EncodeP` is the `field_val`:
(rr) p field_val->dump_bfs(3,0,"#")
dist dump
---------------------------------------------
   3  303  CallDynamicJava  === 203 299 202 8 1 (10 40 1 1 90 90 69 ) [[ 304 305 306 308 317 316 ]] # Dynamic  java.lang.ClassLoader::findResources java/lang/Object * ( java/security/SecureClassLoader:NotNull *, java/lang/String (java/io/Serializable,java/lang/Comparable,java/lang/CharSequence,java/lang/constant/Constable,java/lang/constant/ConstantDesc):exact * ) ClassLoader::getResources @ bci:42 (line 1445) !jvms: ClassLoader::getResources @ bci:42 (line 1445)
   3  332  If  === 311 331  [[ 333 334 ]] P=0.999999, C=-1.000000 !jvms: ClassLoader::getResources @ bci:45 (line 1445)
   2  308  Proj  === 303  [[ 335 330 ]] #5  Oop:java/lang/Object * !jvms: ClassLoader::getResources @ bci:42 (line 1445)
   2  334  IfTrue  === 332  [[ 376 335 ]] #1 !jvms: ClassLoader::getResources @ bci:45 (line 1445)
   1  335  CastPP  === 334 308  [[ 358 343 353 ]]  #java/lang/Object:NotNull *  Oop:java/lang/Object:NotNull * !jvms: ClassLoader::getResources @ bci:45 (line 1445)
   0  358  EncodeP  === _ 335  [[ 359 ]]  #narrowoop: java/lang/Object:NotNull * !jvms: ClassLoader::getResources @ bci:45 (line 1445)
It seems the value comes from the call, via a projection, and a null-check cast. But I see no type/interface check cast for `Enumeration`.
This is the store that is being eliminated:
359  StoreN  === 377 393 322 358  [[ 365 ]]  @narrowoop: java/lang/Object *[int:>=0] (java/lang/Cloneable,java/io/Serializable)+any * [narrow], idx=6;  Memory: @narrowoop: java/lang/Object (java/util/Enumeration) *[int:2] (java/lang/Cloneable,java/io/Serializable):NotNull:exact[1] *,iid=73 [narrow], idx=12; !jvms: ClassLoader::getResources @ bci:45 (line 1445)
Tracing back where the store comes from: `Parse::array_store`.
(rr) p elemtype->dump()
narrowoop: java/lang/Object (java/util/Enumeration) *
Inside `Parse::array_store_check` -> `GraphKit::gen_checkcast` we create a null check, with the CastPP we saw above:
335  CastPP  === 334 308  [[ 24 ]]  #java/lang/Object:NotNull *  Oop:java/lang/Object:NotNull * !jvms: ClassLoader::getResources @ bci:45 (line 1445)
More in next comment...
-------------
PR Review Comment: https://git.openjdk.org/jdk/pull/27997#discussion_r2474151074
    
    
More information about the hotspot-compiler-dev
mailing list