JDK-8335220 : C2: Missing check for Opaque4 node in EscapeAnalysis
  • Type: Bug
  • Component: hotspot
  • Sub-Component: compiler
  • Affected Version: 23,24
  • Priority: P3
  • Status: Resolved
  • Resolution: Fixed
  • Submitted: 2024-06-26
  • Updated: 2024-07-01
  • Resolved: 2024-06-27
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 23 JDK 24
23Fixed 24 masterFixed
Related Reports
Relates :  
Relates :  
Relates :  
Description
While testing Leyden Early Release the problem was found in C2 EscapeAnalysis, in new code which handles allocations merge.
In ConnectionGraph::specialize_cmp() the next line is incorrect because it assumes that If node always points to Bool node:
Node* curr_cmp = curr_ctrl->in(0)->in(1)->in(1); // true/false -> if -> bool -> cmp
But loop and predicates optimizations may add Opaque node in between. Which happens in failure case which have next nodes sequence: If -> Opaque4 -> Bool

As result we hit assert in ConnectionGraph::specialize_cmp() when trying to access inputs of Cmp node:

#  Internal Error (/work/leyden/open/src/hotspot/share/opto/node.hpp:409), pid=70375, tid=27907
#  assert(i < _max) failed: oob: i=2, _max=2
#
# JRE version: Java(TM) SE Runtime Environment (24.0) (fastdebug build 24-internal-2024-06-26-1746082...)
# Java VM: Java HotSpot(TM) 64-Bit Server VM (fastdebug 24-internal-2024-06-26-1746082..., mixed mode, sharing, tiered, compressed oops, compressed class ptrs, g1 gc, bsd-aarch64)
#

---------------  S U M M A R Y ------------

Command Line: -XX:CacheDataStore=spring-leyden.cds -XX:CDSPreimage=spring-leyden.cds.preimage

Host: mac, "MacBookPro18,3" arm64, 8 cores, 32G, Darwin 23.5.0, macOS 14.5 (23F79)
Time: Thu Jun 27 07:50:52 2024 PDT elapsed time: 9.845733 seconds (0d 0h 0m 9s)

---------------  T H R E A D  ---------------

Current thread (0x00000001500ac410):  JavaThread "C2 CompilerThread0" daemon [_thread_in_native, id=27907, stack(0x000000016ee00000,0x000000016f003000) (2060K)]

Current CompileTask:
C2:  F9845 C0 Q0 S17 3146    b    4       org.springframework.boot.loader.zip.ZipCentralDirectoryFileHeaderRecord::load (156 bytes)

Stack: [0x000000016ee00000,0x000000016f003000],  sp=0x000000016effe620,  free space=2041k
Native frames: (J=compiled Java code, j=interpreted, Vv=VM code, C=native code)
V  [libjvm.dylib+0x11d16b4]  VMError::report_and_die(int, char const*, char const*, char*, Thread*, unsigned char*, void*, void*, char const*, int, unsigned long)+0x544  (node.hpp:409)
V  [libjvm.dylib+0x11d1e64]  VMError::report_and_die(Thread*, unsigned int, unsigned char*, void*, void*)+0x0
V  [libjvm.dylib+0x58b25c]  print_error_for_unit_test(char const*, char const*, char*)+0x0
V  [libjvm.dylib+0x650ba8]  ConnectionGraph::specialize_cmp(Node*, Node*)+0x16c
V  [libjvm.dylib+0x650c20]  ConnectionGraph::specialize_castpp(Node*, Node*, Node*)+0x70
V  [libjvm.dylib+0x651d54]  ConnectionGraph::reduce_phi_on_castpp_field_load(Node*, GrowableArray<Node*>&, GrowableArray<Node*>&)+0x1b8
V  [libjvm.dylib+0x654888]  ConnectionGraph::reduce_phi(PhiNode*, GrowableArray<Node*>&, GrowableArray<Node*>&)+0x338
V  [libjvm.dylib+0x64baf4]  ConnectionGraph::split_unique_types(GrowableArray<Node*>&, GrowableArray<ArrayCopyNode*>&, GrowableArray<MergeMemNode*>&, Unique_Node_List&)+0xabc
V  [libjvm.dylib+0x646ea8]  ConnectionGraph::compute_escape()+0x1628
V  [libjvm.dylib+0x645744]  ConnectionGraph::do_analysis(Compile*, PhaseIterGVN*)+0xd8
V  [libjvm.dylib+0x4e99e8]  Compile::Optimize()+0x4b0
V  [libjvm.dylib+0x4e8248]  Compile::Compile(ciEnv*, ciMethod*, int, Options, DirectiveSet*)+0x11e0


This code was introduce for ReduceAllocationMerges optimization JDK-8316991 in JDK-23.
There was followup fix JDK-8330853 to add similar checks but it missed 
code in specialize_cmp().
Comments
A pull request was submitted for review. URL: https://git.openjdk.org/jdk/pull/19949 Date: 2024-06-28 17:32:53 +0000
28-06-2024

Thanks Vladimir for adding the additional information!
28-06-2024

Changeset: 9d986a01 Author: Vladimir Kozlov <kvn@openjdk.org> Date: 2024-06-27 16:06:35 +0000 URL: https://git.openjdk.org/jdk/commit/9d986a013d01a5bcc0942bcc490258038291c22c
27-06-2024

It was never observed in CI testing for both mainline and Leyden-premain repos. It was observed by outside client who tried Leyden EA release with SpringBoot. See JDK-8334809. I reproduced it locally but I have to pull his project to reproduce it. I attached hs_err file I got locally.
27-06-2024

ILW = Assert in EA, observed in Leyden, use -XX:-ReduceAllocationMerges = HLM = P3
27-06-2024

A pull request was submitted for review. URL: https://git.openjdk.org/jdk/pull/19921 Date: 2024-06-27 05:33:11 +0000
27-06-2024

I ended up with different fix: more restricted checks in can_reduce_check_users() to catch such cases.
27-06-2024

[~kvn] change looks good to me, thanks for fixing!
27-06-2024

[~cslucas], are you fine with proposed fix or it should be done differently? For example, check for (Op_CmpP || Op_CmpN) and bailout if not as you do in other places?
26-06-2024

I propose this patch to fix the issue: diff --git a/src/hotspot/share/opto/escape.cpp b/src/hotspot/share/opto/escape.cpp index 8a80392d5c7..3cf058d23b1 100644 --- a/src/hotspot/share/opto/escape.cpp +++ b/src/hotspot/share/opto/escape.cpp @@ -651,7 +651,12 @@ Node* ConnectionGraph::specialize_cmp(Node* base, Node* curr_ctrl) { if (curr_ctrl == nullptr || curr_ctrl->is_Region()) { con = _igvn->zerocon(t->basic_type()); } else { - Node* curr_cmp = curr_ctrl->in(0)->in(1)->in(1); // true/false -> if -> bool -> cmp + Node* bol = curr_ctrl->in(0)->in(1); + if (bol->is_Opaque4()) { + bol = bol->in(1); + assert(bol->is_Bool(), "sanity"); + } + Node* curr_cmp = bol->in(1); // true/false -> if -> bool -> cmp con = curr_cmp->in(1)->is_Con() ? curr_cmp->in(1) : curr_cmp->in(2); }
26-06-2024