# HG changeset patch # User Christian Humer # Date 1395062985 -3600 # Node ID 6681b9eb3f4cebbfcb60715f533429317591c356 # Parent 9c01fabfb167e73882a80643f23fd5ef19769646 Truffle: API cleanup and javadoc for CallNodes. diff -r 9c01fabfb167 -r 6681b9eb3f4c 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 14:29:45 2014 +0100 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallNode.java Mon Mar 17 14:29:45 2014 +0100 @@ -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; @@ -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() { diff -r 9c01fabfb167 -r 6681b9eb3f4c 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 14:29:45 2014 +0100 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultCallNode.java Mon Mar 17 14:29:45 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 9c01fabfb167 -r 6681b9eb3f4c 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 14:29:45 2014 +0100 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/CallNode.java Mon Mar 17 14:29:45 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,23 +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; - } - } diff -r 9c01fabfb167 -r 6681b9eb3f4c 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 14:29:45 2014 +0100 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/Node.java Mon Mar 17 14:29:45 2014 +0100 @@ -81,6 +81,14 @@ this.sourceSection = section; } + /** + * 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) { diff -r 9c01fabfb167 -r 6681b9eb3f4c graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/NodeCost.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/NodeCost.java Mon Mar 17 14:29:45 2014 +0100 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/NodeCost.java Mon Mar 17 14:29:45 2014 +0100 @@ -24,8 +24,46 @@ */ 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 { - NONE, UNINITIALIZED, MONOMORPHIC, POLYMORPHIC, MEGAMORPHIC; + /** + * 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 9c01fabfb167 -r 6681b9eb3f4c 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 14:29:45 2014 +0100 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/NodeInfo.java Mon Mar 17 14:29:45 2014 +0100 @@ -40,21 +40,13 @@ */ String shortName() default ""; + /** + * 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; - /** - * @deprecated use {@link NodeInfo#cost()} instead. - */ - @Deprecated - Kind kind() default Kind.SPECIALIZED; - - /** - * - * @deprecated use {@link NodeCost} instead. - */ - @Deprecated - public enum Kind { - UNINITIALIZED, SPECIALIZED, POLYMORPHIC, GENERIC - } - } diff -r 9c01fabfb167 -r 6681b9eb3f4c 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 14:29:45 2014 +0100 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/RootNode.java Mon Mar 17 14:29:45 2014 +0100 @@ -36,7 +36,7 @@ */ public abstract class RootNode extends Node { - private CallTarget callTarget; + private RootCallTarget callTarget; private final FrameDescriptor frameDescriptor; /* @@ -61,10 +61,25 @@ } } + /** + * 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} + */ public RootNode split() { - return NodeUtil.cloneNode(this); + throw new UnsupportedOperationException(); } + /** + * 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. + */ public boolean isSplittable() { return false; } @@ -73,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); } @@ -87,7 +102,7 @@ */ public abstract Object execute(VirtualFrame frame); - public CallTarget getCallTarget() { + public final RootCallTarget getCallTarget() { return callTarget; } @@ -95,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); }