001/*
002 * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004 *
005 * This code is free software; you can redistribute it and/or modify it
006 * under the terms of the GNU General Public License version 2 only, as
007 * published by the Free Software Foundation.
008 *
009 * This code is distributed in the hope that it will be useful, but WITHOUT
010 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
011 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
012 * version 2 for more details (a copy is included in the LICENSE file that
013 * accompanied this code).
014 *
015 * You should have received a copy of the GNU General Public License version
016 * 2 along with this work; if not, write to the Free Software Foundation,
017 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
018 *
019 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
020 * or visit www.oracle.com if you need additional information or have any
021 * questions.
022 */
023package com.oracle.graal.truffle.test;
024
025import org.junit.*;
026
027import com.oracle.graal.truffle.*;
028import com.oracle.graal.truffle.test.nodes.*;
029import com.oracle.truffle.api.*;
030import com.oracle.truffle.api.frame.*;
031import com.oracle.truffle.api.nodes.*;
032
033public class ControlFlowExceptionPartialEvaluationTest extends PartialEvaluationTest {
034    public static Object constant42() {
035        return 42;
036    }
037
038    @Test
039    public void catchControlFlowException() {
040        FrameDescriptor fd = new FrameDescriptor();
041        AbstractTestNode result = new CatchControlFlowExceptionTestNode(new ThrowControlFlowExceptionTestNode());
042        assertPartialEvalEquals("constant42", new RootTestNode(fd, "catchControlFlowException", result));
043    }
044
045    @Test
046    public void catchSlowPathAndControlFlowException() {
047        FrameDescriptor fd = new FrameDescriptor();
048        AbstractTestNode result = new CatchSlowPathAndControlFlowExceptionTestNode(new ThrowControlFlowExceptionTestNode());
049        assertPartialEvalEquals("constant42", new RootTestNode(fd, "catchSlowPathAndControlFlowException", result));
050    }
051
052    @Test
053    public void catchControlFlowExceptionWithLoopExplosion() {
054        FrameDescriptor fd = new FrameDescriptor();
055        AbstractTestNode result = new CatchControlFlowExceptionTestNode(new BlockTestNode(new ThrowControlFlowExceptionTestNode()));
056        assertPartialEvalEquals("constant42", new RootTestNode(fd, "catchControlFlowExceptionWithLoopExplosion", result));
057    }
058
059    @Test
060    public void catchControlFlowExceptionFromCall() {
061        Assume.assumeTrue(TruffleCompilerOptions.TruffleFunctionInlining.getValue());
062        CallTarget callTarget = Truffle.getRuntime().createCallTarget(new RootTestNode(new FrameDescriptor(), "throwControlFlowException", new ThrowControlFlowExceptionTestNode()));
063        AbstractTestNode result = new CatchControlFlowExceptionTestNode(new CallTestNode(callTarget));
064        assertPartialEvalEquals("constant42", new RootTestNode(new FrameDescriptor(), "catchControlFlowExceptionFromCall", result));
065    }
066
067    public static class ThrowControlFlowExceptionTestNode extends AbstractTestNode {
068        @Override
069        public int execute(VirtualFrame frame) {
070            throw new ControlFlowException();
071        }
072    }
073
074    public static class CatchControlFlowExceptionTestNode extends AbstractTestNode {
075        @Child private AbstractTestNode child;
076
077        public CatchControlFlowExceptionTestNode(AbstractTestNode child) {
078            this.child = child;
079        }
080
081        @Override
082        public int execute(VirtualFrame frame) {
083            try {
084                return child.execute(frame);
085            } catch (ControlFlowException e) {
086                return 42;
087            }
088        }
089    }
090
091    public static class CatchSlowPathAndControlFlowExceptionTestNode extends AbstractTestNode {
092        @Child private AbstractTestNode child;
093
094        public CatchSlowPathAndControlFlowExceptionTestNode(AbstractTestNode child) {
095            this.child = child;
096        }
097
098        @Override
099        public int execute(VirtualFrame frame) {
100            try {
101                return executeChild(frame);
102            } catch (SlowPathException spe) {
103                return -1;
104            } catch (ControlFlowException e) {
105                return 42;
106            }
107        }
108
109        @SuppressWarnings("unused")
110        private int executeChild(VirtualFrame frame) throws SlowPathException {
111            return child.execute(frame);
112        }
113    }
114
115    public static class BlockTestNode extends AbstractTestNode {
116        @Children private final AbstractTestNode[] statements;
117
118        public BlockTestNode(AbstractTestNode... statements) {
119            this.statements = statements;
120        }
121
122        @Override
123        public int execute(VirtualFrame frame) {
124            return executeSpecial(frame);
125        }
126
127        /*
128         * A statically resolvable method, so that ExplodeLoop annotation is visible during parsing.
129         */
130        @ExplodeLoop
131        private int executeSpecial(VirtualFrame frame) {
132            int result = 0;
133            for (AbstractTestNode statement : statements) {
134                result = statement.execute(frame);
135            }
136            return result;
137        }
138    }
139
140    public static class CallTestNode extends AbstractTestNode {
141        @Child private DirectCallNode callNode;
142
143        public CallTestNode(CallTarget callTarget) {
144            this.callNode = Truffle.getRuntime().createDirectCallNode(callTarget);
145        }
146
147        @Override
148        public int execute(VirtualFrame frame) {
149            return (int) callNode.call(frame, new Object[0]);
150        }
151    }
152}