RFR: 8347006: LoadRangeNode floats above array guard in arraycopy intrinsic
Tobias Hartmann
thartmann at openjdk.org
Wed Jan 8 12:29:50 UTC 2025
On Wed, 8 Jan 2025 12:17:05 GMT, Roland Westrelin <roland at openjdk.org> wrote:
>> C2's arraycopy intrinsic adds guards that check that the source and destination objects are arrays:
>> https://github.com/openjdk/jdk/blob/afe543414f58a04832d4f07dea88881d64954a0b/src/hotspot/share/opto/library_call.cpp#L5917-L5919
>>
>> If these guards pass, the array length is loaded:
>> https://github.com/openjdk/jdk/blob/afe543414f58a04832d4f07dea88881d64954a0b/src/hotspot/share/opto/library_call.cpp#L5930-L5933
>>
>> But since the `LoadRangeNode` is not pinned, it might float above the array guard:
>> https://github.com/openjdk/jdk/blob/afe543414f58a04832d4f07dea88881d64954a0b/src/hotspot/share/opto/graphKit.cpp#L1214
>>
>> If the object is not an array, we will read garbage. That's usually fine because the result will not be used (the array guard will trigger) but with `-XX:+UseCompactObjectHeaders` it can happen that the memory right after the header is not mapped and we crash.
>>
>> The fix is to add a `CheckCastPPNode` to propagate the information that the operand is an array and prevent the load from floating.
>>
>> Thanks to @shipilev for identifying the root cause!
>>
>> I was able to reliably reproduce the issue with `compiler/arraycopy/TestArrayCopyNoInit.java` and `-XX:-UseTLAB -XX:+UnlockExperimentalVMOptions -XX:-UseCompressedClassPointers` on Linux AArch64 and verified that the fix solves the problem.
>>
>> Best regards,
>> Tobias
>
> src/hotspot/share/opto/library_call.cpp line 5920:
>
>> 5918: // Keep track of the information that src/dest are arrays to prevent below array specific accesses from floating above.
>> 5919: generate_non_array_guard(load_object_klass(src), slow_region);
>> 5920: const Type* tary = TypeAryPtr::make(TypePtr::BotPTR, TypeAry::make(Type::BOTTOM, TypeInt::POS), nullptr, false, Type::OffsetBot);
>
> Is this never used elsewhere? Should it a static field in `TypeAryPtr` same as `TypeAryPtr::BYTES` and friends?
I wondered as well and no, we don't use this type anywhere else (the closest would be `TypeAryPtr::RANGE`). We only create it when meeting arrays of primitive and non-primitive element type. Do you think this should still go to `TypeAryPtr::*`?
-------------
PR Review Comment: https://git.openjdk.org/jdk/pull/22967#discussion_r1907103145
More information about the hotspot-compiler-dev
mailing list