JDK-8351468 : C2: array fill optimization assigns wrong type to intrinsic call
  • Type: Bug
  • Component: hotspot
  • Sub-Component: compiler
  • Affected Version: 8,11,17,21,25
  • Priority: P3
  • Status: Resolved
  • Resolution: Fixed
  • Submitted: 2025-03-10
  • Updated: 2025-04-29
  • Resolved: 2025-03-24
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 25
25 b16Fixed
Related Reports
Causes :  
Relates :  
Relates :  
Relates :  
Description
The array fill optimization [1] replaces simple array initialization loops with calls to array-fill intrinsics. For arrays of shorts, the optimization wrongly assigns the address type char[] to its resulting array fill intrinsic call, instead of the expected type short[] [2]. As a consequence, anti-dependence analysis [3] fails to recognize and enforce anti-dependences between short[] loads and the intrinsic call. This can cause GCM/LCM to schedule such loads too late, triggering a miscompilation. Besides missing anti-dependences, there might be other unanticipated failures due to type mismatches.

The attached example illustrates the issue:

$ java -ea -Xint Test.java

$ java -ea -Xbatch -XX:-TieredCompilation -XX:CompileOnly=Test::test -XX:LoopUnrollLimit=0 -XX:+OptimizeFill Test.java
Exception in thread "main" java.lang.AssertionError
	at Test.main(Test.java:39)

cfg.pdf (attached) shows the control-flow graph of Test::test() after C2's scheduling phase. Note how the load (160 loadS) is wrongly scheduled after the intrinsic call (142 CallLeafNoFPDirect). Anti-dependency analysis misses their anti-dependency because of their different alias indices 10 and 7 (derived from their address types char[] and short[]).

[1] https://github.com/openjdk/jdk/blob/4e1367e34be724a0f84069100854c38333610714/src/hotspot/share/opto/loopTransform.cpp#L3772
[2] https://github.com/openjdk/jdk/blob/4e1367e34be724a0f84069100854c38333610714/src/hotspot/share/opto/memnode.hpp#L680
[3] https://github.com/openjdk/jdk/blob/4e1367e34be724a0f84069100854c38333610714/src/hotspot/share/opto/gcm.cpp#L681
Comments
Changeset: de580090 Branch: master Author: Roberto CastaƱeda Lozano <rcastanedalo@openjdk.org> Date: 2025-03-24 11:05:46 +0000 URL: https://git.openjdk.org/jdk/commit/de580090cd9ada313a878975b9f183045d293684
24-03-2025

A pull request was submitted for review. Branch: master URL: https://git.openjdk.org/jdk/pull/24005 Date: 2025-03-12 09:47:17 +0000
12-03-2025

ILW = Incorrect result with C2 compiled code, found with verification, reproducible with targeted test and with -XX:+OptimizeFill (only enabled by default on AArch64), disable compilation of affected method or -XX:-OptimizeFill = HLM = P3
10-03-2025

The attached test does not fail on JDK 11, because a LoadP pinned to the inner loop inhibits the array fill optimization (see attached cfg-11-vs-25.png), but PhaseIdealLoop::intrinsify_fill computes the address type of the intrinsic in the same way as in mainline, so JDK 11 is potentially affected as well.
10-03-2025

The attached test does not fail on JDK 8 either. In this JDK version, the intrinsic is still assigned the wrong type, so it is potentially affected as well. However, in the specific test case the load cannot be scheduled below it because it is indirectly used by an uncommon trap reached before the intrinsic call (see attached cfg-8.pdf, generated with the above JVM options and -XX:-LoopUnswitching).
10-03-2025