# HG changeset patch # User Christian Humer # Date 1390575341 -3600 # Node ID e076c87ab1750d4d676f02397db509085ea4d0a2 # Parent a03cb658e68e863f8dd02ea30adfbc27ff856a92 Truffle: refactored inlining interfaces to a more compact CallNode. diff -r a03cb658e68e -r e076c87ab175 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallTarget.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallTarget.java Fri Jan 24 12:26:05 2014 +0100 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallTarget.java Fri Jan 24 15:55:41 2014 +0100 @@ -261,7 +261,7 @@ int notInlinedCallSiteCount = TruffleInliningImpl.getInlinableCallSites(callTarget).size(); int nodeCount = NodeUtil.countNodes(callTarget.rootNode); - int inlinedCallSiteCount = NodeUtil.countNodes(callTarget.rootNode, InlinedCallSite.class); + int inlinedCallSiteCount = countInlinedNodes(callTarget.rootNode); 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, @@ -276,6 +276,17 @@ OUT.printf("%-50s | %10d | %15d | %15d | %10d | %3d\n", "Total", totalCallCount, totalInlinedCallSiteCount, totalNotInlinedCallSiteCount, totalNodeCount, totalInvalidationCount); } + private static int countInlinedNodes(Node rootNode) { + List 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); } diff -r a03cb658e68e -r e076c87ab175 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerImpl.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerImpl.java Fri Jan 24 12:26:05 2014 +0100 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerImpl.java Fri Jan 24 15:55:41 2014 +0100 @@ -186,13 +186,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; } @@ -200,7 +202,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()); diff -r a03cb658e68e -r e076c87ab175 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleInliningImpl.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleInliningImpl.java Fri Jan 24 12:26:05 2014 +0100 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleInliningImpl.java Fri Jan 24 15:55:41 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()) { + 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); + DefaultCallTarget target = (DefaultCallTarget) 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()) { + inlinableCallSites.add(new InlinableCallSiteInfo(callNode)); + } } return true; } diff -r a03cb658e68e -r e076c87ab175 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/CallNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/CallNode.java Fri Jan 24 15:55:41 2014 +0100 @@ -0,0 +1,230 @@ +/* + * 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 constant {@link CallTarget} in the Truffle AST. This node should + * be used whenever a {@link CallTarget} is considered constant at a certain location. 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; + } + + /** + * Returns 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 true if 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 true for {@link RootNode#isInlinable()}. + */ + public boolean isInlinable() { + return false; + } + + /** + * Returns true if this {@link CallNode} was already inlined. + */ + public boolean isInlined() { + return false; + } + + /** + * 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 optimized version of + * {@link RootNode#inline()}. + * + * @return true if the inlining operation was successful. + * @throws IllegalStateException if {@link #isInlinable()} is false. + */ + public boolean inline() { + CompilerDirectives.transferToInterpreter(); + if (!isInlinable()) { + throw new IllegalStateException("Invoked inline on a non inlinable CallNode."); + } + assert !isInlined(); + return false; + } + + /** + * Creates a new {@link CallNode} using a constant {@link CallTarget}. + * + * @param target the {@link CallTarget} the {@link CallNode} should 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()) { + 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()) { + ((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); + } + + } + + 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() { + super.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 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 isInlinable() { + return false; + } + + @Override + public boolean isInlined() { + return true; + } + + } + +} diff -r a03cb658e68e -r e076c87ab175 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/InlinableCallSite.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/InlinableCallSite.java Fri Jan 24 12:26:05 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); -} diff -r a03cb658e68e -r e076c87ab175 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/InlinedCallSite.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/InlinedCallSite.java Fri Jan 24 12:26:05 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(); -} diff -r a03cb658e68e -r e076c87ab175 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/RootNode.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/RootNode.java Fri Jan 24 12:26:05 2014 +0100 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/RootNode.java Fri Jan 24 15:55:41 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 of 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 proper + * implementations of {@link #inline()} and {@link #getInlineNodeCount()} must be provided. + * Returns true 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; } diff -r a03cb658e68e -r e076c87ab175 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/debug/RubyASTPrinter.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/debug/RubyASTPrinter.java Fri Jan 24 12:26:05 2014 +0100 +++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/debug/RubyASTPrinter.java Fri Jan 24 15:55:41 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.*; diff -r a03cb658e68e -r e076c87ab175 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/SLNodeFactory.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/SLNodeFactory.java Fri Jan 24 12:26:05 2014 +0100 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/SLNodeFactory.java Fri Jan 24 15:55:41 2014 +0100 @@ -96,7 +96,7 @@ } public TypedNode createCall(TypedNode function, TypedNode[] parameters) { - return assignSource(CallNode.create(function, parameters)); + return assignSource(FunctionCallNode.create(function, parameters)); } public TypedNode createBinary(String operation, TypedNode left, TypedNode right) { diff -r a03cb658e68e -r e076c87ab175 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/CallNode.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/CallNode.java Fri Jan 24 12:26:05 2014 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,222 +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.nodes; - -import com.oracle.truffle.api.*; -import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; -import com.oracle.truffle.api.frame.*; -import com.oracle.truffle.api.impl.*; -import com.oracle.truffle.api.nodes.*; -import com.oracle.truffle.sl.runtime.*; - -public abstract class CallNode extends TypedNode { - - private static final int INLINE_CACHE_SIZE = 2; - - @Child protected TypedNode functionNode; - @Child protected ArgumentsNode argumentsNode; - - public CallNode(TypedNode functionNode, ArgumentsNode argumentsNode) { - this.functionNode = adoptChild(functionNode); - this.argumentsNode = adoptChild(argumentsNode); - } - - @Override - public final Object executeGeneric(VirtualFrame frame) { - CallTarget function; - try { - function = functionNode.executeCallTarget(frame); - } catch (UnexpectedResultException e) { - throw new UnsupportedOperationException("Call to " + e.getMessage() + " not supported."); - } - Object[] arguments = argumentsNode.executeArray(frame); - return executeCall(frame, function, arguments); - } - - public abstract Object executeCall(VirtualFrame frame, CallTarget function, Object[] arguments); - - public static CallNode create(TypedNode function, TypedNode[] arguments) { - return new UninitializedCallNode(function, new ArgumentsNode(arguments), 0); - } - - private static final class UninitializedCallNode extends CallNode { - - protected final int depth; - - UninitializedCallNode(TypedNode function, ArgumentsNode args, int depth) { - super(function, args); - this.depth = depth; - } - - UninitializedCallNode(UninitializedCallNode copy) { - super(null, null); - this.depth = copy.depth + 1; - } - - @Override - public Object executeCall(VirtualFrame frame, CallTarget function, Object[] arguments) { - CompilerDirectives.transferToInterpreter(); - return specialize(function).executeCall(frame, function, arguments); - } - - private CallNode specialize(CallTarget function) { - CompilerAsserts.neverPartOfCompilation(); - - if (depth < INLINE_CACHE_SIZE) { - DefaultCallTarget callTarget = (DefaultCallTarget) function; - FunctionRootNode root = (FunctionRootNode) callTarget.getRootNode(); - CallNode next = new UninitializedCallNode(this); - InlinableDirectCallNode directCall = new InlinableDirectCallNode(functionNode, argumentsNode, next, callTarget); - replace(directCall); - if (root.isInlineImmediatly()) { - return directCall.inlineImpl(); - } else { - return directCall; - } - } else { - CallNode topMost = (CallNode) NodeUtil.getNthParent(this, depth); - return topMost.replace(new GenericCallNode(topMost.functionNode, topMost.argumentsNode)); - } - } - - } - - private abstract static class DirectCallNode extends CallNode { - - protected final DefaultCallTarget cachedFunction; - - @Child protected CallNode nextNode; - - public DirectCallNode(TypedNode function, ArgumentsNode arguments, DefaultCallTarget cachedFunction, CallNode next) { - super(function, arguments); - this.cachedFunction = cachedFunction; - this.nextNode = adoptChild(next); - } - - @Override - public Object executeCall(VirtualFrame frame, CallTarget function, Object[] arguments) { - if (this.cachedFunction == function) { - return executeCurrent(frame, arguments); - } - return nextNode.executeCall(frame, function, arguments); - } - - protected abstract Object executeCurrent(VirtualFrame frame, Object[] arguments); - - } - - private static final class InlinableDirectCallNode extends DirectCallNode implements InlinableCallSite { - - @CompilationFinal private int callCount; - - InlinableDirectCallNode(TypedNode function, ArgumentsNode arguments, CallNode next, DefaultCallTarget cachedFunction) { - super(function, arguments, cachedFunction, next); - } - - @Override - public Object executeCurrent(VirtualFrame frame, Object[] arguments) { - if (CompilerDirectives.inInterpreter()) { - callCount++; - } - return cachedFunction.call(frame.pack(), new SLArguments(arguments)); - } - - InlinedDirectCallNode inlineImpl() { - CompilerAsserts.neverPartOfCompilation(); - RootNode root = cachedFunction.getRootNode(); - TypedNode inlinedNode = ((FunctionRootNode) root).inline(); - assert inlinedNode != null; - return replace(new InlinedDirectCallNode(this, inlinedNode), "Inlined " + root); - } - - @Override - public boolean inline(FrameFactory factory) { - inlineImpl(); - /* SL is 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 = cachedFunction.getRootNode(); - if (root instanceof FunctionRootNode) { - return ((FunctionRootNode) root).getUninitializedBody(); - } - return null; - } - - @Override - public CallTarget getCallTarget() { - return cachedFunction; - } - - } - - private static class InlinedDirectCallNode extends DirectCallNode implements InlinedCallSite { - - private final FrameDescriptor descriptor; - @Child private TypedNode inlinedBody; - - InlinedDirectCallNode(InlinableDirectCallNode prev, TypedNode inlinedBody) { - super(prev.functionNode, prev.argumentsNode, prev.cachedFunction, prev.nextNode); - this.descriptor = cachedFunction.getRootNode().getFrameDescriptor(); - this.inlinedBody = adoptChild(inlinedBody); - } - - @Override - public Object executeCurrent(VirtualFrame frame, Object[] arguments) { - SLArguments slArguments = new SLArguments(arguments); - VirtualFrame newFrame = Truffle.getRuntime().createVirtualFrame(frame.pack(), slArguments, descriptor); - return inlinedBody.executeGeneric(newFrame); - } - - @Override - public CallTarget getCallTarget() { - return cachedFunction; - } - - } - - private static final class GenericCallNode extends CallNode { - - GenericCallNode(TypedNode functionNode, ArgumentsNode arguments) { - super(functionNode, arguments); - } - - @Override - public Object executeCall(VirtualFrame frame, CallTarget function, Object[] arguments) { - return function.call(frame.pack(), new SLArguments(arguments)); - } - } - -} diff -r a03cb658e68e -r e076c87ab175 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/FunctionCallNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/FunctionCallNode.java Fri Jan 24 15:55:41 2014 +0100 @@ -0,0 +1,140 @@ +/* + * 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.nodes; + +import com.oracle.truffle.api.*; +import com.oracle.truffle.api.frame.*; +import com.oracle.truffle.api.impl.*; +import com.oracle.truffle.api.nodes.*; +import com.oracle.truffle.sl.runtime.*; + +public abstract class FunctionCallNode extends TypedNode { + + private static final int INLINE_CACHE_SIZE = 2; + + @Child protected TypedNode functionNode; + @Child protected ArgumentsNode argumentsNode; + + public FunctionCallNode(TypedNode functionNode, ArgumentsNode argumentsNode) { + this.functionNode = adoptChild(functionNode); + this.argumentsNode = adoptChild(argumentsNode); + } + + @Override + public final Object executeGeneric(VirtualFrame frame) { + CallTarget function; + try { + function = functionNode.executeCallTarget(frame); + } catch (UnexpectedResultException e) { + throw new UnsupportedOperationException("Call to " + e.getMessage() + " not supported."); + } + Object[] arguments = argumentsNode.executeArray(frame); + return executeCall(frame, function, new SLArguments(arguments)); + } + + public abstract Object executeCall(VirtualFrame frame, CallTarget function, SLArguments arguments); + + public static FunctionCallNode create(TypedNode function, TypedNode[] arguments) { + return new UninitializedCallNode(function, new ArgumentsNode(arguments), 0); + } + + private static final class UninitializedCallNode extends FunctionCallNode { + + protected final int depth; + + UninitializedCallNode(TypedNode function, ArgumentsNode args, int depth) { + super(function, args); + this.depth = depth; + } + + UninitializedCallNode(UninitializedCallNode copy) { + super(null, null); + this.depth = copy.depth + 1; + } + + @Override + public Object executeCall(VirtualFrame frame, CallTarget function, SLArguments arguments) { + CompilerDirectives.transferToInterpreter(); + return specialize(function).executeCall(frame, function, arguments); + } + + private FunctionCallNode specialize(CallTarget function) { + CompilerAsserts.neverPartOfCompilation(); + if (depth < INLINE_CACHE_SIZE) { + return replace(new CachedCallNode(functionNode, argumentsNode, function, new UninitializedCallNode(this))); + } else { + FunctionCallNode topMost = (FunctionCallNode) NodeUtil.getNthParent(this, depth); + return topMost.replace(new GenericCallNode(topMost.functionNode, topMost.argumentsNode)); + } + } + + } + + private static final class CachedCallNode extends FunctionCallNode { + + protected final CallTarget cachedFunction; + + @Child protected CallNode callNode; + @Child protected FunctionCallNode nextNode; + + public CachedCallNode(TypedNode function, ArgumentsNode arguments, CallTarget cachedFunction, FunctionCallNode next) { + super(function, arguments); + this.cachedFunction = cachedFunction; + this.callNode = adoptChild(CallNode.create(cachedFunction)); + this.nextNode = adoptChild(next); + + // inline usually known functions that should always be inlined + if (findSLFunctionRoot(cachedFunction).isInlineImmediatly()) { + if (callNode.isInlinable() && !callNode.isInlined()) { + callNode.inline(); + } + } + } + + @Override + public Object executeCall(VirtualFrame frame, CallTarget function, SLArguments arguments) { + if (this.cachedFunction == function) { + return callNode.call(frame.pack(), arguments); + } + return nextNode.executeCall(frame, function, arguments); + } + + private static FunctionRootNode findSLFunctionRoot(CallTarget target) { + return (FunctionRootNode) ((DefaultCallTarget) target).getRootNode(); + } + + } + + private static final class GenericCallNode extends FunctionCallNode { + + GenericCallNode(TypedNode functionNode, ArgumentsNode arguments) { + super(functionNode, arguments); + } + + @Override + public Object executeCall(VirtualFrame frame, CallTarget function, SLArguments arguments) { + return function.call(frame.pack(), arguments); + } + } + +} diff -r a03cb658e68e -r e076c87ab175 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/FunctionRootNode.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/FunctionRootNode.java Fri Jan 24 12:26:05 2014 +0100 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/FunctionRootNode.java Fri Jan 24 15:55:41 2014 +0100 @@ -71,8 +71,19 @@ return inlineImmediatly; } - public TypedNode inline() { - return NodeUtil.cloneNode(uninitializedBody); + @Override + public RootNode inline() { + return new FunctionRootNode(getFrameDescriptor().shallowCopy(), NodeUtil.cloneNode(uninitializedBody), name, inlineImmediatly); + } + + @Override + public int getInlineNodeCount() { + return NodeUtil.countNodes(uninitializedBody); + } + + @Override + public boolean isInlinable() { + return true; } public Node getUninitializedBody() {