changeset 14566:6681b9eb3f4c

Truffle: API cleanup and javadoc for CallNodes.
author Christian Humer <christian.humer@gmail.com>
date Mon, 17 Mar 2014 14:29:45 +0100
parents 9c01fabfb167
children b1dded9c748a
files graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallNode.java graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultCallNode.java graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/CallNode.java graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/Node.java graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/NodeCost.java graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/NodeInfo.java graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/RootNode.java
diffstat 7 files changed, 157 insertions(+), 58 deletions(-) [+]
line wrap: on
line diff
--- 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() {
--- 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();
     }
--- 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 <code>true</code> 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 <code>true</code> 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 <code>true</code> 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 <code>true</code> for {@link RootNode#isSplittable()}.
+     * 
+     * @return <code>true</code> 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 <code>true</code> 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 <code>null</code>.
+     * 
+     * @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;
-    }
-
 }
--- 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) {
--- 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;
 
 }
--- 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
-    }
-
 }
--- 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 <code>true</code> 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 <code>true</code> a proper implementation of {@link #split()} must also be provided.
+     * This method is intended to be overridden by a subclass.
+     * 
+     * @return <code>true</code> if splittable else <code>false</code>.
+     */
     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);
     }