JDK-8328702 : C2: Crash during parsing because sub type check is not folded
  • Type: Bug
  • Component: hotspot
  • Sub-Component: compiler
  • Affected Version: 21,22,23
  • Priority: P2
  • Status: Closed
  • Resolution: Fixed
  • Submitted: 2024-03-21
  • Updated: 2024-07-18
  • Resolved: 2024-04-04
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 21 JDK 22 JDK 23
21.0.4-oracleFixed 22.0.2Fixed 23 b17Fixed
Related Reports
Duplicate :  
Relates :  
Relates :  
Description
Attached Crash.java triggers a crash during C2 compilation.

java -XX:-TieredCompilation -Xbatch -XX:CompileCommand=compileonly,Crash::* Crash.java

# A fatal error has been detected by the Java Runtime Environment:
#
#  Internal Error (/workspace/open/src/hotspot/share/opto/graphKit.hpp:369), pid=2866297, tid=2866311
#  assert(argument(0)->bottom_type()->isa_ptr()) failed: must be
#
# JRE version: Java(TM) SE Runtime Environment (23.0+14) (fastdebug build 23-ea+14-1026)
# Java VM: Java HotSpot(TM) 64-Bit Server VM (fastdebug 23-ea+14-1026, mixed mode, sharing, compressed oops, compressed class ptrs, g1 gc, linux-amd64)
# Problematic frame:
# V  [libjvm.so+0x1221fc3]  LibraryCallKit::inline_native_getClass()+0x133

Current CompileTask:
C2:2232  110    b        Crash::compileRoot (19 bytes)

Stack: [0x00007f2101bfc000,0x00007f2101cfd000],  sp=0x00007f2101cf8b30,  free space=1010k
Native frames: (J=compiled Java code, j=interpreted, Vv=VM code, C=native code)
V  [libjvm.so+0x1221fc3]  LibraryCallKit::inline_native_getClass()+0x133  (graphKit.hpp:369)
V  [libjvm.so+0x1242284]  LibraryIntrinsic::generate(JVMState*)+0x1e4
V  [libjvm.so+0xb8dc42]  Parse::do_call()+0x602
V  [libjvm.so+0x151d778]  Parse::do_one_bytecode()+0x328
V  [libjvm.so+0x150b38a]  Parse::do_one_block()+0x20a
V  [libjvm.so+0x150c846]  Parse::do_all_blocks()+0x136
V  [libjvm.so+0x1510b85]  Parse::Parse(JVMState*, ciMethod*, float)+0xb15
V  [libjvm.so+0x84be49]  ParseGenerator::generate(JVMState*)+0x169
V  [libjvm.so+0xb8dc42]  Parse::do_call()+0x602
V  [libjvm.so+0x151d778]  Parse::do_one_bytecode()+0x328
V  [libjvm.so+0x150b38a]  Parse::do_one_block()+0x20a
V  [libjvm.so+0x150c846]  Parse::do_all_blocks()+0x136
V  [libjvm.so+0x1510b85]  Parse::Parse(JVMState*, ciMethod*, float)+0xb15
V  [libjvm.so+0x84be49]  ParseGenerator::generate(JVMState*)+0x169
V  [libjvm.so+0x9f542e]  Compile::Compile(ciEnv*, ciMethod*, int, Options, DirectiveSet*)+0x163e
V  [libjvm.so+0x8498a5]  C2Compiler::compile_method(ciEnv*, ciMethod*, int, bool, DirectiveSet*)+0x1d5
V  [libjvm.so+0xa016d8]  CompileBroker::invoke_compiler_on_method(CompileTask*)+0x928
V  [libjvm.so+0xa02368]  CompileBroker::compiler_thread_loop()+0x478
V  [libjvm.so+0xebfccc]  JavaThread::thread_main_inner()+0xcc
V  [libjvm.so+0x17b9e66]  Thread::call_run()+0xb6
V  [libjvm.so+0x14bdb47]  thread_native_entry(Thread*)+0x127

It's a regression from JDK-8297933 in JDK 21 b05. The problem is that a node in the C2 IR is replaced by TOP. We assert in debug or crash during compilation in product.

#3  0x00007f27b716f804 in LibraryCallKit::inline_native_getClass (this=0x7f279b3f7cd0) at /oracle/valhalla/open/src/hotspot/share/opto/library_call.cpp:4948
4948	  set_result(load_mirror_from_klass(load_object_klass(obj)));
(rr) p obj->dump(1)
   0  Root  === 0 70 106  [[ 0 1 3 20 21 22 33 38 53 56 65 76 97 101 ]] 
   1  Con  === 0  [[ ]]  #top

The underlying issue is that after JDK-8297933, C2's type system is able to determine that the instanceof check in Crash::typeCheck is always false when called from Crash::compileRoot and thus the type 'i' is replaced by TOP (= no possible type). However, C2 is not able to fold the corresponding subtype check, leading to an inconsistent intermediate representation.

The problem is not specific to the Object.getClass() intrinsic. We just end up crashing when trying to intrinsify that method and encountering TOP. Using 'i.hashCode()' instead of 'getClass' will result in a different failure mode.
Comments
[jdk21u-fix-request] Approval Request from Aleksey Shipilëv Fixes another C2 bug, regression in JDK 21. Usual risk for C2 changes, but the fix looks simple enough. Passes all tests, including the aggressive compiler testing. New regression test fails without the fix, passes with it.
08-04-2024

A pull request was submitted for review. URL: https://git.openjdk.org/jdk21u-dev/pull/450 Date: 2024-04-04 13:58:17 +0000
05-04-2024

Fix Request (JDK 22u) Fixes a crash during C2 parsing due to a broken graph. The fix is simple and low risk. Testing with tier1,tier2,tier3,tier4,hs-comp-stress,hs-precheckin-comp. Applies cleanly.
04-04-2024

A pull request was submitted for review. URL: https://git.openjdk.org/jdk22u/pull/125 Date: 2024-04-04 07:49:47 +0000
04-04-2024

Changeset: e5e21a8a Author: Christian Hagedorn <chagedorn@openjdk.org> Date: 2024-04-04 06:02:35 +0000 URL: https://git.openjdk.org/jdk/commit/e5e21a8a6e64466f9cda2064aa2723a15d4ae86a
04-04-2024

A pull request was submitted for review. URL: https://git.openjdk.org/jdk/pull/18512 Date: 2024-03-27 13:48:09 +0000
27-03-2024

Sorry I've missed that it was already assigned when I've looked into it during triaging (was unassigned before). I've had a quick look with the test case Crash.java since I suspected it might be related to JDK-8328480. It turns out, it is not. But I think I found the problem. In TypePtr::maybe_java_subtype_of_helper_for_array() we check if the TypeAryKlassPtr this_one might be a subtype of the interface I. Since the base element type of this_one is bottom, we conclude that this_one *might* be a sub type of interface I. However, this is wrong: An array class cannot be a sub type of interface I. We should therefore return here false (i.e. not a sub type). We would actually perform that check but only after the bottom/top check: https://github.com/openjdk/jdk/blob/master/src/hotspot/share/opto/type.cpp#L6462-L6468 I suggest to move the this_top_or_bottom check below: - bool this_top_or_bottom = (this_one->base_element_type(dummy) == Type::TOP || this_one->base_element_type(dummy) == Type::BOTTOM); - if (!this_one->is_loaded() || !other->is_loaded() || this_top_or_bottom) { + if (!this_one->is_loaded() || !other->is_loaded()) { return true; } if (this_one->is_instance_type(other)) { return other->klass()->equals(ciEnv::current()->Object_klass()) && other->_interfaces->intersection_with(this_one->_interfaces)->eq(other->_interfaces); } + + bool this_top_or_bottom = (this_one->base_element_type(dummy) == Type::TOP || this_one->base_element_type(dummy) == Type::BOTTOM); + if (this_top_or_bottom) { + return true; + } Is that reasonable? But maybe I've missed something. At is_java_subtype_of_helper_for_array() we have the same order as currently in maybe_java_subtype_of_helper_for_array() but there it's fine because we would return false if this_top_or_bottom is true because we cannot tell if it's a sub type or not if the base element type is bottom.
21-03-2024

Roland, could you please have a look? Thanks.
21-03-2024

ILW = Crash during C2 compilation (regression), easy to reproduce but edge case, no workaround but disable compilation of affected method = HMM = P2
21-03-2024