Mercurial > hg > graal-compiler
changeset 13810:44bcfc983adb
Merge.
author | Christian Humer <christian.humer@gmail.com> |
---|---|
date | Wed, 29 Jan 2014 12:19:03 +0100 |
parents | 030e75d4d7dc (diff) 8cd953e97e2d (current diff) |
children | 641f22b1c6b8 |
files | graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILCompilationResult.java graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerImpl.java |
diffstat | 17 files changed, 543 insertions(+), 399 deletions(-) [+] |
line wrap: on
line diff
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallTarget.java Wed Jan 29 09:21:50 2014 +0100 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallTarget.java Wed Jan 29 12:19:03 2014 +0100 @@ -262,7 +262,7 @@ int notInlinedCallSiteCount = TruffleInliningImpl.getInlinableCallSites(callTarget).size(); int nodeCount = NodeUtil.countNodes(callTarget.getRootNode()); - int inlinedCallSiteCount = NodeUtil.countNodes(callTarget.getRootNode(), InlinedCallSite.class); + int inlinedCallSiteCount = countInlinedNodes(callTarget.getRootNode()); String comment = callTarget.installedCode == null ? " int" : ""; comment += callTarget.compilationEnabled ? "" : " fail"; OUT.printf("%-50s | %10d | %15d | %15d | %10d | %3d%s\n", callTarget.getRootNode(), callTarget.callCount, inlinedCallSiteCount, notInlinedCallSiteCount, nodeCount, @@ -277,6 +277,17 @@ OUT.printf("%-50s | %10d | %15d | %15d | %10d | %3d\n", "Total", totalCallCount, totalInlinedCallSiteCount, totalNotInlinedCallSiteCount, totalNodeCount, totalInvalidationCount); } + private static int countInlinedNodes(Node rootNode) { + List<CallNode> callers = NodeUtil.findAllNodeInstances(rootNode, CallNode.class); + int count = 0; + for (CallNode callNode : callers) { + if (callNode.isInlined()) { + count++; + } + } + return count; + } + private static void registerCallTarget(OptimizedCallTarget callTarget) { callTargets.put(callTarget, 0); }
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerImpl.java Wed Jan 29 09:21:50 2014 +0100 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerImpl.java Wed Jan 29 12:19:03 2014 +0100 @@ -185,13 +185,15 @@ private class InlineTreeVisitor implements NodeVisitor { public boolean visit(Node node) { - if (node instanceof InlinedCallSite) { - InlinedCallSite inlinedCallSite = (InlinedCallSite) node; - int indent = this.indent(node); - for (int i = 0; i < indent; ++i) { - OUT.print(" "); + if (node instanceof CallNode) { + CallNode callNode = (CallNode) node; + if (callNode.isInlined()) { + int indent = this.indent(node); + for (int i = 0; i < indent; ++i) { + OUT.print(" "); + } + OUT.println(callNode.getCallTarget()); } - OUT.println(inlinedCallSite.getCallTarget()); } return true; } @@ -199,7 +201,7 @@ private int indent(Node n) { if (n instanceof RootNode) { return 0; - } else if (n instanceof InlinedCallSite) { + } else if (n instanceof CallNode && ((CallNode) n).isInlined()) { return indent(n.getParent()) + 1; } else { return indent(n.getParent());
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleInliningImpl.java Wed Jan 29 09:21:50 2014 +0100 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleInliningImpl.java Wed Jan 29 12:19:03 2014 +0100 @@ -73,7 +73,7 @@ if (!policy.isWorthInlining(inlinableCallSite)) { break; } - if (inlinableCallSite.getCallSite().inline(target)) { + if (inlinableCallSite.getCallSite().inline()) { if (TraceTruffleInlining.getValue()) { printCallSiteInfo(policy, inlinableCallSite, "inlined"); } @@ -84,7 +84,9 @@ if (inlined) { for (InlinableCallSiteInfo callSite : inlinableCallSites) { - callSite.getCallSite().resetCallCount(); + if (callSite.getCallSite().isInlinable() && !callSite.getCallSite().isInlined()) { + CallNode.internalResetCallCount(callSite.getCallSite()); + } } } else { if (TraceTruffleInliningDetails.getValue()) { @@ -155,15 +157,17 @@ private static final class InlinableCallSiteInfo { - private final InlinableCallSite callSite; + private final CallNode callSite; private final int callCount; private final int nodeCount; private final int recursiveDepth; - public InlinableCallSiteInfo(InlinableCallSite callSite) { + public InlinableCallSiteInfo(CallNode callSite) { + assert callSite.isInlinable(); this.callSite = callSite; - this.callCount = callSite.getCallCount(); - this.nodeCount = NodeUtil.countNodes(callSite.getInlineTree()); + this.callCount = CallNode.internalGetCallCount(callSite); + RootCallTarget target = (RootCallTarget) callSite.getCallTarget(); + this.nodeCount = target.getRootNode().getInlineNodeCount(); this.recursiveDepth = calculateRecursiveDepth(); } @@ -176,8 +180,11 @@ Node parent = ((Node) callSite).getParent(); while (!(parent instanceof RootNode)) { assert parent != null; - if (parent instanceof InlinedCallSite && ((InlinedCallSite) parent).getCallTarget() == callSite.getCallTarget()) { - depth++; + if (parent instanceof CallNode) { + CallNode parentCall = (CallNode) parent; + if (parentCall.isInlined() && parentCall.getCallTarget() == callSite.getCallTarget()) { + depth++; + } } parent = parent.getParent(); } @@ -187,7 +194,7 @@ return depth; } - public InlinableCallSite getCallSite() { + public CallNode getCallSite() { return callSite; } @@ -206,8 +213,11 @@ @Override public boolean visit(Node node) { - if (node instanceof InlinableCallSite) { - inlinableCallSites.add(new InlinableCallSiteInfo((InlinableCallSite) node)); + if (node instanceof CallNode) { + CallNode callNode = (CallNode) node; + if (callNode.isInlinable() && !callNode.isInlined()) { + inlinableCallSites.add(new InlinableCallSiteInfo(callNode)); + } } return true; }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/CallNode.java Wed Jan 29 12:19:03 2014 +0100 @@ -0,0 +1,244 @@ +/* + * Copyright (c) 2012, 2013, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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.truffle.api.nodes; + +import com.oracle.truffle.api.*; +import com.oracle.truffle.api.frame.*; +import com.oracle.truffle.api.impl.*; + +/** + * This node represents a call to a static {@link CallTarget}. This node should be used whenever a + * {@link CallTarget} is considered constant at a certain location in the tree. This enables the + * Truffle runtime to perform inlining or other optimizations for this call-site. + * + * @see #create(CallTarget) to create a CallNode instance. + */ +public abstract class CallNode extends Node { + + protected final CallTarget callTarget; + + private CallNode(CallTarget callTarget) { + this.callTarget = callTarget; + } + + /** + * @return the constant {@link CallTarget} that is associated with this {@link CallNode}. + */ + public CallTarget getCallTarget() { + return callTarget; + } + + /** + * Calls this constant target passing a caller frame and arguments. + * + * @param caller the caller frame + * @param arguments the arguments that should be passed to the callee + * @return the return result of the call + */ + public abstract Object call(PackedFrame caller, Arguments arguments); + + /** + * Returns <code>true</code> if the {@link CallTarget} contained in this {@link CallNode} can be + * inlined. A {@link CallTarget} is considered inlinable if it was created using + * {@link TruffleRuntime#createCallTarget(RootNode)} and if the enclosed {@link RootNode} + * returns <code>true</code> for {@link RootNode#isInlinable()}. + */ + public abstract boolean isInlinable(); + + /** + * @return true if this {@link CallNode} was already inlined. + */ + public abstract boolean isInlined(); + + /** + * Enforces an inlining optimization on this {@link CallNode} instance. If not performed + * manually the Truffle runtime may perform inlining using an heuristic to optimize the + * performance of the execution. It is recommended to implement an version of + * {@link RootNode#inline()} that adapts the inlining for possible guest language specific + * behavior. If the this {@link CallNode} is not inlinable or is already inlined + * <code>false</code> is returned. + * + * @return <code>true</code> if the inlining operation was successful. + */ + public abstract boolean inline(); + + /** + * Creates a new {@link CallNode} using a {@link CallTarget}. + * + * @param target the {@link CallTarget} to call + * @return a call node that calls the provided target + */ + public static CallNode create(CallTarget target) { + if (isInlinable(target)) { + return new InlinableCallNode(target); + } else { + return new DefaultCallNode(target); + } + } + + /** + * Warning: this is internal API and may change without notice. + */ + public static int internalGetCallCount(CallNode callNode) { + if (callNode.isInlinable() && !callNode.isInlined()) { + return ((InlinableCallNode) callNode).getCallCount(); + } + throw new UnsupportedOperationException(); + } + + /** + * Warning: this is internal API and may change without notice. + */ + public static void internalResetCallCount(CallNode callNode) { + if (callNode.isInlinable() && !callNode.isInlined()) { + ((InlinableCallNode) callNode).resetCallCount(); + return; + } + throw new UnsupportedOperationException(); + } + + private static boolean isInlinable(CallTarget callTarget) { + if (callTarget instanceof DefaultCallTarget) { + return (((DefaultCallTarget) callTarget).getRootNode()).isInlinable(); + } + return false; + } + + static final class DefaultCallNode extends CallNode { + + public DefaultCallNode(CallTarget target) { + super(target); + } + + @Override + public Object call(PackedFrame caller, Arguments arguments) { + return callTarget.call(caller, arguments); + } + + @Override + public boolean inline() { + return false; + } + + @Override + public boolean isInlinable() { + return false; + } + + @Override + public boolean isInlined() { + return false; + } + + } + + static final class InlinableCallNode extends CallNode { + + private int callCount; + + public InlinableCallNode(CallTarget target) { + super(target); + } + + @Override + public Object call(PackedFrame parentFrame, Arguments arguments) { + if (CompilerDirectives.inInterpreter()) { + callCount++; + } + return callTarget.call(parentFrame, arguments); + } + + @Override + public boolean inline() { + DefaultCallTarget defaultTarget = (DefaultCallTarget) getCallTarget(); + RootNode originalRootNode = defaultTarget.getRootNode(); + boolean inlined = false; + if (originalRootNode.isInlinable()) { + RootNode inlinedRootNode = defaultTarget.getRootNode().inline(); + replace(new InlinedCallNode(defaultTarget, inlinedRootNode)); + inlined = true; + } + return inlined; + } + + @Override + public boolean isInlined() { + return false; + } + + @Override + public boolean isInlinable() { + return true; + } + + /* Truffle internal API. */ + int getCallCount() { + return callCount; + } + + /* Truffle internal API. */ + void resetCallCount() { + callCount = 0; + } + + } + + static final class InlinedCallNode extends CallNode { + + private final RootNode inlinedRoot; + + public InlinedCallNode(DefaultCallTarget callTarget, RootNode inlinedRoot) { + super(callTarget); + this.inlinedRoot = inlinedRoot; + } + + @Override + public Object call(PackedFrame caller, Arguments arguments) { + return inlinedRoot.execute(Truffle.getRuntime().createVirtualFrame(caller, arguments, inlinedRoot.getFrameDescriptor())); + } + + @Override + public InlinedCallNode copy() { + return new InlinedCallNode((DefaultCallTarget) getCallTarget(), NodeUtil.cloneNode(inlinedRoot)); + } + + @Override + public boolean inline() { + return false; + } + + @Override + public boolean isInlinable() { + return true; + } + + @Override + public boolean isInlined() { + return true; + } + + } + +}
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/InlinableCallSite.java Wed Jan 29 09:21:50 2014 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,69 +0,0 @@ -/* - * Copyright (c) 2012, 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * 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.truffle.api.nodes; - -import com.oracle.truffle.api.*; - -/** - * Denotes a call node that can inline the tree of its associated call target. - * - * @see InlinedCallSite - */ -public interface InlinableCallSite { - - /** - * Returns the number of calls since the last reset of the call count. - * - * @return the current call count. - */ - int getCallCount(); - - /** - * Resets the call count to 0. - */ - void resetCallCount(); - - /** - * Returns the tree that would be inlined by a call to {@link #inline(FrameFactory)}. - * - * @return the node tree to be inlined. - */ - Node getInlineTree(); - - /** - * Returns the call target associated with this call site. - * - * @return the inlinable {@link CallTarget}. - */ - CallTarget getCallTarget(); - - /** - * Instructs the call node to inline the associated call target. - * - * @param factory Frame factory for creating new virtual frames for inlined calls. - * @return {@code true} if call target was inlined; {@code false} otherwise. - */ - boolean inline(FrameFactory factory); -}
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/InlinedCallSite.java Wed Jan 29 09:21:50 2014 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,42 +0,0 @@ -/* - * Copyright (c) 2012, 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * 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.truffle.api.nodes; - -import com.oracle.truffle.api.*; - -/** - * Denotes a call node with an inlined call target. Allows for recursive call detection. - * - * @see InlinableCallSite - */ -public interface InlinedCallSite { - - /** - * Returns the call target that has been inlined at this call site. - * - * @return the inlined call target. - */ - CallTarget getCallTarget(); -}
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/RootNode.java Wed Jan 29 09:21:50 2014 +0100 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/RootNode.java Wed Jan 29 12:19:03 2014 +0100 @@ -55,6 +55,58 @@ } /** + * Creates a copy of the current {@link RootNode} for use as inlined AST. The default + * implementation copies this {@link RootNode} and all its children recursively. It is + * recommended to override this method to provide an implementation that copies an uninitialized + * version of this AST. An uninitialized version of an AST was usually never executed which + * means that it has not yet collected any profiling feedback. Please note that changes in the + * behavior of this method might also require changes in {@link #getInlineNodeCount()}. + * + * @see RootNode#getInlineNodeCount() + * @see RootNode#isInlinable() + * + * @return the copied RootNode for inlining + * @throws UnsupportedOperationException if {@link #isInlinable()} returns false + */ + public RootNode inline() { + if (!isInlinable()) { + throw new UnsupportedOperationException("Inlining is not enabled."); + } + return NodeUtil.cloneNode(this); + } + + /** + * Returns the number of nodes that would be returned if {@link #inline()} would get invoked. + * This node count may be used for the calculation in a smart inlining heuristic. + * + * @see RootNode#inline() + * @see RootNode#isInlinable() + * + * @return the number of nodes that will get inlined + * @throws UnsupportedOperationException if {@link #isInlinable()} returns false + */ + public int getInlineNodeCount() { + if (!isInlinable()) { + throw new UnsupportedOperationException("Inlining is not enabled."); + } + return NodeUtil.countNodes(this); + } + + /** + * Returns true if this RootNode can be inlined. If this method returns true implementations of + * {@link #inline()} and {@link #getInlineNodeCount()} must be provided. Returns + * <code>true</code> by default. + * + * @see RootNode#inline() + * @see RootNode#getInlineNodeCount() + * + * @return true if this RootNode can be inlined + */ + public boolean isInlinable() { + return true; + } + + /** * Executes this function using the specified frame and returns the result value. * * @param frame the frame of the currently executing guest language method @@ -66,7 +118,7 @@ return callTarget; } - public FrameDescriptor getFrameDescriptor() { + public final FrameDescriptor getFrameDescriptor() { return frameDescriptor; }
--- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/debug/RubyASTPrinter.java Wed Jan 29 09:21:50 2014 +0100 +++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/debug/RubyASTPrinter.java Wed Jan 29 12:19:03 2014 +0100 @@ -19,7 +19,7 @@ import com.oracle.truffle.api.nodes.NodeUtil.NodeFieldKind; import com.oracle.truffle.api.nodes.instrument.*; import com.oracle.truffle.ruby.nodes.*; -import com.oracle.truffle.ruby.nodes.call.*; +import com.oracle.truffle.ruby.nodes.call.CallNode; import com.oracle.truffle.ruby.nodes.literal.*; import com.oracle.truffle.ruby.nodes.methods.*;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/SLSimpleTestSuite.java Wed Jan 29 12:19:03 2014 +0100 @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2012, 2013, 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.truffle.sl.test; + +import org.junit.runner.*; + +@RunWith(SLTestRunner.class) +@SLTestSuite({"graal/com.oracle.truffle.sl.test/tests", "tests"}) +public class SLSimpleTestSuite { + + public static void main(String[] args) throws Exception { + SLTestRunner.runInMain(SLSimpleTestSuite.class, args); + } + +}
--- a/graal/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/SLTestRunner.java Wed Jan 29 09:21:50 2014 +0100 +++ b/graal/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/SLTestRunner.java Wed Jan 29 12:19:03 2014 +0100 @@ -23,103 +23,143 @@ package com.oracle.truffle.sl.test; import java.io.*; +import java.nio.charset.*; import java.nio.file.*; import java.nio.file.attribute.*; import java.util.*; import org.junit.*; +import org.junit.internal.*; +import org.junit.runner.*; +import org.junit.runner.manipulation.*; +import org.junit.runner.notification.*; +import org.junit.runners.*; +import org.junit.runners.model.*; import com.oracle.truffle.api.*; import com.oracle.truffle.api.source.*; import com.oracle.truffle.sl.*; import com.oracle.truffle.sl.runtime.*; +import com.oracle.truffle.sl.test.SLTestRunner.TestCase; -public class SLTestRunner { +public final class SLTestRunner extends ParentRunner<TestCase> { private static final int REPEATS = 10; - private static final String TEST_DIR = "graal/com.oracle.truffle.sl.test/tests"; + private static final String INPUT_SUFFIX = ".sl"; private static final String OUTPUT_SUFFIX = ".output"; - static class TestCase { - protected final String name; - protected final Source input; - protected final String expectedOutput; - protected String actualOutput; + private static final String LF = System.getProperty("line.separator"); - protected TestCase(String name, Source input, String expectedOutput) { - this.name = name; + public static final class TestCase { + private final Source input; + private final String expectedOutput; + private final Description name; + + public TestCase(Class<?> testClass, String name, Source input, String expectedOutput) { this.input = input; this.expectedOutput = expectedOutput; + this.name = Description.createTestDescription(testClass, name); + } + } + + private final SourceManager sourceManager = new SourceManager(); + private final List<TestCase> testCases; + + public SLTestRunner(Class<?> runningClass) throws InitializationError { + super(runningClass); + try { + testCases = createTests(runningClass); + } catch (IOException e) { + throw new InitializationError(e); } } - protected boolean useConsole = false; + @Override + protected Description describeChild(TestCase child) { + return child.name; + } - protected final SourceManager sourceManager = new SourceManager(); - protected final List<TestCase> testCases = new ArrayList<>(); + @Override + protected List<TestCase> getChildren() { + return testCases; + } + + @Override + public void filter(Filter filter) throws NoTestsRemainException { + super.filter(filter); + } - protected boolean runTests(String namePattern) throws IOException { - Path testsRoot = FileSystems.getDefault().getPath(TEST_DIR); + protected List<TestCase> createTests(final Class<?> c) throws IOException, InitializationError { + SLTestSuite suite = c.getAnnotation(SLTestSuite.class); + if (suite == null) { + throw new InitializationError(String.format("@%s annotation required on class '%s' to run with '%s'.", SLTestSuite.class.getSimpleName(), c.getName(), SLTestRunner.class.getSimpleName())); + } + + String[] pathes = suite.value(); - Files.walkFileTree(testsRoot, new SimpleFileVisitor<Path>() { + Path root = null; + for (String path : pathes) { + root = FileSystems.getDefault().getPath(path); + if (Files.exists(root)) { + break; + } + } + if (root == null && pathes.length > 0) { + throw new FileNotFoundException(pathes[0]); + } + + final Path rootPath = root; + + final List<TestCase> foundCases = new ArrayList<>(); + Files.walkFileTree(rootPath, new SimpleFileVisitor<Path>() { @Override public FileVisitResult visitFile(Path inputFile, BasicFileAttributes attrs) throws IOException { String name = inputFile.getFileName().toString(); if (name.endsWith(INPUT_SUFFIX)) { - name = name.substring(0, name.length() - INPUT_SUFFIX.length()); - Path outputFile = inputFile.resolveSibling(name + OUTPUT_SUFFIX); + String baseName = name.substring(0, name.length() - INPUT_SUFFIX.length()); + + Path outputFile = inputFile.resolveSibling(baseName + OUTPUT_SUFFIX); if (!Files.exists(outputFile)) { throw new Error("Output file does not exist: " + outputFile); } - testCases.add(new TestCase(name, sourceManager.get(inputFile.toString()), new String(Files.readAllBytes(outputFile)))); + // fix line feeds for non unix os + StringBuilder outFile = new StringBuilder(); + for (String line : Files.readAllLines(outputFile, Charset.defaultCharset())) { + outFile.append(line); + outFile.append(LF); + } + foundCases.add(new TestCase(c, baseName, sourceManager.get(inputFile.toString()), outFile.toString())); } return FileVisitResult.CONTINUE; } }); - - if (testCases.size() == 0) { - System.out.format("No test cases match filter %s", namePattern); - return false; - } - - boolean success = true; - for (TestCase testCase : testCases) { - if (namePattern.length() == 0 || testCase.name.toLowerCase().contains(namePattern.toLowerCase())) { - success = success & executeTest(testCase); - } - } - return success; + return foundCases; } - protected boolean executeTest(TestCase testCase) { - System.out.format("Running %s\n", testCase.name); + @Override + protected void runChild(TestCase testCase, RunNotifier notifier) { + notifier.fireTestStarted(testCase.name); ByteArrayOutputStream out = new ByteArrayOutputStream(); - PrintStream printer = new PrintStream(useConsole ? new SplitOutputStream(out, System.err) : out); + PrintStream printer = new PrintStream(out); PrintStream origErr = System.err; try { System.setErr(printer); SLContext context = new SLContext(sourceManager, printer); SLMain.run(context, testCase.input, null, REPEATS); + + String actualOutput = new String(out.toByteArray()); + + Assert.assertEquals(repeat(testCase.expectedOutput, REPEATS), actualOutput); + } catch (AssertionError e) { + notifier.fireTestFailure(new Failure(testCase.name, e)); } catch (Throwable ex) { - ex.printStackTrace(printer); + notifier.fireTestFailure(new Failure(testCase.name, ex)); } finally { System.setErr(origErr); - } - testCase.actualOutput = new String(out.toByteArray()); - - if (testCase.actualOutput.equals(repeat(testCase.expectedOutput, REPEATS))) { - System.out.format("OK %s\n", testCase.name); - return true; - } else { - if (!useConsole) { - System.out.format("== Expected ==\n%s\n", testCase.expectedOutput); - System.out.format("== Actual ==\n%s\n", testCase.actualOutput); - } - System.out.format("FAILED %s\n", testCase.name); - return false; + notifier.fireTestFinished(testCase.name); } } @@ -131,19 +171,35 @@ return result.toString(); } - public static void main(String[] args) throws IOException { - String namePattern = ""; + public static void runInMain(Class<?> testClass, String[] args) throws InitializationError, NoTestsRemainException { + JUnitCore core = new JUnitCore(); + core.addListener(new TextListener(System.out)); + SLTestRunner suite = new SLTestRunner(testClass); if (args.length > 0) { - namePattern = args[0]; + suite.filter(new NameFilter(args[0])); } - boolean success = new SLTestRunner().runTests(namePattern); - if (!success) { + Result r = core.run(suite); + if (!r.wasSuccessful()) { System.exit(1); } } - @Test - public void test() throws IOException { - Assert.assertTrue(runTests("")); + private static final class NameFilter extends Filter { + private final String pattern; + + private NameFilter(String pattern) { + this.pattern = pattern.toLowerCase(); + } + + @Override + public boolean shouldRun(Description description) { + return description.getMethodName().toLowerCase().contains(pattern); + } + + @Override + public String describe() { + return "Filter contains " + pattern; + } } + }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/SLTestSuite.java Wed Jan 29 12:19:03 2014 +0100 @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2012, 2013, 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.truffle.sl.test; + +import java.lang.annotation.*; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE) +public @interface SLTestSuite { + + /** + * Defines the base path of the test suite. Multiple base pathes can be specified. However only + * the first base that exists is used to lookup the test cases. + */ + String[] value(); + +}
--- a/graal/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/SplitOutputStream.java Wed Jan 29 09:21:50 2014 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,69 +0,0 @@ -/* - * Copyright (c) 2012, 2012, 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.truffle.sl.test; - -import java.io.*; - -public class SplitOutputStream extends OutputStream { - - private final OutputStream[] outputs; - - public SplitOutputStream(OutputStream... outputs) { - this.outputs = outputs; - } - - @Override - public void write(int b) throws IOException { - for (OutputStream out : outputs) { - out.write(b); - } - } - - @Override - public void write(byte[] b) throws IOException { - for (OutputStream out : outputs) { - out.write(b); - } - } - - @Override - public void write(byte[] b, int off, int len) throws IOException { - for (OutputStream out : outputs) { - out.write(b, off, len); - } - } - - @Override - public void flush() throws IOException { - for (OutputStream out : outputs) { - out.flush(); - } - } - - @Override - public void close() throws IOException { - for (OutputStream out : outputs) { - out.close(); - } - } -}
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/SLRootNode.java Wed Jan 29 09:21:50 2014 +0100 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/SLRootNode.java Wed Jan 29 12:19:03 2014 +0100 @@ -73,8 +73,19 @@ return inlineImmediatly; } - public SLExpressionNode inline() { - return NodeUtil.cloneNode(uninitializedBody); + @Override + public RootNode inline() { + return new SLRootNode(getFrameDescriptor().shallowCopy(), NodeUtil.cloneNode(uninitializedBody), name, inlineImmediatly); + } + + @Override + public int getInlineNodeCount() { + return NodeUtil.countNodes(uninitializedBody); + } + + @Override + public boolean isInlinable() { + return true; } public Node getUninitializedBody() {
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/call/SLDirectDispatchNode.java Wed Jan 29 09:21:50 2014 +0100 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/call/SLDirectDispatchNode.java Wed Jan 29 12:19:03 2014 +0100 @@ -27,27 +27,29 @@ import com.oracle.truffle.api.nodes.*; import com.oracle.truffle.sl.runtime.*; -abstract class SLDirectDispatchNode extends SLAbstractDispatchNode { +final class SLDirectDispatchNode extends SLAbstractDispatchNode { protected final SLFunction cachedFunction; protected final RootCallTarget cachedCallTarget; protected final Assumption cachedCallTargetStable; + @Child protected CallNode callNode; @Child protected SLAbstractDispatchNode nextNode; protected SLDirectDispatchNode(SLAbstractDispatchNode next, SLFunction cachedFunction) { this.cachedFunction = cachedFunction; this.cachedCallTarget = cachedFunction.getCallTarget(); this.cachedCallTargetStable = cachedFunction.getCallTargetStable(); + this.callNode = adoptChild(CallNode.create(cachedCallTarget)); this.nextNode = adoptChild(next); } @Override - protected final Object executeCall(VirtualFrame frame, SLFunction function, SLArguments arguments) { + protected Object executeCall(VirtualFrame frame, SLFunction function, SLArguments arguments) { if (this.cachedFunction == function) { try { cachedCallTargetStable.check(); - return executeCurrent(frame, arguments); + return callNode.call(frame.pack(), arguments); } catch (InvalidAssumptionException ex) { /* * Remove ourselfs from the polymorphic inline cache, so that we fail the check only @@ -61,6 +63,4 @@ } return nextNode.executeCall(frame, function, arguments); } - - protected abstract Object executeCurrent(VirtualFrame frame, SLArguments arguments); }
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/call/SLInlinableDirectDispatchNode.java Wed Jan 29 09:21:50 2014 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,82 +0,0 @@ -/* - * Copyright (c) 2013, 2013, 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.truffle.sl.nodes.call; - -import com.oracle.truffle.api.*; -import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; -import com.oracle.truffle.api.frame.*; -import com.oracle.truffle.api.nodes.*; -import com.oracle.truffle.sl.nodes.*; -import com.oracle.truffle.sl.runtime.*; - -final class SLInlinableDirectDispatchNode extends SLDirectDispatchNode implements InlinableCallSite { - - @CompilationFinal private int callCount; - - protected SLInlinableDirectDispatchNode(SLAbstractDispatchNode next, SLFunction cachedFunction) { - super(next, cachedFunction); - } - - @Override - protected Object executeCurrent(VirtualFrame frame, SLArguments arguments) { - if (CompilerDirectives.inInterpreter()) { - callCount++; - } - return cachedCallTarget.call(frame.pack(), arguments); - } - - @Override - public boolean inline(FrameFactory factory) { - CompilerAsserts.neverPartOfCompilation(); - RootNode root = cachedCallTarget.getRootNode(); - SLExpressionNode inlinedNode = ((SLRootNode) root).inline(); - assert inlinedNode != null; - replace(new SLInlinedDirectDispatchNode(this, inlinedNode), "Inlined " + root); - /* We are always able to inline if required. */ - return true; - } - - @Override - public int getCallCount() { - return callCount; - } - - @Override - public void resetCallCount() { - callCount = 0; - } - - @Override - public Node getInlineTree() { - RootNode root = cachedCallTarget.getRootNode(); - if (root instanceof SLRootNode) { - return ((SLRootNode) root).getUninitializedBody(); - } - return null; - } - - @Override - public CallTarget getCallTarget() { - return cachedCallTarget; - } -}
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/call/SLInlinedDirectDispatchNode.java Wed Jan 29 09:21:50 2014 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,52 +0,0 @@ -/* - * Copyright (c) 2013, 2013, 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.truffle.sl.nodes.call; - -import com.oracle.truffle.api.*; -import com.oracle.truffle.api.frame.*; -import com.oracle.truffle.api.nodes.*; -import com.oracle.truffle.sl.nodes.*; -import com.oracle.truffle.sl.runtime.*; - -final class SLInlinedDirectDispatchNode extends SLDirectDispatchNode implements InlinedCallSite { - - private final FrameDescriptor descriptor; - @Child private SLExpressionNode inlinedBody; - - protected SLInlinedDirectDispatchNode(SLInlinableDirectDispatchNode prev, SLExpressionNode inlinedBody) { - super(prev.nextNode, prev.cachedFunction); - this.descriptor = cachedCallTarget.getRootNode().getFrameDescriptor(); - this.inlinedBody = adoptChild(inlinedBody); - } - - @Override - protected Object executeCurrent(VirtualFrame frame, SLArguments arguments) { - VirtualFrame newFrame = Truffle.getRuntime().createVirtualFrame(frame.pack(), arguments, descriptor); - return inlinedBody.executeGeneric(newFrame); - } - - @Override - public CallTarget getCallTarget() { - return cachedCallTarget; - } -}
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/call/SLUninitializedCallNode.java Wed Jan 29 09:21:50 2014 +0100 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/call/SLUninitializedCallNode.java Wed Jan 29 12:19:03 2014 +0100 @@ -43,7 +43,7 @@ SLAbstractDispatchNode specialized; if (depth < INLINE_CACHE_SIZE) { SLAbstractDispatchNode next = new SLUninitializedCallNode(); - SLAbstractDispatchNode direct = new SLInlinableDirectDispatchNode(next, function); + SLAbstractDispatchNode direct = new SLDirectDispatchNode(next, function); specialized = replace(direct); } else { SLAbstractDispatchNode generic = new SLGenericDispatchNode();