Class LoopNode

java.lang.Object
com.oracle.truffle.api.nodes.Node
com.oracle.truffle.api.nodes.LoopNode
All Implemented Interfaces:
NodeInterface, Cloneable

public abstract class LoopNode extends Node

A loop node calls repeating nodes as long as it returns true. Using the loop node in a guest language implementation allows the Truffle runtime to optimize loops in a better way. For example a Truffle runtime implementation might decide to optimize loop already during its first execution (also called on stack replacement OSR). Loop nodes are intended to be implemented by Truffle runtime implementations and not by guest language implementations. Note: The loop condition is automatically profiled by the loop node, so the repeating node should not use a loop condition profile.

Full usage example for guest language while node:

 
 public class WhileNode extends GuestLanguageNode {

     @Node.Child private LoopNode loop;

     public WhileNode(GuestLanguageNode conditionNode, GuestLanguageNode bodyNode) {
         loop = Truffle.getRuntime().createLoopNode(new WhileRepeatingNode(conditionNode, bodyNode));
     }

     @Override
     public Object execute(VirtualFrame frame) {
         loop.executeLoop(frame);
         return null;
     }

     private static class WhileRepeatingNode extends Node implements RepeatingNode {

         @Node.Child private GuestLanguageNode conditionNode;
         @Node.Child private GuestLanguageNode bodyNode;

         public WhileRepeatingNode(GuestLanguageNode conditionNode, GuestLanguageNode bodyNode) {
             this.conditionNode = conditionNode;
             this.bodyNode = bodyNode;
         }

         public boolean executeRepeating(VirtualFrame frame) {
             if ((boolean) conditionNode.execute(frame)) {
                 try {
                     bodyNode.execute(frame);
                 } catch (ContinueException ex) {
                     // the body might throw a continue control-flow exception
                     // continue loop invocation
                 } catch (BreakException ex) {
                     // the body might throw a break control-flow exception
                     // break loop invocation by returning false
                     return false;
                 }
                 return true;
             } else {
                 return false;
             }
         }
     }

 }

 // substitute with a guest language node type
 public abstract class GuestLanguageNode extends Node {

     public abstract Object execute(VirtualFrame frame);

 }
 // thrown by guest language continue statements
 public final class ContinueException extends ControlFlowException {}
 // thrown by guest language break statements
 public final class BreakException extends ControlFlowException {}
 
 
Since:
0.8 or earlier
See Also:
  • Constructor Details

    • LoopNode

      protected LoopNode()
      Constructor for subclasses.
      Since:
      0.8 or earlier
  • Method Details

    • execute

      public Object execute(VirtualFrame frame)
      Invokes one loop invocation by repeatedly calling execute) on the repeating node the loop was initialized with. Any exceptions that occur in the execution of the repeating node will just be forwarded to this method and will cancel the current loop invocation.
      Parameters:
      frame - the current execution frame or null if the repeating node does not require a frame
      Returns:
      a value v returned by execute satisfying shouldContinue(v) == false, which can be used in a language-specific way (for example, to encode structured jumps)
      Since:
      19.3
    • getRepeatingNode

      public abstract RepeatingNode getRepeatingNode()
      Returns the repeating node the loop node was created with.
      Since:
      0.8 or earlier
    • reportLoopCount

      public static void reportLoopCount(Node source, int iterations)

      Reports the execution count of a loop for which no LoopNode was used. The optimization heuristics can use the loop count from non Truffle loops to guide compilation and inlining better. Do not use LoopNode and reportLoopCount(Node, int) at the same time for one loop. If the number of iterations needs to be counted and can overflow, only count if CompilerDirectives.hasNextTier() is true (reporting will have no effect in the last tier) and consider reporting Integer.MAX_VALUE in case of overflows. If the number is often zero and reportLoopCount(Node, int) is called frequently (e.g. in a loop), consider adding a check to avoid the overhead of redundant calls with an iterations argument of zero in the interpreter.

      Example usage for a custom loop iterating over an array:

       public int executeCustomLoopSum(int[] data) {
           int sum = 0;
           for (int i = 0; i < data.length; i++) {
               sum += data[i];
           }
           LoopNode.reportLoopCount(this, data.length);
           return sum;
       }
       
      Example usage for a custom loop with an unknown number of iterations and a potential int overflow:
       public Object executeCustomLoopWithUnknownIterations(int[] data) {
           Object result;
           int counter = 0;
           while(true) {
               if (isResultAvailable()) {
                   result = getResult();
                   break;
               }
               // do some work to calculate result
               if (CompilerDirectives.hasNextTier()) {
                   counter++;
               }
           }
           if (counter != 0) {
               LoopNode.reportLoopCount(this, counter > 0 ? counter : Integer.MAX_VALUE);
           }
           return result;
       }
       

      Parameters:
      source - the Node which invoked the loop.
      iterations - the number iterations to report to the runtime system, must be >= 0
      Since:
      0.12