package org.graalvm.compiler.hotspot.test;
import java.io.IOException;
import java.util.concurrent.locks.ReentrantLock;
import java.util.List;
import org.graalvm.compiler.test.SubprocessUtil;
import org.graalvm.compiler.test.SubprocessUtil.Subprocess;
import org.junit.Assume;
import org.junit.Before;
import org.junit.Test;
public class ReservedStackAccessTest extends HotSpotGraalCompilerTest {
@Before
public void check() {
Assume.assumeTrue(runtime().getVMConfig().enableStackReservedZoneAddress != 0);
}
public void stackAccessTest() {
Assume.assumeTrue(runtime().getVMConfig().enableStackReservedZoneAddress != 0);
int passed = 0;
for (int i = 0; i < 1000; i++) {
RunWithSOEContext r = new RunWithSOEContext(new ReentrantLockTest(), 256);
Thread thread = new Thread(r);
thread.start();
try {
thread.join();
assertTrue(r.result.equals("PASSED"), r.result);
++passed;
} catch (InterruptedException ex) {
}
}
System.out.println("RESULT: " + (passed == 1000 ? "PASSED" : "FAILED"));
}
public static void main(String[] args) {
new ReservedStackAccessTest().stackAccessTest();
}
@Test
public void run() throws IOException, InterruptedException {
Assume.assumeTrue(runtime().getVMConfig().enableStackReservedZoneAddress != 0);
List<String> vmArgs = SubprocessUtil.withoutDebuggerArguments(SubprocessUtil.getVMCommandLine());
vmArgs.add("-XX:+UseJVMCICompiler");
vmArgs.add("-Dgraal.Inline=false");
vmArgs.add("-XX:CompileCommand=exclude,java/util/concurrent/locks/AbstractOwnableSynchronizer.setExclusiveOwnerThread");
vmArgs.add("-Dgraal.CompileGraalWithC1Only=false");
Subprocess proc = SubprocessUtil.java(vmArgs, ReservedStackAccessTest.class.getName());
boolean passed = false;
for (String line : proc.output) {
if (line.equals("RESULT: PASSED")) {
passed = true;
}
}
if (!passed) {
System.err.println(proc);
}
assertTrue(passed);
}
static class ReentrantLockTest {
private ReentrantLock[] lockArray;
private static final int LOCK_ARRAY_SIZE = 8192;
private boolean stackOverflowErrorReceived;
StackOverflowError soe = null;
int index = -1;
public void initialize() {
lockArray = new ReentrantLock[LOCK_ARRAY_SIZE];
for (int i = 0; i < LOCK_ARRAY_SIZE; i++) {
lockArray[i] = new ReentrantLock();
}
stackOverflowErrorReceived = false;
}
public String getResult() {
if (!stackOverflowErrorReceived) {
return "ERROR: Not conclusive test: no StackOverflowError received";
}
for (int i = 0; i < LOCK_ARRAY_SIZE; i++) {
if (lockArray[i].isLocked()) {
if (!lockArray[i].isHeldByCurrentThread()) {
StringBuilder s = new StringBuilder();
s.append("FAILED: ReentrantLock ");
s.append(i);
s.append(" looks corrupted");
return s.toString();
}
}
}
return "PASSED";
}
public void run() {
try {
lockAndCall(0);
} catch (StackOverflowError e) {
soe = e;
stackOverflowErrorReceived = true;
}
}
private void lockAndCall(int i) {
index = i;
if (i < LOCK_ARRAY_SIZE) {
lockArray[i].lock();
lockAndCall(i + 1);
}
}
}
static class RunWithSOEContext implements Runnable {
int counter;
int deframe;
int decounter;
int setupSOEFrame;
int testStartFrame;
ReentrantLockTest test;
String result = "FAILED: no result";
RunWithSOEContext(ReentrantLockTest test, int deframe) {
this.test = test;
this.deframe = deframe;
}
@Override
public void run() {
counter = 0;
decounter = deframe;
test.initialize();
recursiveCall();
System.out.println("Framework got StackOverflowError at frame = " + counter);
System.out.println("Test started execution at frame = " + (counter - deframe));
result = test.getResult();
}
@SuppressWarnings("unused")
void recursiveCall() {
long l1;
long l2;
long l3;
long l4;
long l5;
long l6;
long l7;
long l8;
long l9;
long l10;
long l11;
long l12;
long l13;
long l14;
long l15;
long l16;
long l17;
long l18;
long l19;
long l20;
long l21;
long l22;
long l23;
long l24;
long l25;
long l26;
long l27;
long l28;
long l30;
long l31;
long l32;
long l33;
long l34;
long l35;
long l36;
long l37;
counter++;
try {
recursiveCall();
} catch (StackOverflowError e) {
}
decounter--;
if (decounter == 0) {
setupSOEFrame = counter;
testStartFrame = counter - deframe;
test.run();
}
}
}
}