Similar to JDK-8202952, the failure is caused by a leftover dead node from failing to subsume into a memory operand a shared address expression that is wrongly marked as clonable by x86's implementation of `Matcher::pd_clone_address_expressions`. In this case, the shared address expression consists of two chained `AddP` nodes with a small constant offset each (see before-matching.pdf), a pattern that is wrongly recognized as subsumable into a complex addressing mode by x86's `Matcher::pd_clone_address_expressions`. Accordingly, C2's matcher builds the state tree depicted in match.pdf, where the address expression AddP(AddP ..), ..) is duplicated and matched by two identical Mach instructions (`109 leaPCompressedOopOffset` and `111 leaPCompressedOopOffset`). Similarly to the case in JDK-8202952, the `Expand` method of `108 subI_mem_rReg` selects one of them (`109 leaPCompressedOopOffset`) and leaves the other one (`111 leaPCompressedOopOffset`) dead but referenced from `110 loadConN`'s output set. When GCM visits `110 loadConN`, it assumes that all its outputs have been already assigned a basic block, and causes a segmentation fault when fetching the (unassigned) basic block of `111 leaPCompressedOopOffset`.
A potential solution is to not mark the above pattern (two chained `AddP` nodes with a small constant offset each, see before-matching.pdf) as clonable in x86's implementation of `Matcher::pd_clone_address_expressions`. Note that the pattern should be optimized by `AddPNode::Ideal` into a single `AddP` node with the constant sum of the offsets (in this case it is not, due to JDK-8343067), but it is desirable to not rely on the application of specific optimizations for correctness.
ORIGINAL REPORT:
-------------------------
ADDITIONAL SYSTEM INFORMATION :
# JRE version: Java(TM) SE Runtime Environment (21.0.4+8) (build 21.0.4+8-LTS-274)
# Java VM: Java HotSpot(TM) 64-Bit Server VM (21.0.4+8-LTS-274, mixed mode, sharing, tiered, compressed oops, compressed class ptrs, g1 gc, linux-amd64)
A DESCRIPTION OF THE PROBLEM :
We attempted to use R8 to generate more concise class files. During our attempt, we encountered an issue: when running the R8-processed class files with jdk-21.0.4-oracle, the JVM crashes. The specific crash information is detailed in the hs_err file. We believe this could be an issue with the JDK because it does not occur when using OpenJ9 or JDK-17.
R8 is a code shrinker and obfuscation tool provided by Google for Android. It optimizes Java bytecode into a smaller and more efficient format, reducing the size of applications and improving performance. R8 replaces ProGuard, integrating code shrinking and obfuscation features, and improves compilation efficiency through tight integration with the D8 compiler.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
1. javac Test.java
2. jar cvf classes.jar ./*.class
3. java -cp r8.jar com.android.tools.r8.R8 --pg-conf rules.pro --release --classfile --output ./r8 ./classes.jar
4. java -cp ./r8 Test
```
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
no output
ACTUAL -
#
# A fatal error has been detected by the Java Runtime Environment:
#
# SIGSEGV (0xb) at pc=0x0000712d9ee4251d, pid=467817, tid=467831
#
# JRE version: Java(TM) SE Runtime Environment (21.0.4+8) (build 21.0.4+8-LTS-274)
# Java VM: Java HotSpot(TM) 64-Bit Server VM (21.0.4+8-LTS-274, mixed mode, sharing, tiered, compressed oops, compressed class ptrs, g1 gc, linux-amd64)
# Problematic frame:
# V [libjvm.so+0x84251d] Node_Backward_Iterator::next()+0x11d
#
# Core dump will be written. Default location: Core dumps may be processed with "/usr/share/apport/apport -p%p -s%s -c%c -d%d -P%P -u%u -g%g -- %E" (or dumping to /data/user/proj/core.467817)
#
# An error report file with more information is saved as:
# /data/user/proj/hs_err_pid467817.log
#
# Compiler replay data is saved as:
# /data/user/proj/replay_pid467817.log
#
# If you would like to submit a bug report, please visit:
# https://bugreport.java.com/bugreport/crash.jsp
#
Current CompileTask:
C2: 41 6 % ! 4 Test::main @ 60 (171 bytes)
Stack: [0x0000712d46600000,0x0000712d46700000], sp=0x0000712d466fbf80, free space=1007k
Native frames: (J=compiled Java code, j=interpreted, Vv=VM code, C=native code)
V [libjvm.so+0x84251d] Node_Backward_Iterator::next()+0x11d
V [libjvm.so+0x844999] PhaseCFG::schedule_late(VectorSet&, Node_Stack&)+0x79
V [libjvm.so+0x845161] PhaseCFG::global_code_motion()+0x241
V [libjvm.so+0x84695a] PhaseCFG::do_global_code_motion()+0x4a
V [libjvm.so+0x643e45] Compile::Code_Gen()+0x285
V [libjvm.so+0x648024] Compile::Compile(ciEnv*, ciMethod*, int, Options, DirectiveSet*)+0x1584
V [libjvm.so+0x574d5d] C2Compiler::compile_method(ciEnv*, ciMethod*, int, bool, DirectiveSet*)+0x17d
V [libjvm.so+0x64d7e7] CompileBroker::invoke_compiler_on_method(CompileTask*)+0xa97
V [libjvm.so+0x6508d8] CompileBroker::compiler_thread_loop()+0x6a8
V [libjvm.so+0x8fd9b8] JavaThread::thread_main_inner() [clone .part.0]+0xb8
V [libjvm.so+0xea7848] Thread::call_run()+0xa8
V [libjvm.so+0xcca7da] thread_native_entry(Thread*)+0xda
timeout: the monitored command dumped core
---------- BEGIN SOURCE ----------
class Test {
static int a = 56;
long b;
int c;
int w[];
static int d[] = new int[a];
void e() {
int h[][] = new int[a][a];
long k[] = new long[a];
for (int i = 0; i < h.length; ++i)
for (int j = 0; j < h.length; ++j)
;
long m = 0;
for (int i = 0; i < k.length; ++i)
m = k[i];
}
void r() {
// short t = 4;
int i;
int p = 5;
long q;
for (i = 0; i < 216; i++)
e();
for (q = 1; q < 3; q++)
d[(int) q] -= p;
try {
w[i] = i;
} catch (Throwable throwable) {
}
w = d;
}
public static void main(String[] u) {
Test v = new Test();
for (int i = 0; i < 20; ++i)
v.r();
}
}
---------- END SOURCE ----------