001/*
002 * Copyright (c) 2013, 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 jdk.internal.jvmci.code.*;
026
027import org.junit.*;
028
029import com.oracle.graal.replacements.*;
030import com.oracle.graal.truffle.*;
031import com.oracle.graal.truffle.test.nodes.*;
032import com.oracle.truffle.api.frame.*;
033import com.oracle.truffle.api.nodes.*;
034
035public class SimplePartialEvaluationTest extends PartialEvaluationTest {
036
037    public static Object constant42() {
038        return 42;
039    }
040
041    @Test
042    public void constantValue() {
043        FrameDescriptor fd = new FrameDescriptor();
044        AbstractTestNode result = new ConstantTestNode(42);
045        assertPartialEvalEquals("constant42", new RootTestNode(fd, "constantValue", result));
046    }
047
048    @Test
049    public void addConstants() {
050        FrameDescriptor fd = new FrameDescriptor();
051        AbstractTestNode result = new AddTestNode(new ConstantTestNode(40), new ConstantTestNode(2));
052        assertPartialEvalEquals("constant42", new RootTestNode(fd, "addConstants", result));
053    }
054
055    @Test
056    public void neverPartOfCompilationTest() {
057        FrameDescriptor fd = new FrameDescriptor();
058        AbstractTestNode firstTree = new NeverPartOfCompilationTestNode(new ConstantTestNode(1), 2);
059        assertPartialEvalEquals("constant42", new RootTestNode(fd, "neverPartOfCompilationTest", firstTree));
060
061        AbstractTestNode secondTree = new NeverPartOfCompilationTestNode(new ConstantTestNode(1), 1);
062        try {
063            assertPartialEvalEquals("constant42", new RootTestNode(fd, "neverPartOfCompilationTest", secondTree));
064            Assert.fail("Expected verification error!");
065        } catch (SourceStackTrace t) {
066            // Expected verification error occurred.
067            StackTraceElement[] trace = t.getStackTrace();
068            Assert.assertTrue(trace[0].toString().startsWith("com.oracle.graal.truffle.test.nodes.NeverPartOfCompilationTestNode.execute(NeverPartOfCompilationTestNode.java:"));
069            Assert.assertTrue(trace[1].toString().startsWith("com.oracle.graal.truffle.test.nodes.RootTestNode.execute(RootTestNode.java:"));
070        }
071    }
072
073    @Test
074    public void nestedLoopExplosion() {
075        FrameDescriptor fd = new FrameDescriptor();
076        AbstractTestNode result = new AddTestNode(new NestedExplodedLoopTestNode(5), new ConstantTestNode(17));
077        assertPartialEvalEquals("constant42", new RootTestNode(fd, "nestedLoopExplosion", result));
078    }
079
080    @Test
081    public void twoMergesLoopExplosion() {
082        FrameDescriptor fd = new FrameDescriptor();
083        AbstractTestNode result = new AddTestNode(new TwoMergesExplodedLoopTestNode(5), new ConstantTestNode(37));
084        assertPartialEvalEquals("constant42", new RootTestNode(fd, "nestedLoopExplosion", result));
085    }
086
087    @Test
088    public void sequenceConstants() {
089        FrameDescriptor fd = new FrameDescriptor();
090        AbstractTestNode result = new BlockTestNode(new AbstractTestNode[]{new ConstantTestNode(40), new ConstantTestNode(42)});
091        assertPartialEvalEquals("constant42", new RootTestNode(fd, "sequenceConstants", result));
092    }
093
094    @Test
095    public void localVariable() {
096        FrameDescriptor fd = new FrameDescriptor();
097        AbstractTestNode result = new BlockTestNode(new AbstractTestNode[]{new StoreLocalTestNode("x", fd, new ConstantTestNode(42)), new LoadLocalTestNode("x", fd)});
098        assertPartialEvalEquals("constant42", new RootTestNode(fd, "localVariable", result));
099    }
100
101    @Test
102    public void longSequenceConstants() {
103        FrameDescriptor fd = new FrameDescriptor();
104        int length = 40;
105        AbstractTestNode[] children = new AbstractTestNode[length];
106        for (int i = 0; i < children.length; ++i) {
107            children[i] = new ConstantTestNode(42);
108        }
109
110        AbstractTestNode result = new BlockTestNode(children);
111        assertPartialEvalEquals("constant42", new RootTestNode(fd, "longSequenceConstants", result));
112    }
113
114    @Test
115    public void longAddConstants() {
116        FrameDescriptor fd = new FrameDescriptor();
117        AbstractTestNode result = new ConstantTestNode(2);
118        for (int i = 0; i < 20; ++i) {
119            result = new AddTestNode(result, new ConstantTestNode(2));
120        }
121        assertPartialEvalEquals("constant42", new RootTestNode(fd, "longAddConstants", result));
122    }
123
124    @Test
125    public void mixLocalAndAdd() {
126        FrameDescriptor fd = new FrameDescriptor();
127        AbstractTestNode result = new BlockTestNode(new AbstractTestNode[]{new StoreLocalTestNode("x", fd, new ConstantTestNode(40)),
128                        new StoreLocalTestNode("x", fd, new AddTestNode(new LoadLocalTestNode("x", fd), new ConstantTestNode(2))), new LoadLocalTestNode("x", fd)});
129        assertPartialEvalEquals("constant42", new RootTestNode(fd, "mixLocalAndAdd", result));
130    }
131
132    @Test
133    public void loop() {
134        FrameDescriptor fd = new FrameDescriptor();
135        AbstractTestNode result = new BlockTestNode(new AbstractTestNode[]{new StoreLocalTestNode("x", fd, new ConstantTestNode(0)),
136                        new LoopTestNode(7, new StoreLocalTestNode("x", fd, new AddTestNode(new LoadLocalTestNode("x", fd), new ConstantTestNode(6))))});
137        assertPartialEvalEquals("constant42", new RootTestNode(fd, "loop", result));
138    }
139
140    @Test
141    public void longLoop() {
142        FrameDescriptor fd = new FrameDescriptor();
143        AbstractTestNode result = new BlockTestNode(new AbstractTestNode[]{new StoreLocalTestNode("x", fd, new ConstantTestNode(0)),
144                        new LoopTestNode(42, new StoreLocalTestNode("x", fd, new AddTestNode(new LoadLocalTestNode("x", fd), new ConstantTestNode(1))))});
145        RootTestNode rootNode = new RootTestNode(fd, "loop", result);
146        assertPartialEvalNoInvokes(rootNode);
147        assertPartialEvalEquals("constant42", rootNode);
148    }
149
150    @Test
151    public void lambda() {
152        FrameDescriptor fd = new FrameDescriptor();
153        AbstractTestNode result = new LambdaTestNode();
154        assertPartialEvalEquals("constant42", new RootTestNode(fd, "constantValue", result));
155    }
156
157    @Test
158    public void allowedRecursion() {
159        /* Recursion depth just below the threshold that reports it as too deep recursion. */
160        FrameDescriptor fd = new FrameDescriptor();
161        AbstractTestNode result = new RecursionTestNode(PEGraphDecoder.Options.InliningDepthError.getValue() - 5);
162        assertPartialEvalEquals("constant42", new RootTestNode(fd, "allowedRecursion", result));
163    }
164
165    @Test(expected = BailoutException.class)
166    public void tooDeepRecursion() {
167        /* Recursion depth just above the threshold that reports it as too deep recursion. */
168        FrameDescriptor fd = new FrameDescriptor();
169        AbstractTestNode result = new RecursionTestNode(PEGraphDecoder.Options.InliningDepthError.getValue());
170        assertPartialEvalEquals("constant42", new RootTestNode(fd, "tooDeepRecursion", result));
171    }
172
173    @Test
174    public void intrinsicStatic() {
175        /*
176         * The intrinsic for String.equals() is inlined early during bytecode parsing, because we
177         * call equals() on a value that has the static type String.
178         */
179        FrameDescriptor fd = new FrameDescriptor();
180        AbstractTestNode result = new StringEqualsNode("abc", "abf");
181        RootNode rootNode = new RootTestNode(fd, "intrinsicStatic", result);
182        OptimizedCallTarget compilable = compileHelper("intrinsicStatic", rootNode, new Object[0]);
183
184        Assert.assertEquals(42, compilable.call(new Object[0]));
185    }
186
187    @Test
188    public void intrinsicVirtual() {
189        /*
190         * The intrinsic for String.equals() is inlined late during Truffle partial evaluation,
191         * because we call equals() on a value that has the static type Object, but during partial
192         * evaluation the more precise type String is known.
193         */
194        FrameDescriptor fd = new FrameDescriptor();
195        AbstractTestNode result = new ObjectEqualsNode("abc", "abf");
196        RootNode rootNode = new RootTestNode(fd, "intrinsicVirtual", result);
197        OptimizedCallTarget compilable = compileHelper("intrinsicVirtual", rootNode, new Object[0]);
198
199        Assert.assertEquals(42, compilable.call(new Object[0]));
200    }
201}