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
{}
RepeatingNode
,
TruffleRuntime.createLoopNode(RepeatingNode)
Node.Child, Node.Children
Modifier | Constructor and Description |
---|---|
protected |
LoopNode()
Constructor for subclasses.
|
Modifier and Type | Method and Description |
---|---|
Object |
execute(VirtualFrame frame)
Invokes one loop invocation by repeatedly calling
execute) on the repeating node the loop
was initialized with. |
abstract RepeatingNode |
getRepeatingNode()
Returns the repeating node the loop node was created with.
|
static void |
reportLoopCount(Node source,
int iterations)
Reports the execution count of a loop for which no
LoopNode was used. |
accept, adoptChildren, atomic, atomic, copy, deepCopy, getChildren, getCost, getDebugProperties, getDescription, getEncapsulatingSourceSection, getLock, getParent, getRootNode, getSourceSection, insert, insert, isAdoptable, isSafelyReplaceableBy, notifyInserted, onReplace, replace, replace, reportPolymorphicSpecialize, toString
public Object execute(VirtualFrame frame)
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.frame
- the current execution frame or null if the repeating node does not require a
framev
returned by
execute
satisfying
shouldContinue(v)
== false
, which
can be used in a language-specific way (for example, to encode structured jumps)public abstract RepeatingNode getRepeatingNode()
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 LoopNode.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 LoopNode.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:
Example usage for a custom loop with an unknown number of iterations and a potential
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;
}
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;
}
source
- the Node which invoked the loop.iterations
- the number iterations to report to the runtime system, must be >= 0