JDK-8265767 : compiler/eliminateAutobox/TestIntBoxing.java crashes on arm32 after 8264649 in debug VMs
  • Type: Bug
  • Component: hotspot
  • Sub-Component: compiler
  • Affected Version: 17
  • Priority: P3
  • Status: Resolved
  • Resolution: Fixed
  • OS: linux
  • CPU: arm
  • Submitted: 2021-04-22
  • Updated: 2021-06-03
  • Resolved: 2021-05-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 17
17 b21Fixed
Related Reports
Relates :  
Description
The change made by JDK-8264649 seems to break the test case compiler/eliminateAutobox/TestIntBoxing.java on 32-bit arm in fastdebug builds. This is a bit weird to me, since it looks like the change should actually fix the problem.

The JVM crashes with:

ACTION: main -- Failed. Unexpected exit from test [exit code: 1]
REASON: User specified action: run main/othervm -Xbatch -XX:+IgnoreUnrecognizedVMOptions -XX:+EliminateAutoBox compiler.eliminateAutobox.TestIntBoxing 
TIME:   7.335 seconds
messages:
command: main -Xbatch -XX:+IgnoreUnrecognizedVMOptions -XX:+EliminateAutoBox compiler.eliminateAutobox.TestIntBoxing
reason: User specified action: run main/othervm -Xbatch -XX:+IgnoreUnrecognizedVMOptions -XX:+EliminateAutoBox compiler.eliminateAutobox.TestIntBoxing 
Mode: othervm [/othervm specified]
elapsed time (seconds): 7.335
configuration:
STDOUT:
 715  AddI  === _  564  109  [[]]  !jvms: TestIntBoxing::remi_sump_deop @ bci:-1 (line 504)
# To suppress the following error report, specify this argument
# after -XX: or in .hotspotrc:  SuppressErrorAt=/compile.cpp:2375
#
# A fatal error has been detected by the Java Runtime Environment:
#
#  Internal Error (/home/cgo/dev/openjdk/jdk/src/hotspot/share/opto/compile.cpp:2375), pid=18855, tid=18866
#  fatal error: no reachable node should have no use
#
# JRE version: OpenJDK Runtime Environment (17.0+18) (fastdebug build 17-internal+18-ahead-146--e16d568c1f5d7030b9e038e21fb3815ae5b1163a)
# Java VM: OpenJDK Server VM (fastdebug 17-internal+18-ahead-146--e16d568c1f5d7030b9e038e21fb3815ae5b1163a, mixed mode, serial gc, linux-arm)
# Problematic frame:
# V  [libjvm.so+0x63dea8]  Compile::check_no_dead_use() const+0x34c
#
# CreateCoredumpOnCrash turned off, no core file dumped
#
# An error report file with more information is saved as:
# /home/microdoc/cgo/jdk/build/run-test-prebuilt/test-support/jtreg_test_hotspot_jtreg_compiler_eliminateAutobox_TestIntBoxing_java/scratch/hs_err_pid18855.log
#
# Compiler replay data is saved as:
# /home/microdoc/cgo/jdk/build/run-test-prebuilt/test-support/jtreg_test_hotspot_jtreg_compiler_eliminateAutobox_TestIntBoxing_java/scratch/replay_pid18855.log
#
# If you would like to submit a bug report, please visit:
#   https://bugreport.java.com/bugreport/crash.jsp
#

Reverting the change done in JDK-8264649 using `$ git revert --no-commit 42f4d706` makes the problem disappear and the test doesn't crash anymore.
Comments
Changeset: ee5bba0d Author: Hui Shi <hshi@openjdk.org> Committer: Tobias Hartmann <thartmann@openjdk.org> Date: 2021-05-04 12:58:25 +0000 URL: https://git.openjdk.java.net/jdk/commit/ee5bba0dc4cc7c2bfe633c5a3fe731c6c37adb1d
04-05-2021

compiler/eliminateAutobox/TestIntBoxing.java crashes on arm32 after fixing for JDK-8264649. In LoadNode::eliminate_autobox, "previous" result is dead after line 1450 but not added into PhaseGVN worklist. Its out_cnt is 0. If it isn't optimized, will trigger assertion in Compile::check_no_dead_use. 1443 } else if (result->is_Add() && result->in(2)->is_Con() && 1444 result->in(1)->Opcode() == Op_LShiftX && 1445 result->in(1)->in(2) == phase->intcon(shift)) { 1446 // We can't do general optimization: ((X<<Z) + Y) >> Z ==> X + (Y>>Z) 1447 // but for boxing cache access we know that X<<Z will not overflow 1448 // (there is range check) so we do this optimizatrion by hand here. 1449 Node* add_con = new RShiftXNode(result->in(2), phase->intcon(shift)); 1450 result = new AddXNode(result->in(1)->in(1), phase->transform(add_con)); 1451 } else ----- --------------------------------------------------------- Why does this assertion occur only on arm32? In above LoadNode::eliminate_autobox branch, optimization is matching "IntegerCache.cache[i + (-IntegerCache.low)]" and get int value by offset . Testing on X86_64, TestIntBoxing.remi_sump_deop enters above branch four times and create four dead AddL nodes. offset_expression for "IntegerCache.cache[i + (-IntegerCache.low)]" in bytes is "((i + (-IntegerCache.low)) << 2) + 16"; 16 is array header size. "previous" reuslt at line 1450 is "((i + (-IntegerCache.low)) << 2) - 512)". "updated" result at line 1450 suppose be "((i + (-IntegerCache.low)) << 2) - 512) >> 2", its simplification form is "(i + (-IntegerCache.low)) + (-128)". Final result node is adding (i + (-IntegerCache.low)) with (-128). These four AddL nodes will be removed when removing node 680 (long:-512) as it has no other uses and no assertion in Compile::check_no_dead_use. 680 ConL === 0 [[ 679 694 712 725 ]] #long:-512 679 AddL === _ 575 680 [[]] !jvms: TestIntBoxing::remi_sump_deop @ bci:-1 (line 494) 694 AddL === _ 465 680 [[]] !jvms: TestIntBoxing::remi_sump_deop @ bci:-1 (line 494) 712 AddL === _ 366 680 [[]] !jvms: TestIntBoxing::remi_sump_deop @ bci:-1 (line 494) 725 AddL === _ 244 680 [[]] !jvms: TestIntBoxing::remi_sump_deop @ bci:-1 (line 494) ----- --------------------------------------------------------- Why does this assertion occur after JDK-8264649 on arm32? arm32 optimizes better for "IntegerCache.cache[i + (-IntegerCache.low)]". Its offset_expression is "(i << 2) + 528", (-IntegerCache.low) is folded with array header size. "previous" reuslt at line 1450 is "(i << 2) + 4". There is Integer object "j+1", "+1" expression is folded into offset_expression like "(i << 2) + 8". 503 static int remi_sump_deop(Integer j) { 504 for (int i = 0; i< 1000; i++) { 505 j = foo(j + 1); // j + 1 expression 506 } 507 dummy(); 508 return j; 509 } 510 Node 728 casuses assertion in Compile::check_no_dead_use. 672 ConI === 0 [[ 700 686 ]] #int:4 // dead, no other use 109 ConI === 0 [[ 467 327 691 728 ]] #int:8 // live, has other use 671 AddI === _ 572 672 [[]] !jvms: TestIntBoxing::remi_sump_deop @ bci:-1 (line 494) 686 AddI === _ 369 672 [[]] !jvms: TestIntBoxing::remi_sump_deop @ bci:-1 (line 494) 700 AddI === _ 465 672 [[]] !jvms: TestIntBoxing::remi_sump_deop @ bci:-1 (line 494) 728 AddI === _ 572 109 [[]] !jvms: TestIntBoxing::remi_sump_deop @ bci:-1 (line 494) // failure node in Compile::check_no_dead_use. ----- --------------------------------------------------------- Why does this assertion not occur before JDK-8264649 on arm32? Integer object "j+1", "+1" expression is not folded into offset_expression before JDK-8264649. All dead AddI has input "#int:4" and removed later.
30-04-2021

This bug releated with adding top node into wroklist, with following chagne, arm32 case can pass. diff --git a/src/hotspot/share/opto/phaseX.cpp b/src/hotspot/share/opto/phaseX.cpp index 8c0a7de2d66..6d74e8ddb91 100644 --- a/src/hotspot/share/opto/phaseX.cpp +++ b/src/hotspot/share/opto/phaseX.cpp @@ -1481,7 +1481,7 @@ void PhaseIterGVN::subsume_node( Node *old, Node *nn ) { temp->init_req(0,nn); // Add a use to nn to prevent him from dying remove_dead_node( old ); temp->del_req(0); // Yank bogus edge - if (nn != NULL && nn->outcnt() == 0) { + if (nn != NULL && nn->outcnt() == 0 && !nn->is_top()) { _worklist.push(nn); } #ifndef PRODUCT
29-04-2021

Thanks for triaging and find this regression! Arm32 is not aviable at my hand. Still trying to setup a cross build environment and see if I can reproduce it on qemu. Basically arm32 turn off TieredCompilation defaultly, it might releated with that, will try turn off TieredCompilation and see if it happens on x64/aarch64 first.
28-04-2021