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 adopated 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{ privateSourceSectionsourceSection; void setSourceSection(SourceSectionsourceSection) { this.sourceSection = sourceSection; } @OverridepublicSourceSectiongetSourceSection() { 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 abstractObjectexecute(VirtualFrameframe); // 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; } @Overridepublic finalSourceSectiongetSourceSection() { if (sourceCharIndex == NO_SOURCE) { // AST node without source return null; }RootNoderootNode = getRootNode(); if (rootNode == null) { // not yet adopted yet return null; }Sourcesource = rootNode.getSourceSection().getSource(); return source.createSection(sourceCharIndex, sourceLength); } }
public SourceSection getEncapsulatingSourceSection()
public boolean isAdoptable()
true if this node can be adopated 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; @OverridepublicObjectexecute(VirtualFrameframe) { 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 LanguageReference reference;
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 ContextReference reference;
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.