changeset 22904:4baa8603ae7c

Add SafepointRethrowDeoptPETest
author Gilles Duboscq <gilles.m.duboscq@oracle.com>
date Thu, 29 Oct 2015 13:53:23 +0100
parents 217a942e3603
children 463553e69619
files graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/SafepointRethrowDeoptPETest.java
diffstat 1 files changed, 232 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/SafepointRethrowDeoptPETest.java	Thu Oct 29 13:53:23 2015 +0100
@@ -0,0 +1,232 @@
+/*
+ * Copyright (c) 2015, 2015, 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 com.oracle.graal.truffle.test;
+
+import java.util.concurrent.CountDownLatch;
+
+import org.junit.Assert;
+import org.junit.Assume;
+import org.junit.Test;
+
+import com.oracle.graal.compiler.common.GraalOptions;
+import com.oracle.graal.truffle.OptimizedCallTarget;
+import com.oracle.truffle.api.frame.VirtualFrame;
+import com.oracle.truffle.api.nodes.Node;
+import com.oracle.truffle.api.nodes.RootNode;
+
+public class SafepointRethrowDeoptPETest extends PartialEvaluationTest {
+
+    static final Object RETURN_VALUE = "1 2 3";
+    static final RuntimeException BREAK_EX = new RuntimeException();
+    static final RuntimeException CONTINUE_EX = new RuntimeException();
+    static volatile int terminate;
+    static volatile int entered;
+
+    public static class Test0RootNode extends RootNode {
+        public Test0RootNode() {
+            super(MockLanguage.class, null, null);
+        }
+
+        @Override
+        public Object execute(VirtualFrame frame) {
+            entered = 1;
+            for (;;) {
+                try {
+                    if (terminate != 0) {
+                        throw BREAK_EX;
+                    } else {
+                        throw CONTINUE_EX;
+                    }
+                } catch (RuntimeException e) {
+                    if (e == BREAK_EX) {
+                        break;
+                    } else if (e == CONTINUE_EX) {
+                        continue;
+                    }
+                    throw e;
+                }
+            }
+            return RETURN_VALUE;
+        }
+    }
+
+    public abstract static class TestNode extends Node {
+        public abstract void executeVoid();
+    }
+
+    public static class ThrowNode extends TestNode {
+        private final RuntimeException exception;
+
+        public ThrowNode(RuntimeException exception) {
+            this.exception = exception;
+        }
+
+        @Override
+        public void executeVoid() {
+            throw exception;
+        }
+    }
+
+    public static class Test1RootNode extends RootNode {
+        @Child private ThrowNode throwBreak = new ThrowNode(BREAK_EX);
+        @Child private ThrowNode throwContinue = new ThrowNode(CONTINUE_EX);
+
+        public Test1RootNode() {
+            super(MockLanguage.class, null, null);
+        }
+
+        @Override
+        public Object execute(VirtualFrame frame) {
+            entered = 1;
+            for (;;) {
+                try {
+                    if (terminate != 0) {
+                        throwBreak.executeVoid();
+                    } else {
+                        throwContinue.executeVoid();
+                    }
+                } catch (RuntimeException e) {
+                    if (e == BREAK_EX) {
+                        break;
+                    } else if (e == CONTINUE_EX) {
+                        continue;
+                    }
+                    throw e;
+                }
+            }
+            return RETURN_VALUE;
+        }
+    }
+
+    public static class BreakOrContinueNode extends TestNode {
+        @Child private ThrowNode throwBreak = new ThrowNode(BREAK_EX);
+        @Child private ThrowNode throwContinue = new ThrowNode(CONTINUE_EX);
+
+        @Override
+        public void executeVoid() {
+            if (terminate != 0) {
+                throwBreak.executeVoid();
+            } else {
+                throwContinue.executeVoid();
+            }
+        }
+    }
+
+    public static class ExceptionTargetNode extends TestNode {
+        @Child private TestNode body;
+        private final RuntimeException exception;
+
+        public ExceptionTargetNode(RuntimeException exception, TestNode body) {
+            this.body = body;
+            this.exception = exception;
+        }
+
+        @Override
+        public void executeVoid() {
+            try {
+                body.executeVoid();
+            } catch (RuntimeException e) {
+                if (e != exception) {
+                    throw e;
+                }
+            }
+        }
+    }
+
+    public static class LoopNode extends TestNode {
+        @Child private TestNode body;
+
+        public LoopNode(TestNode body) {
+            this.body = body;
+        }
+
+        @Override
+        public void executeVoid() {
+            for (;;) {
+                body.executeVoid();
+            }
+        }
+    }
+
+    public static class Test2RootNode extends RootNode {
+        @Child private TestNode body;
+
+        public Test2RootNode() {
+            super(MockLanguage.class, null, null);
+            this.body = new ExceptionTargetNode(BREAK_EX, new LoopNode(new ExceptionTargetNode(CONTINUE_EX, new BreakOrContinueNode())));
+        }
+
+        @Override
+        public Object execute(VirtualFrame frame) {
+            entered = 1;
+            body.executeVoid();
+            return RETURN_VALUE;
+        }
+    }
+
+    @Test
+    public void test() {
+        Assume.assumeTrue(GraalOptions.GenLoopSafepoints.getValue());
+        synchronized (SafepointRethrowDeoptPETest.class) { // safeguard static fields
+            testInner(new Test0RootNode());
+            testInner(new Test1RootNode());
+            testInner(new Test2RootNode());
+        }
+    }
+
+    private void testInner(RootNode rootNode) {
+        terminate = 1; // executed 3 times
+        OptimizedCallTarget compiledMethod = compileHelper(rootNode.getClass().getSimpleName(), rootNode, new Object[0]);
+
+        terminate = 0;
+        entered = 0;
+        CountDownLatch cdl = new CountDownLatch(1);
+        Thread t1 = new Thread(() -> {
+            try {
+                cdl.await();
+                while (entered == 0) {
+                    /* spin */
+                }
+                /* Thread.sleep(100); */
+                compiledMethod.invalidate();
+            } catch (InterruptedException e) {
+                Assert.fail("interrupted");
+            }
+            terminate = 1;
+        });
+        Thread t2 = new Thread(() -> {
+            cdl.countDown();
+            Object result = compiledMethod.call();
+            Assert.assertEquals(RETURN_VALUE, result);
+        });
+
+        t1.start();
+        t2.start();
+        try {
+            t1.join();
+            t2.join();
+        } catch (InterruptedException e) {
+            Assert.fail("interrupted");
+        }
+    }
+}