public abstract class Node extends Object implements NodeInterface, Cloneable
Modifier and Type | Class and Description |
---|---|
static interface |
Node.Child
Marks fields that represent child nodes of this node.
|
static interface |
Node.Children
Marks array fields that are children of this node.
|
Modifier | Constructor and Description |
---|---|
protected |
Node() |
Modifier and Type | Method and Description |
---|---|
void |
accept(NodeVisitor nodeVisitor)
Invokes the
NodeVisitor.visit(Node) method for this node and recursively also for all
child nodes. |
void |
adoptChildren() |
<T> T |
atomic(Callable<T> closure) |
void |
atomic(Runnable closure) |
Node |
copy()
Creates a shallow copy of this node.
|
Node |
deepCopy()
Creates a deep copy of this node.
|
Iterable<Node> |
getChildren()
Iterator over the children of this node.
|
NodeCost |
getCost()
Returns a rough estimate for the cost of this
Node . |
Map<String,Object> |
getDebugProperties()
Returns properties of this node interesting for debugging and can be overwritten by
subclasses to add their own custom properties.
|
String |
getDescription()
Returns a user-readable description of the purpose of the Node, or "" if no description is
available.
|
SourceSection |
getEncapsulatingSourceSection()
Retrieves the segment of guest language source code that is represented by this Node, if
present; otherwise retrieves the segment represented by the nearest AST ancestor that has
this information.
|
protected Lock |
getLock()
Returns a lock object that can be used to synchronize modifications to the AST.
|
Node |
getParent()
The current parent node of this node.
|
RootNode |
getRootNode()
Get the root node of the tree a node belongs to.
|
SourceSection |
getSourceSection()
Retrieves the segment of guest language source code that is represented by this Node.
|
protected <T extends Node> |
insert(T newChild)
|
protected <T extends Node> |
insert(T[] newChildren)
|
boolean |
isAdoptable()
Returns
true if this node can be adopted by a parent. |
boolean |
isSafelyReplaceableBy(Node newNode)
Checks if this node can be replaced by another node: tree structure & type.
|
protected <C,T extends TruffleLanguage<C>> |
lookupContextReference(Class<T> languageClass)
Returns a reference that returns the current execution context associated with the given
language.
|
protected <T extends TruffleLanguage> |
lookupLanguageReference(Class<T> languageClass)
Returns a reference that returns the current language instance.
|
protected void |
notifyInserted(Node node)
Notifies the framework about the insertion of one or more nodes during execution.
|
protected void |
onReplace(Node newNode,
CharSequence reason)
Intended to be implemented by subclasses of
Node to receive a notification when the
node is rewritten. |
<T extends Node> |
replace(T newNode)
Replaces this node with another node.
|
<T extends Node> |
replace(T newNode,
CharSequence reason)
Replaces this node with another node.
|
protected void |
reportPolymorphicSpecialize()
Notifies the runtime that this node specialized to a polymorphic state.
|
String |
toString()
Converts this node to a textual representation useful for debugging.
|
public NodeCost getCost()
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 SourceSection getSourceSection()
null
. If your node represents a
segment of the source code, override this method and return a eagerly or lazily computed
source section value. This method is not designed to be invoked on compiled code paths. May
be called on any thread and without a language context being active.
Simple example implementation using a simple implementation using a field:
abstract class SimpleNode extendsNode
{ privateSourceSection
sourceSection; void setSourceSection(SourceSection
sourceSection) { this.sourceSection = sourceSection; } @Override
publicSourceSection
getSourceSection() { return sourceSection; } }
Recommended implementation computing the source section lazily from primitive fields:
abstract class RecommendedNode extendsNode
{ private static final int NO_SOURCE = -1; private int sourceCharIndex = NO_SOURCE; private int sourceLength; public abstractObject
execute(VirtualFrame
frame); // invoked by the parser to set the source void setSourceSection(int charIndex, int length) { assert sourceCharIndex == NO_SOURCE : "source should only be set once"; this.sourceCharIndex = charIndex; this.sourceLength = length; } @Override
public finalSourceSection
getSourceSection() { if (sourceCharIndex == NO_SOURCE) { // AST node without source return null; }RootNode
rootNode = getRootNode(); if (rootNode == null) { // not yet adopted yet return null; }Source
source = rootNode.getSourceSection().getSource(); return source.createSection(sourceCharIndex, sourceLength); } }
public SourceSection getEncapsulatingSourceSection()
public boolean isAdoptable()
true
if this node can be adopted by a parent. This method is intended to
be overriden by subclasses. If nodes need to be statically shared that they must not be
adoptable, because otherwise the parent reference might cause a memory leak. If a node is not
adoptable then then it is guaranteed that the parent
pointer remains
null
at all times, even if the node is tried to be adopted by a parent.
Implementations of Node.isAdoptable()
are required to fold to a constant result when
compiled with a constant receiver.
protected final <T extends Node> T[] insert(T[] newChildren)
adopted
by a
parent
. The new children need to be assigned to its children
field after insert was called.newChildren
- the array of new children whose parent should be updatedprotected final <T extends Node> T insert(T newChild)
adopted
by a
parent
. The new child needs to be assigned to its child
field after insert was called.newChild
- the new child whose parent should be updatedprotected final void notifyInserted(Node node)
instrumentable
nodes remain unchanged after their root node is first
executed
. Insertions
don't need to be notified if it is known that none of the inserted nodes are
instrumentable
.
The provided Node
and its children must be adopted
in the
AST before invoking this method. The caller must ensure that this method is invoked only once
for a given node and its children.
Example usage:
class MyRootNode extendsRootNode
{ protected MyRootNode(MyLanguage language) { super(language); } @Child InstrumentableLanguageNode child; @Override
publicObject
execute(VirtualFrame
frame) { if (child == null) {CompilerDirectives
.transferToInterpreterAndInvalidate(); child = insert(new InstrumentableLanguageNode()); notifyInserted(child); } return child.execute(frame); } }
node
- the node tree that got inserted.public final void adoptChildren()
public Map<String,Object> getDebugProperties()
public final Node getParent()
public final <T extends Node> T replace(T newNode, CharSequence reason)
Node.getSourceSection()
) associated with this node, it is transferred to the new node.newNode
- the new node that is the replacementreason
- a description of the reason for the replacementpublic final <T extends Node> T replace(T newNode)
Node.getSourceSection()
) associated with this node, it is transferred to the new node.newNode
- the new node that is the replacementpublic final boolean isSafelyReplaceableBy(Node newNode)
protected void onReplace(Node newNode, CharSequence reason)
Node
to receive a notification when the
node is rewritten. This method is invoked before the actual replace has happened.newNode
- the replacement nodereason
- the reason the replace suppliedpublic final void accept(NodeVisitor nodeVisitor)
NodeVisitor.visit(Node)
method for this node and recursively also for all
child nodes.nodeVisitor
- the visitorpublic final Iterable<Node> getChildren()
public Node copy()
public Node deepCopy()
public final RootNode getRootNode()
RootNode
or null
if there is none.protected final void reportPolymorphicSpecialize()
allowed
, create a deep copy of the RootNode
hosting this node and gather context sensitive profiling feedback.public String toString()
public final void atomic(Runnable closure)
public final <T> T atomic(Callable<T> closure)
protected final Lock getLock()
public String getDescription()
protected final <T extends TruffleLanguage> TruffleLanguage.LanguageReference<T> lookupLanguageReference(Class<T> languageClass)
adoptable
then the method must be invoked after the AST was adopted
otherwise an IllegalStateException
is thrown. The reference lookup decides which
lookup method is the best given the parent ExecutableNode
or RootNode
and the
provided languageClass. It is recommended to use
@CachedLanguage
instead whenever possible.
The given language class must not be null
. If the given language class is not
known to the current engine then an IllegalArgumentException
is thrown.
Usage example:
class ExampleNode extends Node { @CompilationFinal private LanguageReferencereference; void execute() { if (reference == null) { CompilerDirectives.transferToInterpreterAndInvalidate(); this.reference = lookupLanguageReference(MyLanguage.class); } MyLanguage language = this.reference.get(); // use language } }
The current language might vary between executions
if resources or code was shared between multiple contexts and the node was
inserted into an AST that was not associated with this language. It is not recommended to
cache the language in the AST directly.
This method is designed for partial evaluation and will reliably return a constant when called with a class literal and the number of accessed languages does not exceed the limit of 5 per root executable node. If possible the reference should be cached in the AST in order to avoid the repeated lookup of the parent executable or root node.
@CachedContext to use the context reference in
specializations or exported messages.
protected final <C,T extends TruffleLanguage<C>> TruffleLanguage.ContextReference<C> lookupContextReference(Class<T> languageClass)
adoptable
then the method must be invoked after
the AST was adopted otherwise an IllegalStateException
is thrown. The reference
lookup decides which lookup method is the best given the parent ExecutableNode
or
RootNode
and the provided languageClass. It is recommended to use
@CachedContext
instead whenever possible.
The given language class must not be null. If the given language class is not known to the
current engine then an IllegalArgumentException
is thrown.
Usage example:
class ExampleNode extends Node { @CompilationFinal private ContextReferencereference; void execute() { if (reference == null) { CompilerDirectives.transferToInterpreterAndInvalidate(); this.reference = lookupContextReference(MyLanguage.class); } MyContext context = this.reference.get(); // use context } }
The current context might vary between executions
if resources or code is shared between multiple contexts. It is not recommended
to cache the context in the AST directly.
This method is designed for partial evaluation and will reliably return a constant when called with a class literal and the number of accessed languages does not exceed the limit of 5 per root executable node. If possible the reference should be cached in the AST in order to avoid the repeated lookup of the parent executable or root node.
@CachedContext to use the context reference in
specializations or exported messages.