RFR: 8370405: C2: mismatched store from MergeStores wrongly scalarized in allocation elimination
Emanuel Peter
epeter at openjdk.org
Wed Oct 29 08:34:00 UTC 2025
**Analysis**
We run Escape Analysis, and see that a local array allocation could possibly be removed, we only have matching `StoreI` to the `int[]`. But there is one `StoreI` that is still in a loop, and so we wait with the actual allocation removal until later, hoping it may go away, or drop out of the loop.
During loop opts, the `StoreI` drops out of the loop, now there should be nothing in the way of allocation removal.
But now we run `MergeStores`, and merge two of the `StoreI` into a mismatched `StoreL`.
Then, we eventually remove the allocation, but don't check again if any new mismatched store has appeared.
Instead of a `ConI`, we receive a `ConL`, for the first of the two merged `StoreI`. The second merged `StoreI` instead captures the state before the `StoreL`, and that is wrong.
**Solution**
We should have some assert, that checks that the captured `field_val` corresponds to the expected `field_type`.
But the real fix was suggested by @merykitty : apparently he just had a similar issue in Valhalla:
https://github.com/openjdk/valhalla/blame/60af17ff5995cfa5de075332355f7f475c163865/src/hotspot/share/opto/macro.cpp#L709-L713
(the idea is to bail out of the elimination if any of the found stores are mismatched.)
**Details**
How the bad sequence develops, and which components are involved.
1) The `SafePoint` contains a `ConL` and 3 `ConI`. (Correct would have been 4 `ConI`)
6 ConI === 23 [[ 4 ]] #int:16777216
7 ConI === 23 [[ 4 ]] #int:256
8 ConI === 23 [[ 4 ]] #int:1048576
9 ConL === 23 [[ 4 ]] #long:68719476737
54 DefinitionSpillCopy === _ 27 [[ 16 12 4 ]]
4 CallStaticJavaDirect === 47 29 30 26 32 33 0 34 0 54 9 8 7 6 [[ 5 3 52 ]] Static wrapper for: uncommon_trap(reason='unstable_if' action='reinterpret' debug_id='0') # void ( int ) C=0.000100 Test::test @ bci:38 (line 21) reexecute !jvms: Test::test @ bci:38 (line 21)
2) This is then encoded into an `ObjectValue`. A `Type::Long` / `ConL` is converted into a `[int=0, long=ConL]` pair, see:
https://github.com/openjdk/jdk/blob/da7121aff9eccb046b82a75093034f1cdbd9b9e4/src/hotspot/share/opto/output.cpp#L920-L925
If I understand it right, there zero is just a placeholder.
And so we get:
(rr) p sv->print_fields_on(tty)
Fields: 0, 68719476737, 1048576, 256, 16777216
We can see the `zero`, followed by the `ConL`, and then 3 `ConI`.
This sequence is then serialized into a stream, and stored in the `nmethod`, as part of the compilation.
3) Once we deopt, we deserialize from the stream, and reconstruct the `sv` (`ObjectValue`). See `rematerialize_objects`.
4) In `Deoptimization::realloc_objects`, we allocate a new array, with `5` elements, because the `sv` has `5` elements.
5) In `Deoptimization::reassign_type_array_elements`, we step through all elements of the `sv`, and fill the values into the array. When we encounter the `[int=0, long=ConL]`, we interpret them as a pair:
https://github.com/openjdk/jdk/blob/da7121aff9eccb046b82a75093034f1cdbd9b9e4/src/hotspot/share/runtime/deoptimization.cpp#L1378-L1408
We do not store an int zero and then a long, but rather we "remove" the zero, and just store the long. The zero was just a placeholder.
And so finally, we arrive with this sequence in the array:
(rr) p obj->print_on (tty)
[I
{0x00000006230b9a10} - klass: {type array int} - flags: is_cloneable_fast
- length: 5
- 0: 0x1 1
- 1: 0x10 16
- 2: 0x100000 1048576
- 3: 0x100 256
- 4: 0x1000000 16777216
-------------
Commit messages:
- Apply suggestions from code review
- more assert adjustment
- ignore debug flag
- id for tests, and fix up the assert
- pass int for short slot
- another test
- improve test
- wip new IR test
- fix up asserts
- improved comments in test
- ... and 4 more: https://git.openjdk.org/jdk/compare/7bb490c4...9114d379
Changes: https://git.openjdk.org/jdk/pull/27997/files
Webrev: https://webrevs.openjdk.org/?repo=jdk&pr=27997&range=00
Issue: https://bugs.openjdk.org/browse/JDK-8370405
Stats: 357 lines in 5 files changed: 357 ins; 0 del; 0 mod
Patch: https://git.openjdk.org/jdk/pull/27997.diff
Fetch: git fetch https://git.openjdk.org/jdk.git pull/27997/head:pull/27997
PR: https://git.openjdk.org/jdk/pull/27997
More information about the hotspot-dev
mailing list