Mercurial > hg > truffle
changeset 13813:460e453d6fec
Merge.
author | Christian Humer <christian.humer@gmail.com> |
---|---|
date | Wed, 29 Jan 2014 21:56:34 +0100 |
parents | f270f09616da (diff) 3e13ec261278 (current diff) |
children | d7ed39d0a6d9 |
files | graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerImpl.java |
diffstat | 22 files changed, 767 insertions(+), 421 deletions(-) [+] |
line wrap: on
line diff
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallTarget.java Wed Jan 29 18:30:42 2014 +0100 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallTarget.java Wed Jan 29 21:56:34 2014 +0100 @@ -56,7 +56,6 @@ super(rootNode); this.compiler = compiler; this.compilationProfile = new CompilationProfile(compilationThreshold, invokeCounter, rootNode.toString()); - this.getRootNode().setCallTarget(this); if (TruffleUseTimeForCompilationDecision.getValue()) { compilationPolicy = new TimedCompilationPolicy(); @@ -261,8 +260,8 @@ } int notInlinedCallSiteCount = TruffleInliningImpl.getInlinableCallSites(callTarget).size(); - int nodeCount = NodeUtil.countNodes(callTarget.getRootNode()); - int inlinedCallSiteCount = NodeUtil.countNodes(callTarget.getRootNode(), InlinedCallSite.class); + int nodeCount = NodeUtil.countNodes(callTarget.getRootNode(), null, true); + 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 +276,18 @@ 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++; + count += countInlinedNodes(callNode.getInlinedRoot()); + } + } + 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 18:30:42 2014 +0100 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerImpl.java Wed Jan 29 21:56:34 2014 +0100 @@ -168,7 +168,7 @@ } if (TraceTruffleCompilation.getValue()) { - int nodeCountTruffle = NodeUtil.countNodes(compilable.getRootNode()); + int nodeCountTruffle = NodeUtil.countNodes(compilable.getRootNode(), null, true); byte[] code = compiledMethod.getCode(); OUT.printf("[truffle] optimized %-50s %x |Nodes %7d |Time %5.0f(%4.0f+%-4.0f)ms |Nodes %5d/%5d |CodeSize %d\n", compilable.getRootNode(), compilable.hashCode(), nodeCountTruffle, (timeCompilationFinished - timeCompilationStarted) / 1e6, (timePartialEvaluationFinished - timeCompilationStarted) / 1e6, @@ -186,22 +186,27 @@ 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()); + callNode.getInlinedRoot().accept(this); } - OUT.println(inlinedCallSite.getCallTarget()); } return true; } private int indent(Node n) { if (n instanceof RootNode) { + CallNode inlinedParent = ((RootNode) n).getParentInlinedCall(); + if (inlinedParent != null) { + return indent(inlinedParent) + 1; + } return 0; - } else if (n instanceof InlinedCallSite) { - 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 18:30:42 2014 +0100 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleInliningImpl.java Wed Jan 29 21:56:34 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,7 @@ if (inlined) { for (InlinableCallSiteInfo callSite : inlinableCallSites) { - callSite.getCallSite().resetCallCount(); + CallNode.internalResetCallCount(callSite.getCallSite()); } } else { if (TraceTruffleInliningDetails.getValue()) { @@ -114,7 +114,7 @@ private final int callerInvocationCount; public InliningPolicy(OptimizedCallTarget caller) { - this.callerNodeCount = NodeUtil.countNodes(caller.getRootNode()); + this.callerNodeCount = NodeUtil.countNodes(caller.getRootNode(), null, true); this.callerInvocationCount = caller.getCompilationProfile().getOriginalInvokeCounter(); } @@ -155,15 +155,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(); } @@ -173,21 +175,23 @@ private int calculateRecursiveDepth() { int depth = 0; - Node parent = ((Node) callSite).getParent(); - while (!(parent instanceof RootNode)) { - assert parent != null; - if (parent instanceof InlinedCallSite && ((InlinedCallSite) parent).getCallTarget() == callSite.getCallTarget()) { - depth++; + + Node parent = callSite.getParent(); + while (parent != null) { + if (parent instanceof RootNode) { + RootNode root = ((RootNode) parent); + if (root.getCallTarget() == callSite.getCallTarget()) { + depth++; + } + parent = root.getParentInlinedCall(); + } else { + parent = parent.getParent(); } - parent = parent.getParent(); - } - if (((RootNode) parent).getCallTarget() == callSite.getCallTarget()) { - depth++; } return depth; } - public InlinableCallSite getCallSite() { + public CallNode getCallSite() { return callSite; } @@ -206,8 +210,15 @@ @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.isInlined()) { + if (callNode.isInlinable()) { + inlinableCallSites.add(new InlinableCallSiteInfo(callNode)); + } + } else { + callNode.getInlinedRoot().accept(this); + } } return true; }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/UnsupportedSpecializationTest.java Wed Jan 29 21:56:34 2014 +0100 @@ -0,0 +1,58 @@ +/* + * 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.api.dsl.test; + +import org.junit.*; + +import com.oracle.truffle.api.dsl.*; +import com.oracle.truffle.api.dsl.test.TypeSystemTest.TestRootNode; +import com.oracle.truffle.api.dsl.test.TypeSystemTest.ValueNode; +import com.oracle.truffle.api.dsl.test.UnsupportedSpecializationTestFactory.Undefined1Factory; + +public class UnsupportedSpecializationTest { + + @Test + public void testUndefined1() { + TestRootNode<Undefined1> root = TestHelper.createRoot(Undefined1Factory.getInstance()); + try { + TestHelper.executeWith(root, ""); + Assert.fail(); + } catch (UnsupportedSpecializationException e) { + Assert.assertNotNull(e.getSuppliedValues()); + Assert.assertEquals(1, e.getSuppliedValues().length); + Assert.assertEquals("", e.getSuppliedValues()[0]); + Assert.assertEquals(root.getNode(), e.getNode()); + } + } + + @NodeChild("a") + abstract static class Undefined1 extends ValueNode { + + @Specialization + public int doInteger(@SuppressWarnings("unused") int a) { + throw new AssertionError(); + } + } + + // TODO more tests required +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api.dsl/src/com/oracle/truffle/api/dsl/UnsupportedSpecializationException.java Wed Jan 29 21:56:34 2014 +0100 @@ -0,0 +1,62 @@ +/* + * 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. 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.dsl; + +import java.util.*; + +import com.oracle.truffle.api.nodes.*; + +/** + * Thrown by the generated code of Truffle-DSL if no compatible Specialization could be found for + * the provided values. + */ +public final class UnsupportedSpecializationException extends RuntimeException { + + private static final long serialVersionUID = -2122892028296836269L; + + private final Node node; + private final Object[] suppliedValues; + + public UnsupportedSpecializationException(Node node, Object... suppliedValues) { + super("Unexpected values provided for " + node + ": " + Arrays.toString(suppliedValues)); + this.node = node; + this.suppliedValues = suppliedValues; + } + + /** + * Returns the {@link Node} that caused the this {@link UnsupportedSpecializationException}. + */ + public Node getNode() { + return node; + } + + /** + * Returns the dynamic values that were supplied to the node. + */ + public Object[] getSuppliedValues() { + return suppliedValues; + } + +}
--- /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 21:56:34 2014 +0100 @@ -0,0 +1,264 @@ +/* + * 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(); + + /** + * Returns the inlined root node if the call node was inlined. If the {@link CallNode} was not + * inlined <code>null</code> is returned. + * + * @return the inlined root node returned by {@link RootNode#inline()} + */ + public RootNode getInlinedRoot() { + return null; + } + + /** + * 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; + } + } + + private static boolean isInlinable(CallTarget callTarget) { + if (callTarget instanceof DefaultCallTarget) { + return (((DefaultCallTarget) callTarget).getRootNode()).isInlinable(); + } + return false; + } + + @Override + public String toString() { + return getParent() != null ? getParent().toString() : super.toString(); + } + + 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(); + if (originalRootNode.isInlinable()) { + RootNode inlinedRootNode = defaultTarget.getRootNode().inline(); + inlinedRootNode.setCallTarget(callTarget); + inlinedRootNode.setParentInlinedCall(this); + replace(new InlinedCallNode(defaultTarget, inlinedRootNode)); + return true; + } + return false; + } + + @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 RootNode getInlinedRoot() { + return 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 18:30:42 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 18:30:42 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/Node.java Wed Jan 29 18:30:42 2014 +0100 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/Node.java Wed Jan 29 21:56:34 2014 +0100 @@ -246,7 +246,7 @@ } private void reportReplace() { - RootNode rootNode = getRootNode(); + RootNode rootNode = NodeUtil.findOutermostRootNode(this); if (rootNode != null) { if (rootNode.getCallTarget() instanceof ReplaceObserver) { ((ReplaceObserver) rootNode.getCallTarget()).nodeReplaced();
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/NodeUtil.java Wed Jan 29 18:30:42 2014 +0100 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/NodeUtil.java Wed Jan 29 21:56:34 2014 +0100 @@ -451,6 +451,31 @@ return null; } + /** + * Returns the outermost not inlined {@link RootNode} which is a parent of this node. + * + * @see RootNode#getParentInlinedCall() + * @param node to search + * @return the outermost {@link RootNode} + */ + public static RootNode findOutermostRootNode(Node node) { + Node parent = node; + while (parent != null) { + if (parent instanceof RootNode) { + RootNode root = (RootNode) parent; + Node next = root.getParentInlinedCall(); + if (next != null) { + parent = next; + } else { + return root; + } + } else { + parent = parent.getParent(); + } + } + return null; + } + public static <T> T findParent(Node start, Class<T> clazz) { Node parent = start.getParent(); if (parent == null) { @@ -571,24 +596,26 @@ } public static int countNodes(Node root) { - return countNodes(root, null); + return countNodes(root, null, false); } - public static int countNodes(Node root, Class<?> clazz) { - NodeCountVisitor nodeCount = new NodeCountVisitor(root, clazz); + public static int countNodes(Node root, Class<?> clazz, boolean countInlinedCallNodes) { + NodeCountVisitor nodeCount = new NodeCountVisitor(root, clazz, countInlinedCallNodes); root.accept(nodeCount); return nodeCount.nodeCount; } private static final class NodeCountVisitor implements NodeVisitor { + private Node root; + private boolean inspectInlinedCalls; int nodeCount; - private final Node root; private final Class<?> clazz; - private NodeCountVisitor(Node root, Class<?> clazz) { + private NodeCountVisitor(Node root, Class<?> clazz, boolean inspectInlinedCalls) { this.root = root; this.clazz = clazz; + this.inspectInlinedCalls = inspectInlinedCalls; } @Override @@ -596,9 +623,18 @@ if (node instanceof RootNode && node != root) { return false; } + if (clazz == null || clazz.isInstance(node)) { nodeCount++; } + + if (inspectInlinedCalls && node instanceof CallNode) { + CallNode call = (CallNode) node; + if (call.isInlined()) { + call.getInlinedRoot().getChildren().iterator().next().accept(this); + } + } + return true; } }
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/RootNode.java Wed Jan 29 18:30:42 2014 +0100 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/RootNode.java Wed Jan 29 21:56:34 2014 +0100 @@ -25,6 +25,7 @@ package com.oracle.truffle.api.nodes; import com.oracle.truffle.api.*; +import com.oracle.truffle.api.CompilerDirectives.*; import com.oracle.truffle.api.frame.*; /** @@ -37,6 +38,12 @@ private CallTarget callTarget; private final FrameDescriptor frameDescriptor; + /* + * Internal field to keep reference to the inlined call node. The inlined parent should not be + * the same as the Node parent to keep the same tree hierarchy if inlined vs not inlined. + */ + @CompilationFinal private CallNode parentInlinedCall; + protected RootNode() { this(null, null); } @@ -55,6 +62,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,11 +125,27 @@ return callTarget; } - public FrameDescriptor getFrameDescriptor() { + public final FrameDescriptor getFrameDescriptor() { return frameDescriptor; } public void setCallTarget(CallTarget callTarget) { this.callTarget = callTarget; } + + /* Internal API. Do not use. */ + void setParentInlinedCall(CallNode inlinedParent) { + this.parentInlinedCall = inlinedParent; + } + + /** + * Returns the {@link CallNode} that uses this {@link RootNode} for an inlined call. Returns + * <code>null</code> if this {@link RootNode} is not inlined into a caller. This method can be + * used to also traverse parent {@link CallTarget} that have been inlined into this call. + * + * @return the responsible {@link CallNode} for inlining. + */ + public final CallNode getParentInlinedCall() { + return parentInlinedCall; + } }
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/NodeCodeGenerator.java Wed Jan 29 18:30:42 2014 +0100 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/NodeCodeGenerator.java Wed Jan 29 21:56:34 2014 +0100 @@ -331,11 +331,10 @@ } protected void emitEncounteredSynthetic(CodeTreeBuilder builder, TemplateMethod current) { - builder.startThrow().startNew(getContext().getType(UnsupportedOperationException.class)); - builder.startCall("createInfo0"); - builder.doubleQuote("Unsupported values"); + builder.startThrow().startNew(getContext().getType(UnsupportedSpecializationException.class)); + builder.string("this"); addInternalValueParameterNames(builder, current, current, null, false, null); - builder.end().end().end(); + builder.end().end(); } private static List<ExecutableElement> findUserConstructors(TypeMirror nodeType) {
--- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/debug/RubyASTPrinter.java Wed Jan 29 18:30:42 2014 +0100 +++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/debug/RubyASTPrinter.java Wed Jan 29 21:56:34 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 21:56:34 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 18:30:42 2014 +0100 +++ b/graal/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/SLTestRunner.java Wed Jan 29 21:56:34 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 21:56:34 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 18:30:42 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 18:30:42 2014 +0100 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/SLRootNode.java Wed Jan 29 21:56:34 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 18:30:42 2014 +0100 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/call/SLDirectDispatchNode.java Wed Jan 29 21:56:34 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 18:30:42 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 18:30:42 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 18:30:42 2014 +0100 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/call/SLUninitializedCallNode.java Wed Jan 29 21:56:34 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();