JDK-8297752 : C2: Broken graph due to IfNode with a pre-loop Opaque1 node that cannot be folded while data is dying
  • Type: Bug
  • Component: hotspot
  • Sub-Component: compiler
  • Affected Version: 19,20,21,22,23,24
  • Priority: P3
  • Status: Open
  • Resolution: Unresolved
  • Submitted: 2022-11-29
  • Updated: 2024-06-12
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 24
24Unresolved
Related Reports
Relates :  
Description
The attached Java Fuzzer testcase starts to fail after JDK-8281429 which improved the type information of iv phi nodes. This might just reveal an existing bug.

To reproduce:

$ java -Xcomp -XX:-TieredCompilation -XX:+StressIGVN -XX:StressSeed=919693051 -XX:CompileOnly=Reduced Reduced.java
$ java -Xcomp -XX:-TieredCompilation -XX:+StressIGVN -XX:StressSeed=919693051 -XX:CompileOnly=Test Test.java

#
# A fatal error has been detected by the Java Runtime Environment:
#
#  Internal Error (c:\sb\prod\1669253370\workspace\open\src\hotspot\share\opto\loopnode.cpp:5866), pid=28688, tid=25384
#  assert(false) failed: Bad graph detected in build_loop_late
.......
Command Line: -XX:-TieredCompilation -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockDiagnosticVMOptions -XX:+StressLCM -XX:+StressGCM -XX:+StressIGVN -XX:+StressCCP -XX:StressSeed=613859031 -Xmx1G -Xcomp -Xbatch -XX:CompileOnly=Test -XX:CompileCommand=quiet -XX:MaxRAMPercentage=4.16667 -Djava.io.tmpdir=c:\sb\prod\1669391292\testoutput\test-support\jtreg_closed_test_hotspot_jtreg_applications_javafuzzer_BigTest_java\tmp Test
.......
Current CompileTask:
C2:    339    7 %  b        Test::vMeth @ 50 (301 bytes)

Stack: [0x0000008402600000,0x0000008402700000]
Native frames: (J=compiled Java code, j=interpreted, Vv=VM code, C=native code)
V  [jvm.dll+0xc04d51]  os::win32::platform_print_native_stack+0xf1  (os_windows_x86.cpp:236)
V  [jvm.dll+0xe8bad0]  VMError::report+0x10c0  (vmError.cpp:841)
V  [jvm.dll+0xe8d5c4]  VMError::report_and_die+0x644  (vmError.cpp:1700)
V  [jvm.dll+0xe8dd04]  VMError::report_and_die+0x64  (vmError.cpp:1481)
V  [jvm.dll+0x576ef7]  report_vm_error+0xb7  (debug.cpp:286)
V  [jvm.dll+0xa953b1]  PhaseIdealLoop::build_loop_late_post_work+0x431  (loopnode.cpp:5866)
V  [jvm.dll+0xa94f28]  PhaseIdealLoop::build_loop_late+0x378  (loopnode.cpp:5717)
V  [jvm.dll+0xa93af2]  PhaseIdealLoop::build_and_optimize+0x932  (loopnode.cpp:4400)
V  [jvm.dll+0x50bbfd]  Compile::Optimize+0x108d  (compile.cpp:2382)
V  [jvm.dll+0x508aca]  Compile::Compile+0x167a  (compile.cpp:831)
V  [jvm.dll+0x42bb05]  C2Compiler::compile_method+0x145  (c2compiler.cpp:116)
V  [jvm.dll+0x522dd8]  CompileBroker::invoke_compiler_on_method+0x858  (compileBroker.cpp:2240)
V  [jvm.dll+0x5205fd]  CompileBroker::compiler_thread_loop+0x23d  (compileBroker.cpp:1917)
V  [jvm.dll+0x7f0af2]  JavaThread::thread_main_inner+0x282  (javaThread.cpp:698)
V  [jvm.dll+0xe01973]  Thread::call_run+0x253  (thread.cpp:229)
V  [jvm.dll+0xc03668]  thread_native_entry+0xb8  (os_windows.cpp:547)
C  [ucrtbase.dll+0x26b4c]
C  [KERNEL32.DLL+0x14ed0]
C  [ntdll.dll+0x7e39b]

Comments
Attached another case where we cannot fold a CountedLoopEndNode due to a pre-loop Opaque1 that blocks this optimization even though it has a constant as an input. We crash in TraceLoopOpts when trying to access the counted loop stride and do not find an AddI incr node but a constant instead. $ java -Xcomp -XX:+TraceLoopOpts -XX:CompileCommand=compileonly,*Test*::* TestTraceLoopOptsCrash.java
08-11-2023

I've revisited this bug and did a more thorough analysis: We unswitch a loop and create a new unswitch If that decides if we should enter the fast or slow loop. The bool of that test compares two constants but one of them is hidden behind an Opaque1 node that was originally added for the pre-loop CountedLoopEnd test. This means that one of the unswitched loop is actually dead but we cannot remove it because of that Opaque1 node. But there is a Cast node in this dead loop which is replaced by top and the graph partially dies. We end up in a broken graph state. The fix would be to make sure that this unswitch If can be folded. This bug is very similar to JDK-8298176 where we are unable to fold a zero trip guard If because an OpaqueZeroTripGuard node blocks this while data dies because a Cast node is replaced by top and we are also left with a broken graph state.
14-12-2022

I've had a closer look at it and it seems to be unrelated to JDK-8288981 or JDK-8290850. In this particular case, a CMove node becomes top because one of its paths become top due to a dying if/region which is folded. This folds some phi nodes which leaves the graph in a broken state. I'm not yet sure if JDK-8281429 is really unrelated as we are using improved type information - but only for the iv phi, we do not propagate this to other phis in the loop. That might be a problem. However, this needs some further investigation. As this is rather an edge-case and is not a recent regression, I'm moving this to JDK 21 for now.
29-11-2022

ILW = Broken C2 graph, single Java Fuzzer testcase, possibly use -XX:ConditionalMoveLimit=0 or disable compilation of affected method = HLM = P3
29-11-2022