T
- the type of the block element nodepublic abstract class BlockNode<T extends Node> extends Node
Elements are executed using the BlockNode.ElementExecutor
provided when
creating
the block node. When a block is executed then
all elements are executed using executeVoid
except the last element which will be executed using the typed execute method also
used to execute the block node. This allows to implement boxing elimination of the return value
of blocks in the interpreter. For example, if executeInt
is invoked on the block , then all elements except the last one is executed using
executeVoid
, but the last one
with executeInt
.
The optimizing runtime may decide to group elements of a block into multiple block compilation units. This may happen if the block is too big to be compiled with a single compilation unit. If the compilation final state of an element is changed, or a node is replaced only the compilation unit of the current block is invalidated and not all compilations units of a block. Therefore, no compilation final assumptions must be taken between elements of a block.
// language base node abstract class LanguageNode extendsNode
{ public abstractObject
execute(VirtualFrame
frame); } final class LanguageBlockNode extends LanguageNode implementsBlockNode.ElementExecutor
<LanguageNode> { @Child privateBlockNode
<LanguageNode> block; LanguageBlockNode(LanguageNode[] elements) { this.block =BlockNode
.create(elements, this); } @Override
public void executeVoid(VirtualFrame
frame, LanguageNode node, int index, int arg) { node.execute(frame); } @Override
publicObject
executeGeneric(VirtualFrame
frame, LanguageNode node, int index, int arg) { return node.execute(frame); } @Override
publicObject
execute(VirtualFrame
frame) { return block.executeGeneric(frame, 0); } }
final class YieldException extendsControlFlowException
{ finalObject
result; YieldException(Object
result) { this.result = result; } } final class ResumableBlockNode extends LanguageNode implementsBlockNode.ElementExecutor
<LanguageNode> { @CompilerDirectives.CompilationFinal
privateInteger
indexSlot; @Child privateBlockNode
<LanguageNode> block; ResumableBlockNode(LanguageNode[] elements) { this.block =BlockNode
.create(elements, this); } @Override
publicObject
execute(VirtualFrame
frame) { frame.setAuxiliarySlot(getIndexSlot(), 0); return block.executeGeneric(frame, 0); } // Called if the resumable block needs to be // resumed later on after a yield. public void resume(VirtualFrame
frame) { getIndexSlot(); int startIndex = frame.getInt(getIndexSlot()); block.executeGeneric(frame, startIndex); } @Override
public void executeVoid(VirtualFrame
frame, LanguageNode node, int elementIndex, int startIndex) { executeGeneric(frame, node, elementIndex, startIndex); } @Override
publicObject
executeGeneric(VirtualFrame
frame, LanguageNode node, int elementIndex, int startIndex) { if (elementIndex >= startIndex) { try { return node.execute(frame); } catch (YieldException e) { // store index to be able to resume later frame.setInt(getIndexSlot(), elementIndex); return e.result; } } else {CompilerDirectives
.transferToInterpreterAndInvalidate(); throw newAssertionError
("Invalid start index"); } } private int getIndexSlot() {Integer
slot = this.indexSlot; if (slot == null) {CompilerDirectives
.transferToInterpreterAndInvalidate();FrameDescriptor
fd = getRootNode().getFrameDescriptor(); this.indexSlot = slot = fd.findOrAddAuxiliarySlot(this); } return slot; } }
Modifier and Type | Class and Description |
---|---|
static interface |
BlockNode.ElementExecutor<T extends Node>
Represents a contract how block element nodes can be executed.
|
Node.Child, Node.Children
Modifier and Type | Field and Description |
---|---|
static int |
NO_ARGUMENT
Use when no argument is needed for the block node.
|
Modifier | Constructor and Description |
---|---|
protected |
BlockNode(T[] elements)
Internal constructor for implementations.
|
Modifier and Type | Method and Description |
---|---|
static <T extends Node> |
create(T[] elements,
BlockNode.ElementExecutor<T> executor)
Creates a new block node.
|
abstract boolean |
executeBoolean(VirtualFrame frame,
int argument)
Executes the block and returns a boolean value.
|
abstract byte |
executeByte(VirtualFrame frame,
int argument)
Executes the block and returns a byte value.
|
abstract char |
executeChar(VirtualFrame frame,
int argument)
Executes the block and returns a char value.
|
abstract double |
executeDouble(VirtualFrame frame,
int argument)
Executes the block and returns a double value.
|
abstract float |
executeFloat(VirtualFrame frame,
int argument)
Executes the block and returns a float value.
|
abstract Object |
executeGeneric(VirtualFrame frame,
int argument)
Executes the block and returns a generic value.
|
abstract int |
executeInt(VirtualFrame frame,
int argument)
Executes the block and returns an int value.
|
abstract long |
executeLong(VirtualFrame frame,
int argument)
Executes the block and returns a long value.
|
abstract short |
executeShort(VirtualFrame frame,
int argument)
Executes the block and returns a short value.
|
abstract void |
executeVoid(VirtualFrame frame,
int argument)
Executes the block and returns no value.
|
NodeCost |
getCost()
Block nodes always have
NodeCost.NONE . |
T[] |
getElements()
Returns the elements of the block node.
|
accept, adoptChildren, atomic, atomic, copy, deepCopy, getChildren, getDebugProperties, getDescription, getEncapsulatingSourceSection, getLock, getParent, getRootNode, getSourceSection, insert, insert, isAdoptable, isSafelyReplaceableBy, notifyInserted, onReplace, replace, replace, reportPolymorphicSpecialize, toString
public static final int NO_ARGUMENT
protected BlockNode(T[] elements)
public abstract void executeVoid(VirtualFrame frame, int argument)
BlockNode.ElementExecutor.executeVoid(VirtualFrame, Node, int, int)
for all elements of the
block.frame
- the frame to execute the block in.argument
- a custom argument that is forwarded to the executor as is. If no argument is
needed then BlockNode.NO_ARGUMENT
should be used.public abstract Object executeGeneric(VirtualFrame frame, int argument)
BlockNode.ElementExecutor.executeVoid(VirtualFrame, Node, int, int)
for all elements of the
block except the last element. The last element is executed using
BlockNode.ElementExecutor.executeGeneric(VirtualFrame, Node, int, int)
.frame
- the frame to execute the block in.argument
- a custom value that is forwarded to the executor as is. If no argument is
needed then BlockNode.NO_ARGUMENT
should be used.public abstract byte executeByte(VirtualFrame frame, int argument) throws UnexpectedResultException
BlockNode.ElementExecutor.executeVoid(VirtualFrame, Node, int, int)
for all elements of the
block except the last element. The last element is executed using
BlockNode.ElementExecutor.executeByte(VirtualFrame, Node, int, int)
.frame
- the frame to execute the block in.argument
- a custom value that is forwarded to the executor as is. If no argument is
needed then BlockNode.NO_ARGUMENT
should be used.UnexpectedResultException
public abstract short executeShort(VirtualFrame frame, int argument) throws UnexpectedResultException
BlockNode.ElementExecutor.executeVoid(VirtualFrame, Node, int, int)
for all elements of the
block except the last element. The last element is executed using
BlockNode.ElementExecutor.executeShort(VirtualFrame, Node, int, int)
.frame
- the frame to execute the block in.argument
- a custom value that is forwarded to the executor as is. If no argument is
needed then BlockNode.NO_ARGUMENT
should be used.UnexpectedResultException
public abstract int executeInt(VirtualFrame frame, int argument) throws UnexpectedResultException
BlockNode.ElementExecutor.executeVoid(VirtualFrame, Node, int, int)
for all elements of the
block except the last element. The last element is executed using
BlockNode.ElementExecutor.executeInt(VirtualFrame, Node, int, int)
.frame
- the frame to execute the block in.argument
- a custom value that is forwarded to the executor as is. If no argument is
needed then BlockNode.NO_ARGUMENT
should be used.UnexpectedResultException
public abstract char executeChar(VirtualFrame frame, int argument) throws UnexpectedResultException
BlockNode.ElementExecutor.executeVoid(VirtualFrame, Node, int, int)
for all elements of the
block except the last element. The last element is executed using
BlockNode.ElementExecutor.executeChar(VirtualFrame, Node, int, int)
.frame
- the frame to execute the block in.argument
- a custom value that is forwarded to the executor as is. If no argument is
needed then BlockNode.NO_ARGUMENT
should be used.UnexpectedResultException
public abstract float executeFloat(VirtualFrame frame, int argument) throws UnexpectedResultException
BlockNode.ElementExecutor.executeVoid(VirtualFrame, Node, int, int)
for all elements of the
block except the last element. The last element is executed using
BlockNode.ElementExecutor.executeFloat(VirtualFrame, Node, int, int)
.frame
- the frame to execute the block in.argument
- a custom value that is forwarded to the executor as is. If no argument is
needed then BlockNode.NO_ARGUMENT
should be used.UnexpectedResultException
public abstract double executeDouble(VirtualFrame frame, int argument) throws UnexpectedResultException
BlockNode.ElementExecutor.executeVoid(VirtualFrame, Node, int, int)
for all elements of the
block except the last element. The last element is executed using
BlockNode.ElementExecutor.executeDouble(VirtualFrame, Node, int, int)
.frame
- the frame to execute the block in.argument
- a custom value that is forwarded to the executor as is. If no argument is
needed then BlockNode.NO_ARGUMENT
should be used.UnexpectedResultException
public abstract long executeLong(VirtualFrame frame, int argument) throws UnexpectedResultException
BlockNode.ElementExecutor.executeVoid(VirtualFrame, Node, int, int)
for all elements of the
block except the last element. The last element is executed using
BlockNode.ElementExecutor.executeLong(VirtualFrame, Node, int, int)
.frame
- the frame to execute the block in.argument
- a custom value that is forwarded to the executor as is. If no argument is
needed then BlockNode.NO_ARGUMENT
should be used.UnexpectedResultException
public abstract boolean executeBoolean(VirtualFrame frame, int argument) throws UnexpectedResultException
BlockNode.ElementExecutor.executeVoid(VirtualFrame, Node, int, int)
for all elements of the
block except the last element. The last element is executed using
BlockNode.ElementExecutor.executeBoolean(VirtualFrame, Node, int, int)
.frame
- the frame to execute the block in.argument
- a custom value that is forwarded to the executor as is. If no argument is
needed then BlockNode.NO_ARGUMENT
should be used.UnexpectedResultException
public final T[] getElements()
BlockNode.create(Node[], ElementExecutor)
.public final NodeCost getCost()
NodeCost.NONE
.
Returns a rough estimate for the cost of this 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
NodeInfo.cost()
of the NodeInfo
annotation declared at the subclass. If no
NodeInfo
annotation is declared the method returns NodeCost.MONOMORPHIC
as a
default value.public static <T extends Node> BlockNode<T> create(T[] elements, BlockNode.ElementExecutor<T> executor)
IllegalArgumentException
is thrown. Elements of a block must at least extend
Node
. An executor must be provided that allows the block node implementation to
execute the block elements. The executor must not be null
.