src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/ReservedStackAccessTest.java
changeset 51126 a25c48c0a1ab
child 54084 84f10bbf993f
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/ReservedStackAccessTest.java	Mon Jul 16 15:09:19 2018 -0700
@@ -0,0 +1,226 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+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++) {
+            // Each iteration has to be executed by a new thread. The test
+            // relies on the random size area pushed by the VM at the beginning
+            // of the stack of each Java thread it creates.
+            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");
+        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) {
+            for (String line : proc.output) {
+                System.err.println("" + line);
+            }
+        }
+        assertTrue(passed);
+    }
+
+    static class ReentrantLockTest {
+
+        private ReentrantLock[] lockArray;
+        // Frame sizes vary a lot between interpreted code and compiled code
+        // so the lock array has to be big enough to cover all cases.
+        // If test fails with message "Not conclusive test", try to increase
+        // LOCK_ARRAY_SIZE value
+        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() {
+            // Unused local variables to increase the frame size
+            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();
+            }
+        }
+    }
+
+}