# HG changeset patch # User Christian Humer # Date 1397500345 -7200 # Node ID 5634b199c4dae0e38d61e5a27bbbab69911dde60 # Parent c73ce0dd35832a759ed8fc7880d3018556a29092 Truffle: API-change: renamed CallNode to DirectCallNode and added IndirectCallNode. diff -r c73ce0dd3583 -r 5634b199c4da CHANGELOG.md --- a/CHANGELOG.md Mon Apr 14 19:11:47 2014 +0200 +++ b/CHANGELOG.md Mon Apr 14 20:32:25 2014 +0200 @@ -12,7 +12,11 @@ ### Truffle * Support for collecting stack traces and for accessing the current frame in slow paths -* CallNode#inline was renamed to CallNode#forceInlining(). +* Renamed CallNode to DirectCallNode. +* Renamed TruffleRuntime#createCallNode to TruffleRuntime#createDirectCallNode. +* Added IndirectCallNode for calls with a changing CallTarget. +* Added TruffleRuntime#createIndirectCallNode to create an IndirectCallNode. +* DirectCallNode#inline was renamed to DirectCallNode#forceInlining(). * ... ## Version 0.2 diff -r c73ce0dd3583 -r 5634b199c4da graal/com.oracle.graal.truffle.hotspot/src/com/oracle/graal/truffle/hotspot/HotSpotFrameInstance.java --- a/graal/com.oracle.graal.truffle.hotspot/src/com/oracle/graal/truffle/hotspot/HotSpotFrameInstance.java Mon Apr 14 19:11:47 2014 +0200 +++ b/graal/com.oracle.graal.truffle.hotspot/src/com/oracle/graal/truffle/hotspot/HotSpotFrameInstance.java Mon Apr 14 20:32:25 2014 +0200 @@ -30,7 +30,6 @@ import com.oracle.truffle.api.*; import com.oracle.truffle.api.CompilerDirectives.SlowPath; import com.oracle.truffle.api.frame.*; -import com.oracle.truffle.api.impl.*; import com.oracle.truffle.api.nodes.*; public abstract class HotSpotFrameInstance implements FrameInstance { @@ -89,10 +88,10 @@ public abstract CallTarget getTargetCallTarget(); - public CallNode getCallNode() { + public DirectCallNode getCallNode() { Object receiver = stackFrame.getLocal(getNotifyIndex()); - if (receiver instanceof CallNode) { - return (CallNode) receiver; + if (receiver instanceof DirectCallNode) { + return (DirectCallNode) receiver; } else { return null; } @@ -100,14 +99,14 @@ /** * This class represents a frame that is taken from the - * {@link OptimizedCallNode#callProxy(MaterializedFrameNotify, OptimizedCallTarget, VirtualFrame, Object[], boolean)} + * {@link OptimizedDirectCallNode#callProxy(MaterializedFrameNotify, CallTarget, VirtualFrame, Object[], boolean)} * method. */ public static final class CallNodeFrame extends HotSpotFrameInstance { public static final Method METHOD; static { try { - METHOD = OptimizedCallNode.class.getDeclaredMethod("callProxy", MaterializedFrameNotify.class, OptimizedCallTarget.class, VirtualFrame.class, Object[].class, boolean.class); + METHOD = OptimizedDirectCallNode.class.getDeclaredMethod("callProxy", MaterializedFrameNotify.class, CallTarget.class, VirtualFrame.class, Object[].class, boolean.class); } catch (NoSuchMethodException | SecurityException e) { throw new GraalInternalError(e); } diff -r c73ce0dd3583 -r 5634b199c4da graal/com.oracle.graal.truffle.hotspot/src/com/oracle/graal/truffle/hotspot/HotSpotTruffleRuntime.java --- a/graal/com.oracle.graal.truffle.hotspot/src/com/oracle/graal/truffle/hotspot/HotSpotTruffleRuntime.java Mon Apr 14 19:11:47 2014 +0200 +++ b/graal/com.oracle.graal.truffle.hotspot/src/com/oracle/graal/truffle/hotspot/HotSpotTruffleRuntime.java Mon Apr 14 20:32:25 2014 +0200 @@ -92,14 +92,18 @@ return new HotSpotOptimizedCallTarget(rootNode, truffleCompiler, TruffleMinInvokeThreshold.getValue(), TruffleCompilationThreshold.getValue(), acceptForCompilation(rootNode)); } - public CallNode createCallNode(CallTarget target) { + public DirectCallNode createDirectCallNode(CallTarget target) { if (target instanceof OptimizedCallTarget) { - return OptimizedCallNode.create((OptimizedCallTarget) target); + return OptimizedDirectCallNode.create((OptimizedCallTarget) target); } else { - return new DefaultCallNode(target); + return new DefaultDirectCallNode(target); } } + public IndirectCallNode createIndirectCallNode() { + return new OptimizedIndirectCallNode(); + } + @Override public VirtualFrame createVirtualFrame(Object[] arguments, FrameDescriptor frameDescriptor) { return OptimizedCallTarget.createFrame(frameDescriptor, arguments); diff -r c73ce0dd3583 -r 5634b199c4da graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/MaterializedFrameNotify.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/MaterializedFrameNotify.java Mon Apr 14 20:32:25 2014 +0200 @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2014, 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.graal.truffle; + +import com.oracle.truffle.api.frame.FrameInstance.*; + +public interface MaterializedFrameNotify { + + FrameAccess getOutsideFrameAccess(); + + void setOutsideFrameAccess(FrameAccess outsideFrameAccess); +} diff -r c73ce0dd3583 -r 5634b199c4da graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallNode.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallNode.java Mon Apr 14 19:11:47 2014 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,194 +0,0 @@ -/* - * Copyright (c) 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.graal.truffle; - -import com.oracle.truffle.api.*; -import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; -import com.oracle.truffle.api.frame.*; -import com.oracle.truffle.api.frame.FrameInstance.*; -import com.oracle.truffle.api.impl.*; -import com.oracle.truffle.api.nodes.*; -import com.oracle.truffle.api.nodes.NodeUtil.NodeCountFilter; - -/** - * A call node with a constant {@link CallTarget} that can be optimized by Graal. - */ -public final class OptimizedCallNode extends DefaultCallNode { - - private int callCount; - private boolean trySplit = true; - - @CompilationFinal private boolean inlined; - @CompilationFinal private OptimizedCallTarget splitCallTarget; - - private OptimizedCallNode(OptimizedCallTarget target) { - super(target); - } - - @Override - public boolean isSplittable() { - return getCallTarget().getRootNode().isSplittable(); - } - - @Override - public OptimizedCallTarget getCallTarget() { - return (OptimizedCallTarget) super.getCallTarget(); - } - - public int getCallCount() { - return callCount; - } - - @Override - public OptimizedCallTarget getCurrentCallTarget() { - return (OptimizedCallTarget) super.getCurrentCallTarget(); - } - - @Override - public OptimizedCallTarget getSplitCallTarget() { - return splitCallTarget; - } - - @Override - public Object call(VirtualFrame frame, Object[] arguments) { - if (CompilerDirectives.inInterpreter()) { - onInterpreterCall(); - } - return callProxy(this, getCurrentCallTarget(), frame, arguments, inlined); - } - - public static Object callProxy(MaterializedFrameNotify notify, OptimizedCallTarget callTarget, VirtualFrame frame, Object[] arguments, boolean inlined) { - try { - if (notify.getOutsideFrameAccess() != FrameAccess.NONE) { - CompilerDirectives.materialize(frame); - } - if (inlined) { - return callTarget.callInlined(arguments); - } else { - return callTarget.call(arguments); - } - } finally { - // this assertion is needed to keep the values from being cleared as non-live locals - assert notify != null & callTarget != null & frame != null; - } - } - - private void onInterpreterCall() { - callCount++; - if (trySplit) { - if (callCount == 1) { - // on first call - getCurrentCallTarget().incrementKnownCallSites(); - } - if (callCount > 1 && !inlined) { - trySplit = false; - if (shouldSplit()) { - splitImpl(true); - } - } - } - } - - /* Called by the runtime system if this CallNode is really going to be inlined. */ - void inline() { - inlined = true; - } - - @Override - public boolean isInlined() { - return inlined; - } - - @Override - public boolean split() { - splitImpl(false); - return true; - } - - private void splitImpl(boolean heuristic) { - CompilerAsserts.neverPartOfCompilation(); - - OptimizedCallTarget splitTarget = (OptimizedCallTarget) Truffle.getRuntime().createCallTarget(getCallTarget().getRootNode().split()); - splitTarget.setSplitSource(getCallTarget()); - if (heuristic) { - OptimizedCallTargetLog.logSplit(this, getCallTarget(), splitTarget); - } - if (callCount >= 1) { - getCallTarget().decrementKnownCallSites(); - splitTarget.incrementKnownCallSites(); - } - this.splitCallTarget = splitTarget; - } - - private boolean shouldSplit() { - if (splitCallTarget != null) { - return false; - } - if (!TruffleCompilerOptions.TruffleSplittingEnabled.getValue()) { - return false; - } - if (!isSplittable()) { - return false; - } - OptimizedCallTarget splitTarget = getCallTarget(); - int nodeCount = OptimizedCallUtils.countNonTrivialNodes(splitTarget, false); - if (nodeCount > TruffleCompilerOptions.TruffleSplittingMaxCalleeSize.getValue()) { - return false; - } - - // disable recursive splitting for now - OptimizedCallTarget root = (OptimizedCallTarget) getRootNode().getCallTarget(); - if (root == splitTarget || root.getSplitSource() == splitTarget) { - // recursive call found - return false; - } - - // max one child call and callCount > 2 and kind of small number of nodes - if (isMaxSingleCall()) { - return true; - } - return countPolymorphic() >= 1; - } - - private boolean isMaxSingleCall() { - return NodeUtil.countNodes(getCurrentCallTarget().getRootNode(), new NodeCountFilter() { - public boolean isCounted(Node node) { - return node instanceof CallNode; - } - }) <= 1; - } - - private int countPolymorphic() { - return NodeUtil.countNodes(getCurrentCallTarget().getRootNode(), new NodeCountFilter() { - public boolean isCounted(Node node) { - NodeCost cost = node.getCost(); - boolean polymorphic = cost == NodeCost.POLYMORPHIC || cost == NodeCost.MEGAMORPHIC; - return polymorphic; - } - }); - } - - public static OptimizedCallNode create(OptimizedCallTarget target) { - return new OptimizedCallNode(target); - } -} diff -r c73ce0dd3583 -r 5634b199c4da graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallTargetLog.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallTargetLog.java Mon Apr 14 19:11:47 2014 +0200 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallTargetLog.java Mon Apr 14 20:32:25 2014 +0200 @@ -64,8 +64,8 @@ } private static void logInliningDecisionRecursive(TruffleInliningResult result, int depth) { - List callNodes = searchCallNodes(result.getCallTarget()); - for (OptimizedCallNode callNode : callNodes) { + List callNodes = searchCallNodes(result.getCallTarget()); + for (OptimizedDirectCallNode callNode : callNodes) { TruffleInliningProfile profile = result.getProfiles().get(callNode); boolean inlined = result.isInlined(callNode); String msg = inlined ? "inline success" : "inline failed"; @@ -76,12 +76,12 @@ } } - private static List searchCallNodes(final OptimizedCallTarget target) { - final List callNodes = new ArrayList<>(); + private static List searchCallNodes(final OptimizedCallTarget target) { + final List callNodes = new ArrayList<>(); target.getRootNode().accept(new NodeVisitor() { public boolean visit(Node node) { - if (node instanceof OptimizedCallNode) { - callNodes.add((OptimizedCallNode) node); + if (node instanceof OptimizedDirectCallNode) { + callNodes.add((OptimizedDirectCallNode) node); } return true; } @@ -169,8 +169,8 @@ String msg = kind == NodeCost.MEGAMORPHIC ? "megamorphic" : "polymorphic"; log(0, msg, node.toString(), props); } - if (node instanceof CallNode) { - CallNode callNode = (CallNode) node; + if (node instanceof DirectCallNode) { + DirectCallNode callNode = (DirectCallNode) node; if (callNode.isInliningForced()) { callNode.getCurrentRootNode().accept(this); } @@ -184,7 +184,7 @@ private static int splitCount = 0; - static void logSplit(OptimizedCallNode callNode, OptimizedCallTarget target, OptimizedCallTarget newTarget) { + static void logSplit(OptimizedDirectCallNode callNode, OptimizedCallTarget target, OptimizedCallTarget newTarget) { if (TraceTruffleSplitting.getValue()) { Map properties = new LinkedHashMap<>(); addASTSizeProperty(target, properties); diff -r c73ce0dd3583 -r 5634b199c4da graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallUtils.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallUtils.java Mon Apr 14 19:11:47 2014 +0200 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallUtils.java Mon Apr 14 20:32:25 2014 +0200 @@ -30,7 +30,7 @@ public static int countCalls(OptimizedCallTarget target) { return NodeUtil.countNodes(target.getRootNode(), new NodeCountFilter() { public boolean isCounted(Node node) { - return node instanceof CallNode; + return node instanceof DirectCallNode; } }, true); } @@ -38,7 +38,7 @@ public static int countCallsInlined(OptimizedCallTarget target) { return NodeUtil.countNodes(target.getRootNode(), new NodeCountFilter() { public boolean isCounted(Node node) { - return (node instanceof OptimizedCallNode) && ((OptimizedCallNode) node).isInlined(); + return (node instanceof OptimizedDirectCallNode) && ((OptimizedDirectCallNode) node).isInlined(); } }, true); } diff -r c73ce0dd3583 -r 5634b199c4da graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedDirectCallNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedDirectCallNode.java Mon Apr 14 20:32:25 2014 +0200 @@ -0,0 +1,220 @@ +/* + * Copyright (c) 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.graal.truffle; + +import com.oracle.truffle.api.*; +import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; +import com.oracle.truffle.api.frame.FrameInstance.FrameAccess; +import com.oracle.truffle.api.frame.*; +import com.oracle.truffle.api.nodes.*; +import com.oracle.truffle.api.nodes.NodeUtil.NodeCountFilter; + +/** + * A call node with a constant {@link CallTarget} that can be optimized by Graal. + */ +public final class OptimizedDirectCallNode extends DirectCallNode implements MaterializedFrameNotify { + + private int callCount; + private boolean trySplit = true; + private boolean inliningForced; + + @CompilationFinal private boolean inlined; + @CompilationFinal private OptimizedCallTarget splitCallTarget; + @CompilationFinal private FrameAccess outsideFrameAccess = FrameAccess.NONE; + + private OptimizedDirectCallNode(OptimizedCallTarget target) { + super(target); + } + + @Override + public Object call(VirtualFrame frame, Object[] arguments) { + if (CompilerDirectives.inInterpreter()) { + onInterpreterCall(); + } + return callProxy(this, getCurrentCallTarget(), frame, arguments, inlined); + } + + public static Object callProxy(MaterializedFrameNotify notify, CallTarget callTarget, VirtualFrame frame, Object[] arguments, boolean inlined) { + try { + if (notify.getOutsideFrameAccess() != FrameAccess.NONE) { + CompilerDirectives.materialize(frame); + } + if (inlined) { + return ((OptimizedCallTarget) callTarget).callInlined(arguments); + } else { + return callTarget.call(arguments); + } + } finally { + // this assertion is needed to keep the values from being cleared as non-live locals + assert notify != null & callTarget != null & frame != null; + } + } + + @Override + public boolean isInlinable() { + return true; + } + + @Override + public void forceInlining() { + inliningForced = true; + } + + @Override + public boolean isInliningForced() { + return inliningForced; + } + + @Override + public FrameAccess getOutsideFrameAccess() { + return outsideFrameAccess; + } + + @Override + public void setOutsideFrameAccess(FrameAccess outsideFrameAccess) { + this.outsideFrameAccess = outsideFrameAccess; + } + + @Override + public boolean isSplittable() { + return getCallTarget().getRootNode().isSplittable(); + } + + @Override + public OptimizedCallTarget getCallTarget() { + return (OptimizedCallTarget) super.getCallTarget(); + } + + public int getCallCount() { + return callCount; + } + + @Override + public OptimizedCallTarget getCurrentCallTarget() { + return (OptimizedCallTarget) super.getCurrentCallTarget(); + } + + @Override + public OptimizedCallTarget getSplitCallTarget() { + return splitCallTarget; + } + + private void onInterpreterCall() { + callCount++; + if (trySplit) { + if (callCount == 1) { + // on first call + getCurrentCallTarget().incrementKnownCallSites(); + } + if (callCount > 1 && !inlined) { + trySplit = false; + if (shouldSplit()) { + splitImpl(true); + } + } + } + } + + /* Called by the runtime system if this CallNode is really going to be inlined. */ + void inline() { + inlined = true; + } + + @Override + public boolean isInlined() { + return inlined; + } + + @Override + public boolean split() { + splitImpl(false); + return true; + } + + private void splitImpl(boolean heuristic) { + CompilerAsserts.neverPartOfCompilation(); + + OptimizedCallTarget splitTarget = (OptimizedCallTarget) Truffle.getRuntime().createCallTarget(getCallTarget().getRootNode().split()); + splitTarget.setSplitSource(getCallTarget()); + if (heuristic) { + OptimizedCallTargetLog.logSplit(this, getCallTarget(), splitTarget); + } + if (callCount >= 1) { + getCallTarget().decrementKnownCallSites(); + splitTarget.incrementKnownCallSites(); + } + this.splitCallTarget = splitTarget; + } + + private boolean shouldSplit() { + if (splitCallTarget != null) { + return false; + } + if (!TruffleCompilerOptions.TruffleSplittingEnabled.getValue()) { + return false; + } + if (!isSplittable()) { + return false; + } + OptimizedCallTarget splitTarget = getCallTarget(); + int nodeCount = OptimizedCallUtils.countNonTrivialNodes(splitTarget, false); + if (nodeCount > TruffleCompilerOptions.TruffleSplittingMaxCalleeSize.getValue()) { + return false; + } + + // disable recursive splitting for now + OptimizedCallTarget root = (OptimizedCallTarget) getRootNode().getCallTarget(); + if (root == splitTarget || root.getSplitSource() == splitTarget) { + // recursive call found + return false; + } + + // max one child call and callCount > 2 and kind of small number of nodes + if (isMaxSingleCall()) { + return true; + } + return countPolymorphic() >= 1; + } + + private boolean isMaxSingleCall() { + return NodeUtil.countNodes(getCurrentCallTarget().getRootNode(), new NodeCountFilter() { + public boolean isCounted(Node node) { + return node instanceof DirectCallNode; + } + }) <= 1; + } + + private int countPolymorphic() { + return NodeUtil.countNodes(getCurrentCallTarget().getRootNode(), new NodeCountFilter() { + public boolean isCounted(Node node) { + NodeCost cost = node.getCost(); + boolean polymorphic = cost == NodeCost.POLYMORPHIC || cost == NodeCost.MEGAMORPHIC; + return polymorphic; + } + }); + } + + public static OptimizedDirectCallNode create(OptimizedCallTarget target) { + return new OptimizedDirectCallNode(target); + } +} diff -r c73ce0dd3583 -r 5634b199c4da graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedIndirectCallNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedIndirectCallNode.java Mon Apr 14 20:32:25 2014 +0200 @@ -0,0 +1,53 @@ +/* + * Copyright (c) 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.graal.truffle; + +import com.oracle.truffle.api.*; +import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; +import com.oracle.truffle.api.frame.FrameInstance.FrameAccess; +import com.oracle.truffle.api.frame.*; +import com.oracle.truffle.api.nodes.*; + +/** + * A call node with a constant {@link CallTarget} that can be optimized by Graal. + */ +public final class OptimizedIndirectCallNode extends IndirectCallNode implements MaterializedFrameNotify { + + @CompilationFinal private FrameAccess outsideFrameAccess = FrameAccess.NONE; + + @Override + public Object call(VirtualFrame frame, CallTarget target, Object[] arguments) { + return OptimizedDirectCallNode.callProxy(this, target, frame, arguments, false); + } + + @Override + public FrameAccess getOutsideFrameAccess() { + return outsideFrameAccess; + } + + @Override + public void setOutsideFrameAccess(FrameAccess outsideFrameAccess) { + this.outsideFrameAccess = outsideFrameAccess; + } + +} diff -r c73ce0dd3583 -r 5634b199c4da graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleInliningHandler.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleInliningHandler.java Mon Apr 14 19:11:47 2014 +0200 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleInliningHandler.java Mon Apr 14 20:32:25 2014 +0200 @@ -67,23 +67,23 @@ } private List lookupProfiles(final OptimizedCallTarget target, int depth) { - final List callNodes = new ArrayList<>(); + final List callNodes = new ArrayList<>(); target.getRootNode().accept(new NodeVisitor() { public boolean visit(Node node) { - if (node instanceof OptimizedCallNode) { - callNodes.add((OptimizedCallNode) node); + if (node instanceof OptimizedDirectCallNode) { + callNodes.add((OptimizedDirectCallNode) node); } return true; } }); final List profiles = new ArrayList<>(); - for (OptimizedCallNode callNode : callNodes) { + for (OptimizedDirectCallNode callNode : callNodes) { profiles.add(lookupProfile(target, callNode, depth)); } return profiles; } - public TruffleInliningProfile lookupProfile(OptimizedCallTarget parentTarget, OptimizedCallNode ocn, int depth) { + public TruffleInliningProfile lookupProfile(OptimizedCallTarget parentTarget, OptimizedDirectCallNode ocn, int depth) { OptimizedCallTarget target = ocn.getCurrentCallTarget(); int callSites = ocn.getCurrentCallTarget().getKnownCallSiteCount(); @@ -116,7 +116,7 @@ return policy; } - private static double calculateFrequency(OptimizedCallTarget target, OptimizedCallNode ocn) { + private static double calculateFrequency(OptimizedCallTarget target, OptimizedDirectCallNode ocn) { return (double) Math.max(1, target.getCompilationProfile().getCallCount()) / Math.max(1, ocn.getCallCount()); } diff -r c73ce0dd3583 -r 5634b199c4da graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleInliningProfile.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleInliningProfile.java Mon Apr 14 19:11:47 2014 +0200 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleInliningProfile.java Mon Apr 14 20:32:25 2014 +0200 @@ -26,7 +26,7 @@ public class TruffleInliningProfile { - private final OptimizedCallNode callNode; + private final OptimizedDirectCallNode callNode; private final int nodeCount; private final int deepNodeCount; private final int callSites; @@ -39,7 +39,7 @@ private int queryIndex = -1; private double score; - public TruffleInliningProfile(OptimizedCallNode callNode, int callSites, int nodeCount, int deepNodeCount, double frequency, boolean forced, boolean recursiveCall, + public TruffleInliningProfile(OptimizedDirectCallNode callNode, int callSites, int nodeCount, int deepNodeCount, double frequency, boolean forced, boolean recursiveCall, TruffleInliningResult recursiveResult) { this.callNode = callNode; this.callSites = callSites; @@ -55,7 +55,7 @@ return recursiveCall; } - public OptimizedCallNode getCallNode() { + public OptimizedDirectCallNode getCallNode() { return callNode; } diff -r c73ce0dd3583 -r 5634b199c4da graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleInliningResult.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleInliningResult.java Mon Apr 14 19:11:47 2014 +0200 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleInliningResult.java Mon Apr 14 20:32:25 2014 +0200 @@ -27,7 +27,7 @@ public final class TruffleInliningResult implements Iterable { private final OptimizedCallTarget callTarget; - private final Map profiles; + private final Map profiles; private final Set inlined; private final int nodeCount; @@ -41,7 +41,7 @@ this.inlined = inlined; } - public Map getProfiles() { + public Map getProfiles() { return profiles; } @@ -53,7 +53,7 @@ return callTarget; } - public boolean isInlined(OptimizedCallNode path) { + public boolean isInlined(OptimizedDirectCallNode path) { return inlined.contains(profiles.get(path)); } diff -r c73ce0dd3583 -r 5634b199c4da graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleTreeDumpHandler.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleTreeDumpHandler.java Mon Apr 14 19:11:47 2014 +0200 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleTreeDumpHandler.java Mon Apr 14 20:32:25 2014 +0200 @@ -53,9 +53,9 @@ visitor.setChildSupplier(new ChildSupplier() { public Object startNode(Object callNode) { - if (callNode instanceof OptimizedCallNode) { - if (((OptimizedCallNode) callNode).isInlined()) { - return ((OptimizedCallNode) callNode).getCurrentRootNode(); + if (callNode instanceof OptimizedDirectCallNode) { + if (((OptimizedDirectCallNode) callNode).isInlined()) { + return ((OptimizedDirectCallNode) callNode).getCurrentRootNode(); } } return null; diff -r c73ce0dd3583 -r 5634b199c4da graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/ThreadSafetyTest.java --- a/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/ThreadSafetyTest.java Mon Apr 14 19:11:47 2014 +0200 +++ b/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/ThreadSafetyTest.java Mon Apr 14 20:32:25 2014 +0200 @@ -50,7 +50,7 @@ RecursiveCallNode callNode = new RecursiveCallNode(new ConstNode(42)); TestRootNode rootNode2 = new TestRootNode(new RewritingNode(new RewritingNode(new RewritingNode(new RewritingNode(new RewritingNode(callNode)))))); final CallTarget target2 = runtime.createCallTarget(rootNode2); - callNode.setCallNode(runtime.createCallNode(target2)); + callNode.setCallNode(runtime.createDirectCallNode(target2)); NodeUtil.verify(rootNode2); testTarget(target1, 47, 1_000_000); @@ -165,7 +165,7 @@ } static class RecursiveCallNode extends ValueNode { - @Child CallNode callNode; + @Child DirectCallNode callNode; @Child private ValueNode valueNode; RecursiveCallNode(ValueNode value) { @@ -182,7 +182,7 @@ } } - void setCallNode(CallNode callNode) { + void setCallNode(DirectCallNode callNode) { this.callNode = insert(callNode); } } diff -r c73ce0dd3583 -r 5634b199c4da graal/com.oracle.truffle.api/src/com/oracle/truffle/api/TruffleRuntime.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/TruffleRuntime.java Mon Apr 14 19:11:47 2014 +0200 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/TruffleRuntime.java Mon Apr 14 20:32:25 2014 +0200 @@ -50,7 +50,20 @@ */ RootCallTarget createCallTarget(RootNode rootNode); - CallNode createCallNode(CallTarget target); + /** + * Creates a new runtime specific version of {@link DirectCallNode}. + * + * @param target the direct {@link CallTarget} to call + * @return the new call node + */ + DirectCallNode createDirectCallNode(CallTarget target); + + /** + * Creates a new runtime specific version of {@link IndirectCallNode}. + * + * @return the new call node + */ + IndirectCallNode createIndirectCallNode(); /** * Creates a new assumption object that can be checked and invalidated. @@ -104,4 +117,5 @@ * important to note that this {@link FrameInstance} supports only slow path access. */ FrameInstance getCurrentFrame(); + } diff -r c73ce0dd3583 -r 5634b199c4da graal/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/FrameInstance.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/FrameInstance.java Mon Apr 14 19:11:47 2014 +0200 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/FrameInstance.java Mon Apr 14 20:32:25 2014 +0200 @@ -40,7 +40,7 @@ boolean isVirtualFrame(); - CallNode getCallNode(); + DirectCallNode getCallNode(); CallTarget getCallTarget(); diff -r c73ce0dd3583 -r 5634b199c4da graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultCallNode.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultCallNode.java Mon Apr 14 19:11:47 2014 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,97 +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.impl; - -import com.oracle.truffle.api.*; -import com.oracle.truffle.api.CompilerDirectives.*; -import com.oracle.truffle.api.frame.*; -import com.oracle.truffle.api.frame.FrameInstance.*; -import com.oracle.truffle.api.nodes.*; - -public class DefaultCallNode extends CallNode implements MaterializedFrameNotify { - - @CompilationFinal private FrameAccess outsideFrameAccess = FrameAccess.NONE; - - private boolean inliningForced; - - public DefaultCallNode(CallTarget target) { - super(target); - } - - @Override - public Object call(VirtualFrame frame, Object[] arguments) { - return getCurrentCallTarget().call(arguments); - } - - @Override - public FrameAccess getOutsideFrameAccess() { - return outsideFrameAccess; - } - - @Override - public void setOutsideFrameAccess(FrameAccess outsideFrameAccess) { - this.outsideFrameAccess = outsideFrameAccess; - } - - @Override - public void forceInlining() { - inliningForced = true; - } - - @Override - public CallTarget getSplitCallTarget() { - return null; - } - - @Override - public boolean split() { - return false; - } - - @Override - public boolean isInlined() { - return false; - } - - @Override - public boolean isSplittable() { - return false; - } - - @Override - public boolean isInliningForced() { - return inliningForced; - } - - @Override - public boolean isInlinable() { - return false; - } - - @Override - public String toString() { - return (getParent() != null ? getParent().toString() : super.toString()) + " call " + getCurrentCallTarget().toString(); - } -} diff -r c73ce0dd3583 -r 5634b199c4da graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultDirectCallNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultDirectCallNode.java Mon Apr 14 20:32:25 2014 +0200 @@ -0,0 +1,86 @@ +/* + * 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.impl; + +import com.oracle.truffle.api.*; +import com.oracle.truffle.api.frame.*; +import com.oracle.truffle.api.nodes.*; + +/** + * This is runtime specific API. Do not use in a guest language. + */ +public final class DefaultDirectCallNode extends DirectCallNode { + + private boolean inliningForced; + + public DefaultDirectCallNode(CallTarget target) { + super(target); + } + + @Override + public Object call(VirtualFrame frame, Object[] arguments) { + return getCurrentCallTarget().call(arguments); + } + + @Override + public void forceInlining() { + inliningForced = true; + } + + @Override + public boolean isInliningForced() { + return inliningForced; + } + + @Override + public CallTarget getSplitCallTarget() { + return null; + } + + @Override + public boolean split() { + return false; + } + + @Override + public boolean isInlined() { + return false; + } + + @Override + public boolean isSplittable() { + return false; + } + + @Override + public boolean isInlinable() { + return false; + } + + @Override + public String toString() { + return (getParent() != null ? getParent().toString() : super.toString()) + " call " + getCurrentCallTarget().toString(); + } +} diff -r c73ce0dd3583 -r 5634b199c4da graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultIndirectCallNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultIndirectCallNode.java Mon Apr 14 20:32:25 2014 +0200 @@ -0,0 +1,41 @@ +/* + * 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.impl; + +import com.oracle.truffle.api.*; +import com.oracle.truffle.api.frame.*; +import com.oracle.truffle.api.nodes.*; + +/** + * This is runtime specific API. Do not use in a guest language. + */ +final class DefaultIndirectCallNode extends IndirectCallNode { + + @Override + public Object call(VirtualFrame frame, CallTarget target, Object[] arguments) { + return target.call(arguments); + } + +} diff -r c73ce0dd3583 -r 5634b199c4da graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultTruffleRuntime.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultTruffleRuntime.java Mon Apr 14 19:11:47 2014 +0200 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultTruffleRuntime.java Mon Apr 14 20:32:25 2014 +0200 @@ -53,8 +53,12 @@ return new DefaultCallTarget(rootNode); } - public CallNode createCallNode(CallTarget target) { - return new DefaultCallNode(target); + public DirectCallNode createDirectCallNode(CallTarget target) { + return new DefaultDirectCallNode(target); + } + + public IndirectCallNode createIndirectCallNode() { + return new DefaultIndirectCallNode(); } @Override diff -r c73ce0dd3583 -r 5634b199c4da graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/MaterializedFrameNotify.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/MaterializedFrameNotify.java Mon Apr 14 19:11:47 2014 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,34 +0,0 @@ -/* - * Copyright (c) 2014, 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.impl; - -import com.oracle.truffle.api.frame.FrameInstance.*; - -public interface MaterializedFrameNotify { - - FrameAccess getOutsideFrameAccess(); - - void setOutsideFrameAccess(FrameAccess outsideFrameAccess); -} diff -r c73ce0dd3583 -r 5634b199c4da graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/CallNode.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/CallNode.java Mon Apr 14 19:11:47 2014 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,166 +0,0 @@ -/* - * 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.*; - -/** - * Represents a call to a {@link CallTarget} in the Truffle AST. In addition to calling the - * {@link CallTarget}, this {@link Node} enables the runtime system to implement further - * optimizations. Optimizations that can possibly be applied to a {@link CallNode} are inlining and - * splitting. Inlining inlines this call site into the call graph of the parent {@link CallTarget}. - * Splitting duplicates the {@link CallTarget} using {@link RootNode#split()} to collect call site - * sensitive profiling information. - * - * Please note: This class is not intended to be subclassed by guest language implementations. - * - * @see TruffleRuntime#createCallNode(CallTarget) - * @see #forceInlining() - * @see #split() - */ -public abstract class CallNode extends Node { - - protected final CallTarget callTarget; - - protected CallNode(CallTarget callTarget) { - this.callTarget = callTarget; - } - - /** - * Calls the inner {@link CallTarget} returned by {@link #getCurrentCallTarget()}. - * - * @param arguments the arguments that should be passed to the callee - * @return the return result of the call - */ - public abstract Object call(VirtualFrame frame, Object[] arguments); - - /** - * Returns the originally supplied {@link CallTarget} when this call node was created. Please - * note that the returned {@link CallTarget} is not necessarily the {@link CallTarget} that is - * called. For that use {@link #getCurrentCallTarget()} instead. - * - * @return the {@link CallTarget} provided. - */ - public CallTarget getCallTarget() { - return callTarget; - } - - /** - * Returns true if the underlying runtime system supports inlining for the - * {@link CallTarget} in this {@link CallNode}. - * - * @return true if inlining is supported. - */ - public abstract boolean isInlinable(); - - /** - * Returns true if the {@link CallTarget} is forced to be inlined. A - * {@link CallNode} can either be inlined manually by invoking {@link #forceInlining()} or by - * the runtime system which may at any point decide to inline. - * - * @return true if this method was inlined else false. - */ - public abstract boolean isInliningForced(); - - /** - * Enforces the runtime system to inline the {@link CallTarget} at this call site. If the - * runtime system does not support inlining or it is already inlined this method has no effect. - * The runtime system may decide to not inline calls which were forced to inline. - */ - public abstract void forceInlining(); - - /** - * Returns true if the runtime system has decided to inline this call-site. If the - * {@link CallNode} was forced to inline then this does not necessarily mean that the - * {@link CallNode} is really going to be inlined. This depends on whether or not the runtime - * system supports inlining. The runtime system may also decide to not inline calls which were - * forced to inline. - */ - public abstract boolean isInlined(); - - /** - * Returns true if this {@link CallNode} can be split. A {@link CallNode} can only - * be split if the runtime system supports splitting and if the {@link RootNode} contained the - * {@link CallTarget} returns true for {@link RootNode#isSplittable()}. - * - * @return true if the target can be split - */ - public abstract boolean isSplittable(); - - /** - * Enforces the runtime system to split the {@link CallTarget}. If the {@link CallNode} is not - * splittable this methods has no effect. - */ - public abstract boolean split(); - - /** - * Returns true if the target of the {@link CallNode} was split. - * - * @return if the target was split - */ - public final boolean isSplit() { - return getSplitCallTarget() != null; - } - - /** - * Returns the split {@link CallTarget} if this method is split. - * - * @return the split {@link CallTarget} - */ - public abstract CallTarget getSplitCallTarget(); - - /** - * Returns the used call target when {@link #call(VirtualFrame, Object[])} is invoked. If the - * {@link CallTarget} was split this method returns the {@link CallTarget} returned by - * {@link #getSplitCallTarget()}. - * - * @return the used {@link CallTarget} when node is called - */ - public CallTarget getCurrentCallTarget() { - CallTarget split = getSplitCallTarget(); - if (split != null) { - return split; - } else { - return getCallTarget(); - } - } - - /** - * Returns the {@link RootNode} associated with {@link CallTarget} returned by - * {@link #getCurrentCallTarget()}. If the stored {@link CallTarget} does not contain a - * {@link RootNode} this method returns null. - * - * @see #getCurrentCallTarget() - * @return the root node of the used call target - */ - public final RootNode getCurrentRootNode() { - CallTarget target = getCurrentCallTarget(); - if (target instanceof RootCallTarget) { - return ((RootCallTarget) target).getRootNode(); - } - return null; - } -} diff -r c73ce0dd3583 -r 5634b199c4da graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/DirectCallNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/DirectCallNode.java Mon Apr 14 20:32:25 2014 +0200 @@ -0,0 +1,170 @@ +/* + * 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.*; + +/** + * Represents a direct call to a {@link CallTarget}. Direct calls are calls for which the + * {@link CallTarget} remains the same for each consecutive call. This part of the Truffle API + * enables the runtime system to perform additional optimizations on direct calls. + * + * Optimizations that can be applied to a {@link DirectCallNode} are inlining and splitting. + * Inlining inlines this call site into the call graph of the parent {@link CallTarget}. Splitting + * duplicates the {@link CallTarget} using {@link RootNode#split()} to collect call site sensitive + * profiling information. + * + * Please note: This class is not intended to be subclassed by guest language implementations. + * + * @see IndirectCallNode for calls with a non-constant target + * @see TruffleRuntime#createDirectCallNode(CallTarget) + * @see #forceInlining() + * @see #split() + */ +public abstract class DirectCallNode extends Node { + + protected final CallTarget callTarget; + + protected DirectCallNode(CallTarget callTarget) { + this.callTarget = callTarget; + } + + /** + * Calls the inner {@link CallTarget} returned by {@link #getCurrentCallTarget()}. + * + * @param arguments the arguments that should be passed to the callee + * @return the return result of the call + */ + public abstract Object call(VirtualFrame frame, Object[] arguments); + + /** + * Returns the originally supplied {@link CallTarget} when this call node was created. Please + * note that the returned {@link CallTarget} is not necessarily the {@link CallTarget} that is + * called. For that use {@link #getCurrentCallTarget()} instead. + * + * @return the {@link CallTarget} provided. + */ + public CallTarget getCallTarget() { + return callTarget; + } + + /** + * Returns true if the underlying runtime system supports inlining for the + * {@link CallTarget} in this {@link DirectCallNode}. + * + * @return true if inlining is supported. + */ + public abstract boolean isInlinable(); + + /** + * Returns true if the {@link CallTarget} is forced to be inlined. A + * {@link DirectCallNode} can either be inlined manually by invoking {@link #forceInlining()} or + * by the runtime system which may at any point decide to inline. + * + * @return true if this method was inlined else false. + */ + public abstract boolean isInliningForced(); + + /** + * Enforces the runtime system to inline the {@link CallTarget} at this call site. If the + * runtime system does not support inlining or it is already inlined this method has no effect. + * The runtime system may decide to not inline calls which were forced to inline. + */ + public abstract void forceInlining(); + + /** + * Returns true if the runtime system has decided to inline this call-site. If the + * {@link DirectCallNode} was forced to inline then this does not necessarily mean that the + * {@link DirectCallNode} is really going to be inlined. This depends on whether or not the + * runtime system supports inlining. The runtime system may also decide to not inline calls + * which were forced to inline. + */ + public abstract boolean isInlined(); + + /** + * Returns true if this {@link DirectCallNode} can be split. A + * {@link DirectCallNode} can only be split if the runtime system supports splitting and if the + * {@link RootNode} contained the {@link CallTarget} returns true for + * {@link RootNode#isSplittable()}. + * + * @return true if the target can be split + */ + public abstract boolean isSplittable(); + + /** + * Enforces the runtime system to split the {@link CallTarget}. If the {@link DirectCallNode} is + * not splittable this methods has no effect. + */ + public abstract boolean split(); + + /** + * Returns true if the target of the {@link DirectCallNode} was split. + * + * @return if the target was split + */ + public final boolean isSplit() { + return getSplitCallTarget() != null; + } + + /** + * Returns the split {@link CallTarget} if this method is split. + * + * @return the split {@link CallTarget} + */ + public abstract CallTarget getSplitCallTarget(); + + /** + * Returns the used call target when {@link #call(VirtualFrame, Object[])} is invoked. If the + * {@link CallTarget} was split this method returns the {@link CallTarget} returned by + * {@link #getSplitCallTarget()}. + * + * @return the used {@link CallTarget} when node is called + */ + public CallTarget getCurrentCallTarget() { + CallTarget split = getSplitCallTarget(); + if (split != null) { + return split; + } else { + return getCallTarget(); + } + } + + /** + * Returns the {@link RootNode} associated with {@link CallTarget} returned by + * {@link #getCurrentCallTarget()}. If the stored {@link CallTarget} does not contain a + * {@link RootNode} this method returns null. + * + * @see #getCurrentCallTarget() + * @return the root node of the used call target + */ + public final RootNode getCurrentRootNode() { + CallTarget target = getCurrentCallTarget(); + if (target instanceof RootCallTarget) { + return ((RootCallTarget) target).getRootNode(); + } + return null; + } +} diff -r c73ce0dd3583 -r 5634b199c4da graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/IndirectCallNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/IndirectCallNode.java Mon Apr 14 20:32:25 2014 +0200 @@ -0,0 +1,51 @@ +/* + * 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.*; + +/** + * Represents an indirect call to a {@link CallTarget}. Indirect calls are calls for which the + * {@link CallTarget} may change dynamically for each consecutive call. This part of the Truffle API + * enables the runtime system to perform additional optimizations on indirect calls. + * + * Please note: This class is not intended to be sub classed by guest language implementations. + * + * @see DirectCallNode for faster calls with a constantly known {@link CallTarget}. + */ +public abstract class IndirectCallNode extends Node { + + /** + * Performs an indirect call to the given {@link CallTarget} target with the provided arguments. + * + * @param frame the caller frame + * @param target the {@link CallTarget} to call + * @param arguments the arguments to provide + * @return the return value of the call + */ + public abstract Object call(VirtualFrame frame, CallTarget target, Object[] arguments); + +} diff -r c73ce0dd3583 -r 5634b199c4da graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/NodeUtil.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/NodeUtil.java Mon Apr 14 19:11:47 2014 +0200 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/NodeUtil.java Mon Apr 14 20:32:25 2014 +0200 @@ -636,8 +636,8 @@ nodeCount++; } - if (visitInlinedCallNodes && node instanceof CallNode) { - CallNode call = (CallNode) node; + if (visitInlinedCallNodes && node instanceof DirectCallNode) { + DirectCallNode call = (DirectCallNode) node; if (call.isInlined()) { Node target = ((RootCallTarget) call.getCurrentCallTarget()).getRootNode(); if (target != null) { diff -r c73ce0dd3583 -r 5634b199c4da 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 Mon Apr 14 19:11:47 2014 +0200 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/RootNode.java Mon Apr 14 20:32:25 2014 +0200 @@ -67,7 +67,7 @@ /** * Returns true if this {@link RootNode} can be split. A {@link RootNode} can be - * split inside of a {@link CallTarget} that is invoked using a {@link CallNode}. If this method + * split inside of a {@link CallTarget} that is invoked using a {@link DirectCallNode}. If this method * returns true a proper implementation of {@link #split()} must also be provided. * This method is intended to be overridden by a subclass. * diff -r c73ce0dd3583 -r 5634b199c4da graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/call/SLDirectDispatchNode.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/call/SLDirectDispatchNode.java Mon Apr 14 19:11:47 2014 +0200 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/call/SLDirectDispatchNode.java Mon Apr 14 20:32:25 2014 +0200 @@ -36,11 +36,11 @@ private final SLFunction cachedFunction; /** - * {@link CallNode} is part of the Truffle API and handles all the steps necessary for method + * {@link DirectCallNode} is part of the Truffle API and handles all the steps necessary for method * inlining: if the call is executed frequently and the callee is small, then the call is * inlined, i.e., the call node is replaced with a copy of the callee's AST. */ - @Child private CallNode callCachedTargetNode; + @Child private DirectCallNode callCachedTargetNode; /** Assumption that the {@link #callCachedTargetNode} is still valid. */ private final Assumption cachedTargetStable; @@ -53,7 +53,7 @@ protected SLDirectDispatchNode(SLAbstractDispatchNode next, SLFunction cachedFunction) { this.cachedFunction = cachedFunction; - this.callCachedTargetNode = Truffle.getRuntime().createCallNode(cachedFunction.getCallTarget()); + this.callCachedTargetNode = Truffle.getRuntime().createDirectCallNode(cachedFunction.getCallTarget()); this.cachedTargetStable = cachedFunction.getCallTargetStable(); this.nextNode = next; } diff -r c73ce0dd3583 -r 5634b199c4da graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/call/SLGenericDispatchNode.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/call/SLGenericDispatchNode.java Mon Apr 14 19:11:47 2014 +0200 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/call/SLGenericDispatchNode.java Mon Apr 14 20:32:25 2014 +0200 @@ -22,19 +22,23 @@ */ package com.oracle.truffle.sl.nodes.call; -import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; +import com.oracle.truffle.api.*; import com.oracle.truffle.api.frame.*; -import com.oracle.truffle.api.frame.FrameInstance.FrameAccess; -import com.oracle.truffle.api.impl.*; +import com.oracle.truffle.api.nodes.*; import com.oracle.truffle.sl.runtime.*; /** * Slow-path code for a call, used when the polymorphic inline cache exceeded its maximum size. Such * calls are not optimized any further, e.g., no method inlining is performed. */ -final class SLGenericDispatchNode extends SLAbstractDispatchNode implements MaterializedFrameNotify { +final class SLGenericDispatchNode extends SLAbstractDispatchNode { - @CompilationFinal private FrameAccess outsideFrameAccess = FrameAccess.NONE; + /** + * {@link IndirectCallNode} is part of the Truffle API and handles all the steps necessary for + * calling a megamorphic call-site. The Graal specific version of this node performs additional + * optimizations for the fast access of the SimpleLanguage stack trace. + */ + @Child private IndirectCallNode callNode = Truffle.getRuntime().createIndirectCallNode(); @Override protected Object executeDispatch(VirtualFrame frame, SLFunction function, Object[] arguments) { @@ -42,14 +46,7 @@ * SL has a quite simple call lookup: just ask the function for the current call target, and * call it. */ - return function.getCallTarget().call(arguments); + return callNode.call(frame, function.getCallTarget(), arguments); } - public FrameAccess getOutsideFrameAccess() { - return outsideFrameAccess; - } - - public void setOutsideFrameAccess(FrameAccess outsideFrameAccess) { - this.outsideFrameAccess = outsideFrameAccess; - } }