I witnessed random fail of one jcstress test on my 128-core aarch64 server: "org.openjdk.jcstress.tests.defaultValues.arrays.small.plain.StringTest"
I used the latest aarch64 jdk8u release build.
Command line: java -jar /home/yangfei/tools/jcstress-tests-all-20191016.jar -jvmArgs "-XX:TieredStopAtLevel=1" -t "org.openjdk.jcstress.tests.defaultValues.arrays.small.plain.StringTest" -time 5000
Error messages:
[ERROR] o.o.j.t.defaultValues.arrays.small.plain.StringTest
Messages:
Unrecoverable error while running
java.lang.ArrayIndexOutOfBoundsException: 0
at org.openjdk.jcstress.tests.defaultValues.arrays.small.plain.StringTest.actor2(StringTest.java:55)
at org.openjdk.jcstress.tests.defaultValues.arrays.small.plain.StringTest_jcstress.actor2(StringTest_jcstress.java:193)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
The jcsress test looks like:
@JCStressTest
@Outcome.Outcomes({@Outcome(
id = {"null, null, null, null"},
expect = Expect.ACCEPTABLE,
desc = "Default value for the element."
), @Outcome(
expect = Expect.FORBIDDEN,
desc = "Non-default values are forbidden."
)})
@State
public class StringTest {
String[] arr;
@Actor
public void actor1() {
this.arr = new String[4];
}
@Actor
public void actor2(LLLL_Result r) {
String[] a = this.arr;
if (a == null) {
r.r1 = r.r2 = r.r3 = r.r4 = null;
} else {
r.r1 = a[0]; <==== throws exception here
r.r2 = a[1];
r.r3 = a[2];
r.r4 = a[3];
}
}
}
From the error message, looks like we are using an array before the initialization of it finished.
I even reproduced the random failure with a similar case:
public class ThreadTest {
public static String[] arr;
public static String r1, r2, r3, r4;
static class FirstThread extends Thread {
public void actor1() {
ThreadTest.arr = new String[4];
}
public void run() {
while (true) {
actor1();
}
}
}
static class SecondThread extends Thread {
public void actor2() {
String[] a = ThreadTest.arr;
if (a == null) {
ThreadTest.r1 = null;
ThreadTest.r2 = null;
ThreadTest.r3 = null;
ThreadTest.r4 = null;
} else {
ThreadTest.r1 = a[0];
ThreadTest.r2 = a[1];
ThreadTest.r3 = a[2];
ThreadTest.r4 = a[3];
}
}
public void run() {
while (true) {
actor2();
}
}
}
public static void main(String args[]) {
FirstThread t1 = new FirstThread();
SecondThread t2 = new SecondThread();
t1.start();
t2.start();
try {
t1.join();
t2.join();
} catch (InterruptedException e) {
System.out.println("INTERRUPTED_MESSAGE");
}
System.out.println("PASS");
}
}
Command line: java -XX:TieredStopAtLevel=1 ThreadTest
Error message:
Exception in thread "Thread-1" java.lang.ArrayIndexOutOfBoundsException: 0
at ThreadTest$SecondThread.actor2(ThreadTest.java:26)
at ThreadTest$SecondThread.run(ThreadTest.java:35)
JIT code for actor1:
Compiled method (c1) 310 16 1 ThreadTest$FirstThread::actor1 (8 bytes)
total in heap [0x0000ffff904cbc50,0x0000ffff904cbff8] = 936
relocation [0x0000ffff904cbd70,0x0000ffff904cbd88] = 24
main code [0x0000ffff904cbdc0,0x0000ffff904cbf40] = 384
stub code [0x0000ffff904cbf40,0x0000ffff904cbf50] = 16
oops [0x0000ffff904cbf50,0x0000ffff904cbf60] = 16
metadata [0x0000ffff904cbf60,0x0000ffff904cbf70] = 16
scopes data [0x0000ffff904cbf70,0x0000ffff904cbf90] = 32
scopes pcs [0x0000ffff904cbf90,0x0000ffff904cbff0] = 96
dependencies [0x0000ffff904cbff0,0x0000ffff904cbff8] = 8
Loaded disassembler from /home/yangfei/jdk8u-release/jvm/openjdk-1.8.0-internal/jre/lib/aarch64/server/hsdis-aarch64.so
Decoding compiled method 0x0000ffff904cbc50:
Code:
[Disassembling for mach='aarch64']
[Entry Point]
[Constants]
# {method} {0x0000ffff81b57880} 'actor1' '()V' in 'ThreadTest$FirstThread'
# [sp+0x40] (sp of caller)
0x0000ffff904cbdc0: ldr w8, [x1,#8]
0x0000ffff904cbdc4: cmp w9, w8
0x0000ffff904cbdc8: b.eq 0x0000ffff904cbe00
0x0000ffff904cbdcc: b 0x0000ffff900b1ec0 ; {runtime_call}
0x0000ffff904cbdd0: nop
0x0000ffff904cbdd4: nop
0x0000ffff904cbdd8: nop
0x0000ffff904cbddc: nop
0x0000ffff904cbde0: nop
0x0000ffff904cbde4: nop
0x0000ffff904cbde8: nop
0x0000ffff904cbdec: nop
0x0000ffff904cbdf0: nop
0x0000ffff904cbdf4: nop
0x0000ffff904cbdf8: nop
0x0000ffff904cbdfc: nop
[Verified Entry Point]
0x0000ffff904cbe00: nop
0x0000ffff904cbe04: orr x9, xzr, #0xffffffffffffc000
0x0000ffff904cbe08: str xzr, [sp,x9]
0x0000ffff904cbe0c: sub sp, sp, #0x40
0x0000ffff904cbe10: stp x29, x30, [sp,#48] ;*iconst_4
; - ThreadTest$FirstThread::actor1@0 (line 7)
0x0000ffff904cbe14: orr w19, wzr, #0x4
0x0000ffff904cbe18: mov x3, #0xaf08 // #44808
; {metadata('java/lang/String'[])}
0x0000ffff904cbe1c: movk x3, #0x1, lsl #16
0x0000ffff904cbe20: movk x3, #0x8, lsl #32
0x0000ffff904cbe24: ubfx x19, x19, #0, #32
0x0000ffff904cbe28: mov x5, x19
0x0000ffff904cbe2c: mov x8, #0xffffff // #16777215
0x0000ffff904cbe30: cmp x19, x8
0x0000ffff904cbe34: b.cs 0x0000ffff904cbf0c
0x0000ffff904cbe38: mov x4, #0x17 // #23
0x0000ffff904cbe3c: add x4, x4, w19, uxtw #2
0x0000ffff904cbe40: and x4, x4, #0xfffffffffffffff8
0x0000ffff904cbe44: ldr x0, [x28,#96]
0x0000ffff904cbe48: add x4, x0, x4, uxtx
0x0000ffff904cbe4c: ldr x8, [x28,#112]
0x0000ffff904cbe50: cmp x4, x8
0x0000ffff904cbe54: b.hi 0x0000ffff904cbf0c
0x0000ffff904cbe58: str x4, [x28,#96]
0x0000ffff904cbe5c: sub x4, x4, x0
0x0000ffff904cbe60: orr x2, xzr, #0x1
0x0000ffff904cbe64: str x2, [x0]
0x0000ffff904cbe68: eor x2, x3, #0x800000000
0x0000ffff904cbe6c: str w2, [x0,#8]
0x0000ffff904cbe70: str w19, [x0,#12]
0x0000ffff904cbe74: subs x4, x4, #0x10
0x0000ffff904cbe78: b.eq 0x0000ffff904cbecc
0x0000ffff904cbe7c: add x0, x0, #0x10
0x0000ffff904cbe80: lsr x4, x4, #3
0x0000ffff904cbe84: and x8, x4, #0x7
0x0000ffff904cbe88: sub x4, x4, x8
0x0000ffff904cbe8c: add x19, x0, x8, lsl #3
0x0000ffff904cbe90: adr x9, 0x0000ffff904cbec0
0x0000ffff904cbe94: sub x9, x9, x8, lsl #2
0x0000ffff904cbe98: br x9
0x0000ffff904cbe9c: sub x4, x4, #0x8
0x0000ffff904cbea0: str xzr, [x19,#-64]
0x0000ffff904cbea4: str xzr, [x19,#-56]
0x0000ffff904cbea8: str xzr, [x19,#-48]
0x0000ffff904cbeac: str xzr, [x19,#-40]
0x0000ffff904cbeb0: str xzr, [x19,#-32]
0x0000ffff904cbeb4: str xzr, [x19,#-24]
0x0000ffff904cbeb8: str xzr, [x19,#-16]
0x0000ffff904cbebc: str xzr, [x19,#-8]
0x0000ffff904cbec0: add x19, x19, #0x40
0x0000ffff904cbec4: cbnz x4, 0x0000ffff904cbe9c
0x0000ffff904cbec8: sub x0, x0, #0x10
0x0000ffff904cbecc: dmb ishst ;*anewarray
; - ThreadTest$FirstThread::actor1@1 (line 7)
0x0000ffff904cbed0: mov x1, #0x22c0 // #8896
; {oop(a 'java/lang/Class' = 'ThreadTest')}
0x0000ffff904cbed4: movk x1, #0x8016, lsl #16
0x0000ffff904cbed8: movk x1, #0x5, lsl #32
0x0000ffff904cbedc: lsr x8, x0, #3
0x0000ffff904cbee0: str w8, [x1,#104]
0x0000ffff904cbee4: lsr x0, x1, #9
0x0000ffff904cbee8: mov x1, #0xf000 // #61440
0x0000ffff904cbeec: movk x1, #0x8bff, lsl #16
0x0000ffff904cbef0: movk x1, #0xffff, lsl #32
0x0000ffff904cbef4: strb wzr, [x0,x1,lsl #0] ;*putstatic arr
; - ThreadTest$FirstThread::actor1@4 (line 7)
0x0000ffff904cbef8: ldp x29, x30, [sp,#48]
0x0000ffff904cbefc: add sp, sp, #0x40
0x0000ffff904cbf00: adrp x8, 0x0000ffffa02e3000
; {poll_return}
0x0000ffff904cbf04: ldr wzr, [x8] ; {poll_return}
0x0000ffff904cbf08: ret
0x0000ffff904cbf0c: bl 0x0000ffff900dcf80 ; OopMap{off=336} < =================== slow path
;*anewarray
; - ThreadTest$FirstThread::actor1@1 (line 7)
; {runtime_call}
0x0000ffff904cbf10: b 0x0000ffff904cbed0
0x0000ffff904cbf14: nop
0x0000ffff904cbf18: nop
0x0000ffff904cbf1c: ldr x0, [x28,#784]
0x0000ffff904cbf20: str xzr, [x28,#784]
0x0000ffff904cbf24: str xzr, [x28,#792]
0x0000ffff904cbf28: ldp x29, x30, [sp,#48]
0x0000ffff904cbf2c: add sp, sp, #0x40
0x0000ffff904cbf30: b 0x0000ffff900defc0 ; {runtime_call}
0x0000ffff904cbf34: .inst 0x00000000 ; undefined
0x0000ffff904cbf38: .inst 0x00000000 ; undefined
0x0000ffff904cbf3c: .inst 0x00000000 ; undefined
[Exception Handler]
[Stub Code]
0x0000ffff904cbf40: bl 0x0000ffff900dc8c0 ; {no_reloc}
[Deopt Handler Code]
0x0000ffff904cbf44: adr x30, 0x0000ffff904cbf44
0x0000ffff904cbf48: b 0x0000ffff900b35c0 ; {runtime_call}
0x0000ffff904cbf4c: .inst 0x00000000 ; undefined
OopMapSet contains 1 OopMaps
#0
OopMap{off=336}
As there is a StoreStore memory barrier for the fast path, I looks into the slow path here.
Obviously, the StoreStore memory barrier is missing for the slow path.
Patch for aarch64 8u:
diff -r 02145a45eff6 src/cpu/aarch64/vm/c1_Runtime1_aarch64.cpp
--- a/src/cpu/aarch64/vm/c1_Runtime1_aarch64.cpp Mon Nov 05 12:53:55 2018 +0100
+++ b/src/cpu/aarch64/vm/c1_Runtime1_aarch64.cpp Fri Nov 08 11:05:48 2019 +0800
@@ -877,6 +877,7 @@
__ sub(arr_size, arr_size, t1); // body length
__ add(t1, t1, obj); // body start
__ initialize_body(t1, arr_size, 0, t2);
+ __ membar(Assembler::StoreStore);
__ verify_oop(obj);
__ ret(lr);
@@ -905,6 +906,7 @@
__ sub(arr_size, arr_size, t1); // body length
__ add(t1, t1, obj); // body start
__ initialize_body(t1, arr_size, 0, t2);
+ __ membar(Assembler::StoreStore);
__ verify_oop(obj);
__ ret(lr);
Patch for 14 and 11u:
diff -r ad157fab6bf5 src/hotspot/cpu/aarch64/c1_Runtime1_aarch64.cpp
--- a/src/hotspot/cpu/aarch64/c1_Runtime1_aarch64.cpp Thu Nov 07 16:26:57 2019 -0800
+++ b/src/hotspot/cpu/aarch64/c1_Runtime1_aarch64.cpp Fri Nov 08 16:10:08 2019 +0800
@@ -840,6 +840,7 @@
__ sub(arr_size, arr_size, t1); // body length
__ add(t1, t1, obj); // body start
__ initialize_body(t1, arr_size, 0, t2);
+ __ membar(Assembler::StoreStore);
__ verify_oop(obj);
__ ret(lr);