# HG changeset patch # User Christian Humer # Date 1395063059 -3600 # Node ID b1dded9c748a2572b18ed86b5f4cc77f8f6e6f21 # Parent 6681b9eb3f4cebbfcb60715f533429317591c356# Parent 82e4fe6fa52594024a30f0f288cff16de6b13571 Merge. diff -r 82e4fe6fa525 -r b1dded9c748a 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 Mar 17 13:08:32 2014 +0100 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallNode.java Mon Mar 17 14:30:59 2014 +0100 @@ -28,7 +28,7 @@ import com.oracle.truffle.api.frame.*; import com.oracle.truffle.api.impl.*; import com.oracle.truffle.api.nodes.*; -import com.oracle.truffle.api.nodes.NodeInfo.Kind; +import com.oracle.truffle.api.nodes.NodeUtil.NodeFilter; /** * Call target that is optimized by Graal upon surpassing a specific invocation threshold. @@ -85,6 +85,11 @@ return new DefaultOptimizedCallNode(target); } + @Override + public boolean isInlinable() { + return true; + } + private static final class DefaultOptimizedCallNode extends OptimizedCallNode { private boolean trySplit = true; @@ -135,7 +140,7 @@ if (isMaxSingleCall()) { return true; } - return countPolymorphic() >= 1 || countGeneric() > 0; + return countPolymorphic() >= 1; } @Override @@ -143,11 +148,6 @@ trySplit = true; } - @Override - protected void notifyCallNodeAdded() { - trySplit = true; - } - private boolean isMaxSingleCall() { final AtomicInteger count = new AtomicInteger(0); getCurrentCallTarget().getRootNode().accept(new NodeVisitor() { @@ -163,11 +163,12 @@ } private int countPolymorphic() { - return NodeUtil.countNodes(getCallTarget().getRootNode(), null, Kind.POLYMORPHIC, false); - } - - private int countGeneric() { - return NodeUtil.countNodes(getCallTarget().getRootNode(), null, Kind.GENERIC, false); + return NodeUtil.countNodes(getCallTarget().getRootNode(), new NodeFilter() { + public boolean isFiltered(Node node) { + NodeCost cost = node.getCost(); + return cost == NodeCost.POLYMORPHIC || cost == NodeCost.MEGAMORPHIC; + } + }); } @Override diff -r 82e4fe6fa525 -r b1dded9c748a 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 Mon Mar 17 13:08:32 2014 +0100 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallTarget.java Mon Mar 17 14:30:59 2014 +0100 @@ -34,7 +34,7 @@ import com.oracle.truffle.api.frame.*; import com.oracle.truffle.api.impl.*; import com.oracle.truffle.api.nodes.*; -import com.oracle.truffle.api.nodes.NodeInfo.Kind; +import com.oracle.truffle.api.nodes.NodeUtil.NodeFilter; /** * Call target that is optimized by Graal upon surpassing a specific invocation threshold. @@ -428,11 +428,11 @@ target.getRootNode().accept(new NodeVisitor() { public boolean visit(Node node) { - Kind kind = node.getKind(); - if (kind == Kind.POLYMORPHIC || kind == Kind.GENERIC) { + NodeCost kind = node.getCost(); + if (kind == NodeCost.POLYMORPHIC || kind == NodeCost.MEGAMORPHIC) { Map props = new LinkedHashMap<>(); props.put("simpleName", node.getClass().getSimpleName()); - String msg = kind == Kind.GENERIC ? "generic" : "polymorphic"; + String msg = kind == NodeCost.MEGAMORPHIC ? "megamorphic" : "polymorphic"; log(0, msg, node.toString(), props); } if (node instanceof CallNode) { @@ -461,8 +461,20 @@ } static void addASTSizeProperty(RootNode target, Map properties) { + int polymorphicCount = NodeUtil.countNodes(target.getRootNode(), new NodeFilter() { + public boolean isFiltered(Node node) { + return node.getCost() == NodeCost.POLYMORPHIC; + } + }, true); + + int megamorphicCount = NodeUtil.countNodes(target.getRootNode(), new NodeFilter() { + public boolean isFiltered(Node node) { + return node.getCost() == NodeCost.MEGAMORPHIC; + } + }, true); + String value = String.format("%4d (%d/%d)", NodeUtil.countNodes(target.getRootNode(), null, true), // - NodeUtil.countNodes(target.getRootNode(), null, Kind.POLYMORPHIC, true), NodeUtil.countNodes(target.getRootNode(), null, Kind.GENERIC, true)); // + polymorphicCount, megamorphicCount); // properties.put("ASTSize", value); } diff -r 82e4fe6fa525 -r b1dded9c748a graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/PolymorphicTest.java --- a/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/PolymorphicTest.java Mon Mar 17 13:08:32 2014 +0100 +++ b/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/PolymorphicTest.java Mon Mar 17 14:30:59 2014 +0100 @@ -33,7 +33,6 @@ import com.oracle.truffle.api.dsl.test.TypeSystemTest.TestRootNode; import com.oracle.truffle.api.dsl.test.TypeSystemTest.ValueNode; import com.oracle.truffle.api.nodes.*; -import com.oracle.truffle.api.nodes.NodeInfo.Kind; public class PolymorphicTest { @@ -55,7 +54,7 @@ assertEquals("(boolean,boolean)", executeWith(node, false, false)); assertEquals("(int,boolean)", executeWith(node, 42, false)); assertEquals("(boolean,int)", executeWith(node, false, 42)); - assertEquals(Kind.SPECIALIZED, node.getNode().getClass().getAnnotation(NodeInfo.class).kind()); + assertEquals(NodeCost.MONOMORPHIC, node.getNode().getCost()); assertParent(node.getNode(), node.getNode().getLeft()); assertParent(node.getNode(), node.getNode().getRight()); } @@ -65,7 +64,7 @@ TestRootNode node = TestHelper.createRoot(Node1Factory.getInstance()); assertEquals("(int,boolean)", executeWith(node, 42, false)); assertEquals("(int,int)", executeWith(node, 42, 42)); - assertEquals(Kind.POLYMORPHIC, node.getNode().getClass().getAnnotation(NodeInfo.class).kind()); + assertEquals(NodeCost.NONE, node.getNode().getCost()); assertParent(node.getNode(), node.getNode().getLeft()); assertParent(node.getNode(), node.getNode().getRight()); } @@ -76,7 +75,7 @@ assertEquals("(int,boolean)", executeWith(node, 42, false)); assertEquals("(boolean,boolean)", executeWith(node, true, false)); assertEquals("(int,int)", executeWith(node, 42, 42)); - assertEquals(Kind.POLYMORPHIC, node.getNode().getClass().getAnnotation(NodeInfo.class).kind()); + assertEquals(NodeCost.NONE, node.getNode().getCost()); assertParent(node.getNode(), node.getNode().getLeft()); assertParent(node.getNode(), node.getNode().getRight()); } @@ -88,7 +87,7 @@ assertEquals("(int,boolean)", executeWith(node, 42, false)); assertEquals("(boolean,boolean)", executeWith(node, true, false)); assertEquals("(int,int)", executeWith(node, 42, 42)); - assertEquals(Kind.GENERIC, node.getNode().getClass().getAnnotation(NodeInfo.class).kind()); + assertEquals(NodeCost.MEGAMORPHIC, node.getNode().getCost()); assertParent(node.getNode(), node.getNode().getLeft()); assertParent(node.getNode(), node.getNode().getRight()); } @@ -97,7 +96,7 @@ public void testGenericInitial() { TestRootNode node = TestHelper.createRoot(Node1Factory.getInstance()); assertEquals("(generic,generic)", executeWith(node, "1", "1")); - assertEquals(Kind.GENERIC, node.getNode().getClass().getAnnotation(NodeInfo.class).kind()); + assertEquals(NodeCost.MEGAMORPHIC, node.getNode().getCost()); assertParent(node.getNode(), node.getNode().getLeft()); assertParent(node.getNode(), node.getNode().getRight()); } @@ -108,7 +107,7 @@ assertEquals("(boolean,int)", executeWith(node, false, 42)); assertEquals("(boolean,boolean)", executeWith(node, false, false)); assertEquals("(generic,generic)", executeWith(node, "", "")); - assertEquals(Kind.GENERIC, node.getNode().getClass().getAnnotation(NodeInfo.class).kind()); + assertEquals(NodeCost.MEGAMORPHIC, node.getNode().getCost()); /* Assertions for bug GRAAL-425 */ assertParent(node.getNode(), node.getNode().getLeft()); assertParent(node.getNode(), node.getNode().getRight()); diff -r 82e4fe6fa525 -r b1dded9c748a graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/PolymorphicTest2.java --- a/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/PolymorphicTest2.java Mon Mar 17 13:08:32 2014 +0100 +++ b/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/PolymorphicTest2.java Mon Mar 17 14:30:59 2014 +0100 @@ -32,7 +32,6 @@ import com.oracle.truffle.api.dsl.test.PolymorphicTest2Factory.Node1Factory; import com.oracle.truffle.api.dsl.test.TypeSystemTest.TestRootNode; import com.oracle.truffle.api.nodes.*; -import com.oracle.truffle.api.nodes.NodeInfo.Kind; public class PolymorphicTest2 { @@ -43,7 +42,7 @@ assertEquals(21, executeWith(node, false, false)); assertEquals(42, executeWith(node, 21, 21)); assertEquals("(boolean,int)", executeWith(node, false, 42)); - assertEquals(Kind.POLYMORPHIC, node.getNode().getClass().getAnnotation(NodeInfo.class).kind()); + assertEquals(NodeCost.NONE, node.getNode().getCost()); } @SuppressWarnings("unused") diff -r 82e4fe6fa525 -r b1dded9c748a graal/com.oracle.truffle.api/src/com/oracle/truffle/api/TruffleOptions.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/TruffleOptions.java Mon Mar 17 13:08:32 2014 +0100 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/TruffleOptions.java Mon Mar 17 14:30:59 2014 +0100 @@ -25,7 +25,6 @@ package com.oracle.truffle.api; import com.oracle.truffle.api.nodes.*; -import com.oracle.truffle.api.nodes.NodeInfo.Kind; /** * Class containing general Truffle options. @@ -56,29 +55,29 @@ public static String TraceRewritesFilterClass = System.getProperty("truffle.TraceRewritesFilterClass"); /** - * Filters rewrites which does not contain the {@link Kind} in its source {@link NodeInfo}. If - * no {@link NodeInfo} is defined the element is filtered if the filter value is set. + * Filters rewrites which does not contain the {@link NodeCost} in its source {@link NodeInfo}. + * If no {@link NodeInfo} is defined the element is filtered if the filter value is set. *

* Can be set with - * {@code -Dtruffle.TraceRewritesFilterFromKind=UNINITIALIZED|SPECIALIZED|POLYMORPHIC|GENERIC}. + * {@code -Dtruffle.TraceRewritesFilterFromCost=NONE|MONOMORPHIC|POLYMORPHIC|MEGAMORPHIC}. */ - public static NodeInfo.Kind TraceRewritesFilterFromKind = parseNodeInfoKind(System.getProperty("truffle.TraceRewritesFilterFromKind")); + public static NodeCost TraceRewritesFilterFromCost = parseNodeInfoKind(System.getProperty("truffle.TraceRewritesFilterFromCost")); /** - * Filters rewrites which does not contain the {@link Kind} in its target {@link NodeInfo}. If - * no {@link NodeInfo} is defined the element is filtered if the filter value is set. + * Filters rewrites which does not contain the {@link NodeCost} in its target {@link NodeInfo}. + * If no {@link NodeInfo} is defined the element is filtered if the filter value is set. *

* Can be set with * {@code -Dtruffle.TraceRewritesFilterToKind=UNINITIALIZED|SPECIALIZED|POLYMORPHIC|GENERIC}. */ - public static NodeInfo.Kind TraceRewritesFilterToKind = parseNodeInfoKind(System.getProperty("truffle.TraceRewritesFilterToKind")); + public static NodeCost TraceRewritesFilterToCost = parseNodeInfoKind(System.getProperty("truffle.TraceRewritesFilterToCost")); - private static NodeInfo.Kind parseNodeInfoKind(String kind) { + private static NodeCost parseNodeInfoKind(String kind) { if (kind == null) { return null; } - return NodeInfo.Kind.valueOf(kind); + return NodeCost.valueOf(kind); } } diff -r 82e4fe6fa525 -r b1dded9c748a 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 Mar 17 13:08:32 2014 +0100 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultCallNode.java Mon Mar 17 14:30:59 2014 +0100 @@ -64,6 +64,11 @@ } @Override + public boolean isInlinable() { + return false; + } + + @Override public String toString() { return getParent() != null ? getParent().toString() : super.toString(); } diff -r 82e4fe6fa525 -r b1dded9c748a 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 Mar 17 13:08:32 2014 +0100 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/CallNode.java Mon Mar 17 14:30:59 2014 +0100 @@ -28,13 +28,18 @@ import com.oracle.truffle.api.frame.*; /** - * This node represents a call to a static {@link CallTarget}. This node should be used whenever a - * {@link CallTarget} is considered constant at a certain location in the tree. This enables the - * Truffle runtime to perform inlining or other optimizations for this call-site. This class is - * intended to be implemented by truffle runtime implementors and not by guest language - * implementors. + * Represents a call to a {@link CallTarget} in the Truffle AST. Addtionally to calling the + * {@link CallTarget} this {@link Node} enables the runtime system to implement further + * optimizations. Optimizations that can possibly 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. * - * @see #create(CallTarget) to create a CallNode instance. + * Please note: This class is not intended to be subclassed by guest language implementations. + * + * @see TruffleRuntime#createCallNode(CallTarget) + * @see #inline() + * @see #split() */ public abstract class CallNode extends Node { @@ -45,7 +50,7 @@ } /** - * Calls this constant target passing a caller frame and arguments. + * Calls the inner {@link CallTarget} returned by {@link #getCurrentCallTarget()}. * * @param caller the caller frame * @param arguments the arguments that should be passed to the callee @@ -65,27 +70,63 @@ } /** - * @return true if this {@link CallNode} was already inlined. + * 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} in this {@link CallNode} is inlined. A + * {@link CallNode} can either be inlined manually by invoking {@link #inline()} 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 isInlined(); + /** + * 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. + */ public abstract void inline(); + /** + * 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 splitted {@link CallTarget} if this method is split. + * + * @return the split {@link CallTarget} + */ public abstract CallTarget getSplitCallTarget(); /** * Returns the used call target when {@link #call(PackedFrame, Arguments)} is invoked. If the - * {@link CallNode} was split this method returns the {@link CallTarget} returned by - * {@link #getSplitCallTarget()}. If not split this method returns the original supplied - * {@link CallTarget}. + * {@link CallTarget} was split this method returns the {@link CallTarget} returned by + * {@link #getSplitCallTarget()}. * * @return the used {@link CallTarget} when node is called */ @@ -98,6 +139,22 @@ } } + /** + * 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; + } + @Override protected void onReplace(Node newNode, String reason) { super.onReplace(newNode, reason); @@ -114,6 +171,9 @@ registerCallTarget((CallNode) newNode); } + /** + * Internal API for the runtime system. + */ protected static final void registerCallTarget(CallNode newNode) { RootNode newRoot = newNode.getCurrentRootNode(); if (newRoot != null) { @@ -121,51 +181,4 @@ } } - protected void notifyCallNodeAdded() { - - } - - /** - * Returns the {@link RootNode} associated with {@link CallTarget} returned by - * {@link #getCurrentCallTarget()}. - * - * @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; - } - - /** - * @deprecated always returns true now. - */ - @Deprecated - public boolean isInlinable() { - return true; - } - - /** - * @deprecated instead use {@link #getCurrentRootNode()} and check for {@link #isInlined()} for - * true. - */ - @Deprecated - public RootNode getInlinedRoot() { - if (!isInlined()) { - return null; - } - return getCurrentRootNode(); - } - - /** - * @deprecated use {@link TruffleRuntime#createCallNode(CallTarget)} instead - */ - @Deprecated - public static CallNode create(CallTarget target) { - return Truffle.getRuntime().createCallNode(target); - } - } diff -r 82e4fe6fa525 -r b1dded9c748a graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/GraphPrintVisitor.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/GraphPrintVisitor.java Mon Mar 17 13:08:32 2014 +0100 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/GraphPrintVisitor.java Mon Mar 17 14:30:59 2014 +0100 @@ -214,7 +214,7 @@ setNodeProperty(node, "name", node.getClass().getSimpleName().replaceFirst("Node$", "")); NodeInfo nodeInfo = node.getClass().getAnnotation(NodeInfo.class); if (nodeInfo != null) { - setNodeProperty(node, "kind", nodeInfo.kind()); + setNodeProperty(node, "cost", nodeInfo.cost()); if (!nodeInfo.shortName().isEmpty()) { setNodeProperty(node, "shortName", nodeInfo.shortName()); } diff -r 82e4fe6fa525 -r b1dded9c748a graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/Node.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/Node.java Mon Mar 17 13:08:32 2014 +0100 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/Node.java Mon Mar 17 14:30:59 2014 +0100 @@ -29,7 +29,6 @@ import java.util.*; import com.oracle.truffle.api.*; -import com.oracle.truffle.api.nodes.NodeInfo.Kind; /** * Abstract base class for all Truffle nodes. @@ -82,12 +81,20 @@ this.sourceSection = section; } - public Kind getKind() { + /** + * Returns a rough estimate for the cost of this {@link Node}. This estimate can be used by + * runtime systems or guest languages to implement heuristics based on Truffle ASTs. This method + * is intended to be overridden by subclasses. The default implementation returns the value of + * {@link NodeInfo#cost()} of the {@link NodeInfo} annotation declared at the subclass. If no + * {@link NodeInfo} annotation is declared the method returns {@link NodeCost#MONOMORPHIC} as a + * default value. + */ + public NodeCost getCost() { NodeInfo info = getClass().getAnnotation(NodeInfo.class); if (info != null) { - return info.kind(); + return info.cost(); } - return Kind.SPECIALIZED; + return NodeCost.MONOMORPHIC; } /** @@ -277,61 +284,54 @@ } private void traceRewrite(Node newNode, String reason) { - Class from = getClass(); - Class to = newNode.getClass(); - if (TruffleOptions.TraceRewritesFilterFromKind != null) { - if (filterByKind(from, TruffleOptions.TraceRewritesFilterFromKind)) { + if (TruffleOptions.TraceRewritesFilterFromCost != null) { + if (filterByKind(this, TruffleOptions.TraceRewritesFilterFromCost)) { return; } } - if (TruffleOptions.TraceRewritesFilterToKind != null) { - if (filterByKind(to, TruffleOptions.TraceRewritesFilterToKind)) { + if (TruffleOptions.TraceRewritesFilterToCost != null) { + if (filterByKind(newNode, TruffleOptions.TraceRewritesFilterToCost)) { return; } } String filter = TruffleOptions.TraceRewritesFilterClass; + Class from = getClass(); + Class to = newNode.getClass(); if (filter != null && (filterByContainsClassName(from, filter) || filterByContainsClassName(to, filter))) { return; } PrintStream out = System.out; - out.printf("[truffle] rewrite %-50s |From %-40s |To %-40s |Reason %s.%n", this.toString(), formatNodeInfo(from), formatNodeInfo(to), reason); + out.printf("[truffle] rewrite %-50s |From %-40s |To %-40s |Reason %s.%n", this.toString(), formatNodeInfo(this), formatNodeInfo(newNode), reason); } - private static String formatNodeInfo(Class clazz) { - NodeInfo nodeInfo = clazz.getAnnotation(NodeInfo.class); - String kind = "?"; - if (nodeInfo != null) { - switch (nodeInfo.kind()) { - case GENERIC: - kind = "G"; - break; - case SPECIALIZED: - kind = "S"; - break; - case UNINITIALIZED: - kind = "U"; - break; - case POLYMORPHIC: - kind = "P"; - break; - default: - kind = "?"; - break; - } + private static String formatNodeInfo(Node node) { + String cost = "?"; + switch (node.getCost()) { + case NONE: + cost = "G"; + break; + case MONOMORPHIC: + cost = "M"; + break; + case POLYMORPHIC: + cost = "P"; + break; + case MEGAMORPHIC: + cost = "G"; + break; + default: + cost = "?"; + break; } - return kind + " " + clazz.getSimpleName(); + return cost + " " + node.getClass().getSimpleName(); } - private static boolean filterByKind(Class clazz, Kind kind) { - NodeInfo info = clazz.getAnnotation(NodeInfo.class); - if (info != null) { - return info.kind() != kind; - } - return true; + private static boolean filterByKind(Node node, NodeCost cost) { + return node.getCost() == cost; } private static boolean filterByContainsClassName(Class from, String filter) { diff -r 82e4fe6fa525 -r b1dded9c748a graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/NodeCost.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/NodeCost.java Mon Mar 17 14:30:59 2014 +0100 @@ -0,0 +1,69 @@ +/* + * 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.*; + +/** + * Represents a rough estimate for the cost of a {@link Node}. This estimate can be used by runtime + * systems or guest languages to implement heuristics based on Truffle ASTs. + * + * @see Node#getCost() + */ +public enum NodeCost { + + /** + * This node has literally no costs and should be ignored for heuristics. This is particularly + * useful for wrapper and profiling nodes which should not influence the heuristics. + */ + NONE, + + /** + * This node has a {@link CompilerDirectives#transferToInterpreter()} or + * {@link CompilerDirectives#transferToInterpreterAndInvalidate()} as its first unconditional + * statement. + */ + UNINITIALIZED, + + /** + * This node represents a specialized monomorphic version of an operation. + */ + MONOMORPHIC, + + /** + * This node represents a polymorphic version of an operation. For multiple chained polymorphic + * nodes the first may return {@link #MONOMORPHIC} and all addtional nodes should return + * {@link #POLYMORPHIC}. + */ + POLYMORPHIC, + + /** + * This node represents a megamorphic version of an operation. This value should only be used if + * the operation implementation supports monomorphism and polymorphism otherwise + * {@link #MONOMORPHIC} should be used instead. + */ + MEGAMORPHIC; + +} diff -r 82e4fe6fa525 -r b1dded9c748a graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/NodeInfo.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/NodeInfo.java Mon Mar 17 13:08:32 2014 +0100 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/NodeInfo.java Mon Mar 17 14:30:59 2014 +0100 @@ -40,10 +40,13 @@ */ String shortName() default ""; - Kind kind() default Kind.SPECIALIZED; - - public enum Kind { - UNINITIALIZED, SPECIALIZED, POLYMORPHIC, GENERIC - } + /** + * Provides a rough estimate for the cost of the annotated {@link Node}. This estimate can be + * used by runtime systems or guest languages to implement heuristics based on Truffle ASTs. + * + * @see Node#getCost() + * @see NodeCost + */ + NodeCost cost() default NodeCost.MONOMORPHIC; } diff -r 82e4fe6fa525 -r b1dded9c748a 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 Mar 17 13:08:32 2014 +0100 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/NodeUtil.java Mon Mar 17 14:30:59 2014 +0100 @@ -34,7 +34,6 @@ import com.oracle.truffle.api.*; import com.oracle.truffle.api.nodes.Node.Child; import com.oracle.truffle.api.nodes.Node.Children; -import com.oracle.truffle.api.nodes.NodeInfo.Kind; /** * Utility class that manages the special access methods for node instances. @@ -452,48 +451,6 @@ return null; } - /** - * @deprecated will be removed, exposed Truffle runtime specific functionality. - */ - @Deprecated - public static List findOutermostCallTargets(Node node) { - RootNode root = node.getRootNode(); - if (root == null) { - return Collections.emptyList(); - } - List roots = new ArrayList<>(); - roots.add(root.getCallTarget()); - for (CallNode callNode : root.getCachedCallNodes()) { - if (callNode.isInlined()) { - roots.addAll(findOutermostCallTargets(callNode)); - } - } - return roots; - } - - /** - * @deprecated will be removed, exposed Truffle runtime specific functionality. - */ - @Deprecated - public static RootNode findOutermostRootNode(Node node) { - Node parent = node; - while (parent != null) { - if (parent instanceof RootNode) { - RootNode root = (RootNode) parent; - @SuppressWarnings("deprecation") - Node next = root.getParentInlinedCall(); - if (next != null) { - parent = next; - } else { - return root; - } - } else { - parent = parent.getParent(); - } - } - return null; - } - public static T findParent(Node start, Class clazz) { Node parent = start.getParent(); if (parent == null) { @@ -614,39 +571,43 @@ } public static int countNodes(Node root) { - return countNodes(root, null, null, false); + return countNodes(root, null, false); } - public static int countNodes(Node root, Class clazz, Kind nodeKind, boolean countInlinedCallNodes) { - NodeCountVisitor nodeCount = new NodeCountVisitor(clazz, nodeKind, countInlinedCallNodes); + public static int countNodes(Node root, NodeFilter filter) { + return countNodes(root, filter, false); + } + + public static int countNodes(Node root, NodeFilter filter, boolean visitInlinedCallNodes) { + NodeCountVisitor nodeCount = new NodeCountVisitor(filter, visitInlinedCallNodes); root.accept(nodeCount); return nodeCount.nodeCount; } - public static int countNodes(Node root, Class clazz, boolean countInlinedCallNodes) { - return countNodes(root, clazz, null, countInlinedCallNodes); + public interface NodeFilter { + + boolean isFiltered(Node node); + } private static final class NodeCountVisitor implements NodeVisitor { - private final boolean inspectInlinedCalls; + private final boolean visitInlinedCallNodes; int nodeCount; - private final Kind kind; - private final Class clazz; + private final NodeFilter filter; - private NodeCountVisitor(Class clazz, Kind kind, boolean inspectInlinedCalls) { - this.clazz = clazz; - this.kind = kind; - this.inspectInlinedCalls = inspectInlinedCalls; + private NodeCountVisitor(NodeFilter filter, boolean visitInlinedCallNodes) { + this.filter = filter; + this.visitInlinedCallNodes = visitInlinedCallNodes; } @Override public boolean visit(Node node) { - if ((clazz == null || clazz.isInstance(node)) && (kind == null || isKind(node))) { + if (filter == null || !filter.isFiltered(node)) { nodeCount++; } - if (inspectInlinedCalls && node instanceof CallNode) { + if (visitInlinedCallNodes && node instanceof CallNode) { CallNode call = (CallNode) node; if (call.isInlined()) { Node target = ((RootCallTarget) call.getCurrentCallTarget()).getRootNode(); @@ -659,9 +620,6 @@ return true; } - private boolean isKind(Node n) { - return kind == n.getKind(); - } } public static void printInliningTree(final PrintStream stream, RootNode root) { diff -r 82e4fe6fa525 -r b1dded9c748a 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 Mar 17 13:08:32 2014 +0100 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/RootNode.java Mon Mar 17 14:30:59 2014 +0100 @@ -36,7 +36,7 @@ */ public abstract class RootNode extends Node { - private CallTarget callTarget; + private RootCallTarget callTarget; private final FrameDescriptor frameDescriptor; /* @@ -62,36 +62,24 @@ } /** - * @deprecated Not required anymore. Do not use. + * Creates a split {@link RootNode} based on the current {@link RootNode}. This method should + * return an AST that was never executed and must not be shared with other {@link RootNode} or + * {@link CallTarget} instances. This method is intended to be overridden by a subclass. + * + * @return the split {@link RootNode} */ - @Deprecated - public RootNode inline() { - if (!isInlinable()) { - throw new UnsupportedOperationException("Inlining is not enabled."); - } - return split(); + public RootNode split() { + throw new UnsupportedOperationException(); } /** - * @deprecated Not required anymore. Do not use. - */ - @Deprecated - public int getInlineNodeCount() { - return 0; - } - - /** - * @deprecated Not required anymore. Do not use. + * 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 + * returns true a proper implementation of {@link #split()} must also be provided. + * This method is intended to be overridden by a subclass. + * + * @return true if splittable else false. */ - @Deprecated - public boolean isInlinable() { - return true; - } - - public RootNode split() { - return NodeUtil.cloneNode(this); - } - public boolean isSplittable() { return false; } @@ -100,7 +88,7 @@ * Reports the execution count of a loop that is a child of this node. The optimization * heuristics can use the loop count to guide compilation and inlining. */ - public void reportLoopCount(int count) { + public final void reportLoopCount(int count) { if (getCallTarget() instanceof LoopCountReceiver) { ((LoopCountReceiver) getCallTarget()).reportLoopCount(count); } @@ -114,7 +102,7 @@ */ public abstract Object execute(VirtualFrame frame); - public CallTarget getCallTarget() { + public final RootCallTarget getCallTarget() { return callTarget; } @@ -122,17 +110,17 @@ return frameDescriptor; } - public final void setCallTarget(CallTarget callTarget) { + public final void setCallTarget(RootCallTarget callTarget) { this.callTarget = callTarget; } /* Internal API. Do not use. */ - void addCachedCallNode(CallNode callSite) { + final void addCachedCallNode(CallNode callSite) { this.cachedCallNodes.add(callSite); } /* Internal API. Do not use. */ - void removeCachedCallNode(CallNode callSite) { + final void removeCachedCallNode(CallNode callSite) { this.cachedCallNodes.remove(callSite); } @@ -148,11 +136,4 @@ return Collections.unmodifiableSet(cachedCallNodes); } - /** - * @deprecated use {@link #getCachedCallNodes()} instead. - */ - @Deprecated - public final CallNode getParentInlinedCall() { - return cachedCallNodes.isEmpty() ? null : cachedCallNodes.iterator().next(); - } } diff -r 82e4fe6fa525 -r b1dded9c748a graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/TruffleTypes.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/TruffleTypes.java Mon Mar 17 13:08:32 2014 +0100 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/TruffleTypes.java Mon Mar 17 14:30:59 2014 +0100 @@ -52,7 +52,7 @@ private final DeclaredType childAnnotation; private final DeclaredType childrenAnnotation; private final DeclaredType nodeInfoAnnotation; - private final DeclaredType nodeInfoKind; + private final DeclaredType nodeCost; private final TypeMirror compilerDirectives; private final TypeMirror compilerAsserts; private final DeclaredType slowPath; @@ -75,7 +75,7 @@ assumption = getRequired(context, Assumption.class); invalidAssumption = getRequired(context, InvalidAssumptionException.class); nodeInfoAnnotation = getRequired(context, NodeInfo.class); - nodeInfoKind = getRequired(context, NodeInfo.Kind.class); + nodeCost = getRequired(context, NodeCost.class); slowPath = getRequired(context, SlowPath.class); sourceSection = getRequired(context, SourceSection.class); truffleOptions = getRequired(context, TruffleOptions.class); @@ -107,8 +107,8 @@ return false; } - public DeclaredType getNodeInfoKind() { - return nodeInfoKind; + public DeclaredType getNodeCost() { + return nodeCost; } private DeclaredType getRequired(ProcessorContext context, Class clazz) { diff -r 82e4fe6fa525 -r b1dded9c748a graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/NodeCodeGenerator.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/NodeCodeGenerator.java Mon Mar 17 13:08:32 2014 +0100 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/NodeCodeGenerator.java Mon Mar 17 14:30:59 2014 +0100 @@ -32,7 +32,6 @@ import javax.lang.model.util.*; import com.oracle.truffle.api.dsl.*; -import com.oracle.truffle.api.nodes.NodeInfo.Kind; import com.oracle.truffle.api.nodes.*; import com.oracle.truffle.dsl.processor.*; import com.oracle.truffle.dsl.processor.ast.*; @@ -953,28 +952,28 @@ clazz.add(createGenericExecute(node, rootGroup)); } - clazz.add(createGetKind(node, null, Kind.SPECIALIZED)); + clazz.add(createGetCost(node, null, NodeCost.MONOMORPHIC)); } protected boolean needsInvokeCopyConstructorMethod() { return getModel().getNode().isPolymorphic(); } - protected CodeExecutableElement createGetKind(NodeData node, SpecializationData specialization, Kind kind) { - CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC), context.getTruffleTypes().getNodeInfoKind(), "getKind"); - - TypeMirror nodeInfoKind = context.getTruffleTypes().getNodeInfoKind(); + protected CodeExecutableElement createGetCost(NodeData node, SpecializationData specialization, NodeCost cost) { + CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC), context.getTruffleTypes().getNodeCost(), "getCost"); + + TypeMirror nodeInfoKind = context.getTruffleTypes().getNodeCost(); CodeTreeBuilder builder = method.createBuilder(); if (node.isPolymorphic() && specialization == null) { // assume next0 exists - builder.startIf().string("next0 != null && next0.getKind() == ").staticReference(nodeInfoKind, "SPECIALIZED").end(); + builder.startIf().string("next0 != null && next0.getCost() == ").staticReference(nodeInfoKind, "MONOMORPHIC").end(); builder.startBlock(); builder.startReturn().staticReference(nodeInfoKind, "POLYMORPHIC").end(); builder.end(); } - builder.startReturn().staticReference(nodeInfoKind, kind.name()).end(); + builder.startReturn().staticReference(nodeInfoKind, cost.name()).end(); return method; } @@ -2475,7 +2474,7 @@ } CodeTypeElement clazz = createClass(node, modifiers(PRIVATE, STATIC, FINAL), nodePolymorphicClassName(node), baseType, false); - clazz.getAnnotationMirrors().add(createNodeInfo(node, Kind.POLYMORPHIC)); + clazz.getAnnotationMirrors().add(createNodeInfo(node, NodeCost.NONE)); for (ActualParameter polymorphParameter : polymorph.getSignatureParameters()) { if (!polymorphParameter.getTypeSystemType().isGeneric()) { @@ -2522,7 +2521,7 @@ } createCachedExecuteMethods(specialization); - clazz.add(createGetKind(specialization.getNode(), specialization, Kind.SPECIALIZED)); + clazz.add(createGetCost(specialization.getNode(), specialization, NodeCost.NONE)); } private ExecutableElement createUpdateType(ActualParameter parameter) { @@ -2562,34 +2561,34 @@ } CodeTypeElement clazz = createClass(node, modifiers(PRIVATE, STATIC, FINAL), nodeSpecializationClassName(specialization), baseType, false); - Kind kind; + NodeCost cost; if (specialization.isGeneric()) { - kind = Kind.GENERIC; + cost = NodeCost.MEGAMORPHIC; } else if (specialization.isUninitialized()) { - kind = Kind.UNINITIALIZED; + cost = NodeCost.UNINITIALIZED; } else if (specialization.isPolymorphic()) { - kind = Kind.POLYMORPHIC; + cost = NodeCost.NONE; } else if (specialization.isSpecialized()) { - kind = Kind.SPECIALIZED; + cost = NodeCost.MONOMORPHIC; } else { throw new AssertionError(); } - clazz.getAnnotationMirrors().add(createNodeInfo(node, kind)); + clazz.getAnnotationMirrors().add(createNodeInfo(node, cost)); return clazz; } - protected CodeAnnotationMirror createNodeInfo(NodeData node, Kind kind) { + protected CodeAnnotationMirror createNodeInfo(NodeData node, NodeCost cost) { String shortName = node.getShortName(); CodeAnnotationMirror nodeInfoMirror = new CodeAnnotationMirror(getContext().getTruffleTypes().getNodeInfoAnnotation()); if (shortName != null) { nodeInfoMirror.setElementValue(nodeInfoMirror.findExecutableElement("shortName"), new CodeAnnotationValue(shortName)); } - DeclaredType nodeinfoKind = getContext().getTruffleTypes().getNodeInfoKind(); - VariableElement varKind = Utils.findVariableElement(nodeinfoKind, kind.name()); - - nodeInfoMirror.setElementValue(nodeInfoMirror.findExecutableElement("kind"), new CodeAnnotationValue(varKind)); + DeclaredType nodeinfoCost = getContext().getTruffleTypes().getNodeCost(); + VariableElement varKind = Utils.findVariableElement(nodeinfoCost, cost.name()); + + nodeInfoMirror.setElementValue(nodeInfoMirror.findExecutableElement("cost"), new CodeAnnotationValue(varKind)); return nodeInfoMirror; } @@ -2608,9 +2607,9 @@ } if (specialization.isGeneric()) { - clazz.add(createGetKind(specialization.getNode(), specialization, Kind.GENERIC)); + clazz.add(createGetCost(specialization.getNode(), specialization, NodeCost.MEGAMORPHIC)); } else if (specialization.isUninitialized()) { - clazz.add(createGetKind(specialization.getNode(), specialization, Kind.UNINITIALIZED)); + clazz.add(createGetCost(specialization.getNode(), specialization, NodeCost.UNINITIALIZED)); } }