public abstract class RootNode extends ExecutableNode
node
that allows to be
executed
using a frame
instance created by
the framework. Please note that the RootNode
should not be executed directly but using
CallTarget.call(Object...)
. The structure of the frame is provided by the
frame descriptor
passed in the constructor. A root node has always a
null
parent
and cannot be replaced
.
language implementation
if it is
available. The language implementation instance is obtainable while
TruffleLanguage.createContext(Env)
or TruffleLanguage.parse(ParsingRequest)
is
executed. If no language environment is available, then null
can be passed. Please
note that root nodes with null
language are considered not instrumentable and don't
have access to its public language information
.
RootNode.getCallTarget()
. This allows the runtime system to optimize the execution of the
AST. The CallTarget
can either be called
directly from
runtime code or direct
and indirect
call nodes
can be created, inserted in a child field and called
. The
use of direct call nodes allows the framework to automatically inline and further optimize call
sites based on heuristics.
After several calls to a call target or call node, the root node might get compiled using partial evaluation. The details of the compilation heuristic are unspecified, therefore the Truffle runtime system might decide to not compile at all.
language
call target
created
language contexts
language
is passed in the root node constructor.
RootNode.isInstrumentable()
is overridden and returns true
.
Node.getSourceSection()
is overridden and returns a non-null value.
InstrumentableNode
.
StandardTags
.
Note: It is recommended to override Node.getSourceSection()
and provide a
source section if available. This allows for better testing/tracing/tooling. If no concrete
source section is available please consider using Source.createUnavailableSection()
.
Node.Child, Node.Children
Modifier | Constructor and Description |
---|---|
protected |
RootNode(TruffleLanguage<?> language)
Creates new root node with a given language instance.
|
protected |
RootNode(TruffleLanguage<?> language,
FrameDescriptor frameDescriptor)
Creates new root node given an language environment and frame descriptor.
|
Modifier and Type | Method and Description |
---|---|
protected RootNode |
cloneUninitialized()
Creates an uninitialized copy of an already initialized/executed root node if it is
supported . |
protected int |
computeSize()
Computes a size estimate of this root node.
|
Node |
copy()
Creates a shallow copy of this node.
|
protected boolean |
countsTowardsStackTraceLimit()
Returns
true if this root node should count towards
AbstractTruffleException.getStackTraceElementLimit() . |
static RootNode |
createConstantNode(Object constant)
Helper method to create a root node that always returns the same value.
|
abstract Object |
execute(VirtualFrame frame)
Executes this function using the specified frame and returns the result value.
|
protected List<TruffleStackTraceElement> |
findAsynchronousFrames(Frame frame)
Provide a list of stack frames that led to a schedule of asynchronous execution of this root
node on the provided frame.
|
RootCallTarget |
getCallTarget() |
FrameDescriptor |
getFrameDescriptor() |
String |
getName()
Returns a simple name of the AST (expected to be a method or procedure name in most
languages) that identifies the AST for the benefit of guest language programmers using tools;
it might appear, for example in the context of a stack dump or trace and is not expected to
be called often.
|
protected FrameDescriptor |
getParentFrameDescriptor()
If this root node has a lexical scope parent, this method returns its frame descriptor.
|
String |
getQualifiedName()
Returns a qualified name of the AST that in the best case uniquely identifiers the method.
|
boolean |
isCaptureFramesForTrace()
Returns
true if an AbstractTruffleException leaving this node should capture
Frame objects in its stack trace in addition to the default information. |
protected boolean |
isCloneUninitializedSupported()
Returns
true if RootNode.cloneUninitialized() can be used to create
uninitialized copies of an already initialized / executed root node. |
boolean |
isCloningAllowed()
Returns
true if this RootNode is allowed to be cloned. |
protected boolean |
isInstrumentable()
Does this contain AST content that it is possible to instrument.
|
boolean |
isInternal()
Returns
true if this root node should be considered internal and not be shown to
a guest language programmer. |
protected boolean |
isTrivial()
Is this root node to be considered trivial by the runtime.
|
protected ExecutionSignature |
prepareForAOT()
Allows languages to perform actions before a root node is attempted to be compiled without
prior call to
RootNode.execute(VirtualFrame) . |
protected Object |
translateStackTraceElement(TruffleStackTraceElement element)
Translates the
TruffleStackTraceElement into an interop object supporting the
hasExecutableName and potentially hasDeclaringMetaObject and
hasSourceLocation messages. |
getLanguage, getLanguageInfo
accept, adoptChildren, atomic, atomic, deepCopy, getChildren, getCost, getDebugProperties, getDescription, getEncapsulatingSourceSection, getLock, getParent, getRootNode, getSourceSection, insert, insert, isAdoptable, isSafelyReplaceableBy, notifyInserted, onReplace, replace, replace, reportPolymorphicSpecialize, toString
protected RootNode(TruffleLanguage<?> language)
TruffleLanguage.createContext(Env)
or
TruffleLanguage.parse(ParsingRequest)
is executed. If no language environment is
available, then null
can be passed. Please note that root nodes with
null
language are considered not instrumentable and don't have access to its
public language information
.language
- the language this root node is associated withprotected RootNode(TruffleLanguage<?> language, FrameDescriptor frameDescriptor)
TruffleLanguage.createContext(Env)
or
TruffleLanguage.parse(ParsingRequest)
is executed. If no language environment is
available, then null
can be passed. Please note that root nodes with
null
language are considered not instrumentable and don't have access to its
public language information
.language
- the language this root node is associated withpublic String getQualifiedName()
name
is used by
default. A root node that represents a Java method could consist of the package name, the
class name and the method name. E.g. mypackage.MyClass.myMethod
public String getName()
myMethod
In some languages AST "compilation units" may have no intrinsic names. When no information is
available, language implementations might simply use the first few characters of the code,
followed by "...
". Language implementations should assign a more helpful name
whenever it becomes possible, for example when a functional value is assigned. This means
that the name might not be stable over time.
Language execution semantics should not depend on either this name or the way that it is formatted. The name should be presented in the way expected to be most useful for programmers.
null
if the language implementation is unable to provide any useful
information.public boolean isInternal()
true
if this root node should be considered internal and not be shown to
a guest language programmer. This method has effect on tools and guest language stack traces.
By default a RootNode
is internal if no language was passed in the constructor or if
the root source section
is set and points to an internal source.
This method is intended to be overwritten by guest languages, when the node's source is
internal, the implementation should respect that. Can be called on any thread and without a
language context.
This method may be invoked on compiled code paths. It is recommended to implement this method such that it returns a compilation final constant.
protected boolean countsTowardsStackTraceLimit()
true
if this root node should count towards
AbstractTruffleException.getStackTraceElementLimit()
.
By default, returns the negation of RootNode.isInternal()
.
This method may be invoked on compiled code paths. It is recommended to implement this method or #isInternal() such that it returns a partial evaluation constant.
public boolean isCaptureFramesForTrace()
true
if an AbstractTruffleException leaving this node should capture
Frame
objects in its stack trace in addition to the default information. This is
false
by default to avoid the attached overhead. The captured frames are then
accessible through TruffleStackTraceElement.getFrame()
public boolean isCloningAllowed()
true
if this RootNode
is allowed to be cloned. The runtime
system might decide to create deep copies of the RootNode
in order to gather context
sensitive profiling feedback. The default implementation returns false
. Guest
language specific implementations may want to return true
here to indicate that
gathering call site specific profiling information might make sense for this RootNode
.true
if cloning is allowed else false
.protected boolean isCloneUninitializedSupported()
true
if RootNode.cloneUninitialized()
can be used to create
uninitialized copies of an already initialized / executed root node. By default, or if this
method returns false
, an optimizing Truffle runtime might need to copy the AST
before it is executed for the first time to ensure it is able to create new uninitialized
copies when needed. By returning true
and therefore supporting uninitialized
copies an optimizing runtime does not need to keep a reference to an uninitialized copy on
its own and might therefore be able to save memory. The returned boolean needs to be
immutable for a RootNode
instance.true
if calls to uninitialized copies
are
supported.RootNode.cloneUninitialized()
protected RootNode cloneUninitialized()
supported
. Throws an
UnsupportedOperationException
exception by default. By default, or if
RootNode.isCloneUninitializedSupported()
returns false
, an optimizing Truffle
runtime might need to copy the root node before it is executed for the first time to ensure
it is able to create new uninitialized copies when needed. By supporting uninitialized copies
an optimizing runtime does not need to keep a reference to an uninitialized copy on its own
and might therefore be able to save memory.
Two common strategies to implement RootNode.cloneUninitialized()
are:
Node
tree and derive an
uninitialized copy from each initialized node.
UnsupportedOperationException
- if not supportedRootNode.isCloneUninitializedSupported()
public abstract Object execute(VirtualFrame frame)
execute
in class ExecutableNode
frame
- the frame of the currently executing guest language methodpublic final RootCallTarget getCallTarget()
public final FrameDescriptor getFrameDescriptor()
protected boolean isInstrumentable()
protected boolean isTrivial()
true
if this root node should be considered trivial by the runtime.
false
otherwise.protected List<TruffleStackTraceElement> findAsynchronousFrames(Frame frame)
TruffleLanguage.getAsynchronousStackDepth()
is positive. The language is free to provide
asynchronous frames or longer list of frames when it's of no performance penalty, or if
requested by other options. This method is invoked on slow-paths only and with a context
entered.frame
- A frame, never null
TruffleStackTraceElement
, or null
when no asynchronous
stack is available.TruffleLanguage.getAsynchronousStackDepth()
protected Object translateStackTraceElement(TruffleStackTraceElement element)
TruffleStackTraceElement
into an interop object supporting the
hasExecutableName
and potentially hasDeclaringMetaObject
and
hasSourceLocation
messages. An executable name must be provided, whereas the
declaring meta object and source location is optional. Guest languages may typically return
their function objects that typically already implement the required contracts.
The intention of this method is to provide a guest language object for other languages that
they can inspect using interop. An implementation of this method is expected to not fail with
a guest error. Implementations are allowed to do context
reference lookups
in the implementation of the method. This may be useful to access the
function objects needed to resolve the stack trace element.
to access the guest object of a stack trace
element.
protected ExecutionSignature prepareForAOT()
RootNode.execute(VirtualFrame)
. By default this method returns
null
to indicate that AOT compilation is not supported. Any non-null value
indicates that compilation without execution is supported for this root node. This method is
guaranteed to not be invoked prior to any calls to execute
.
Common tasks that need to be performed by this method:
FrameDescriptor
of the root node. Without
that any access to the frame will invalidate the code on first execute.
AOTSupport
.
If possible an execution signature
should be returned for better
call efficiency. If the argument and return profile is not available or cannot be derived the
ExecutionSignature.GENERIC
can be used to indicate that any value needs to be
expected for as argument from or as return value of the method. To indicate that a type is
unknown a null
return or argument type should be used. The type
Object
type should not be used in that case.
This method is invoked when no context is currently entered
therefore no guest application code must be executed. The execution might happen on
any thread, even threads unknown to the guest language implementation. It is allowed to
create new call targets
during preparation of the root node or perform
modifications to the language
of this root node.
public static RootNode createConstantNode(Object constant)
inter-operability
API) require return of
stable root nodes
. To simplify creation of such nodes, here is a factory
method that can create RootNode
that returns always the same value.constant
- the constant to returnprotected FrameDescriptor getParentFrameDescriptor()
def m { # For the "m" root node: # getFrameDescriptor returns FrameDescriptor(m) # getParentFrameDescriptor returns null var_method = 0 a = () -> { # For the "a lambda" root node: # getFrameDescriptor returns FrameDescriptor(a) # getParentFrameDescriptor returns FrameDescriptor(m) var_lambda1 = 1 b = () -> { # For the "b lambda" root node: # getFrameDescriptor returns FrameDescriptor(b) # getParentFrameDescriptor returns FrameDescriptor(a) var_method + var_lambda1 } b.call } a.call }This info is used by the runtime to optimize compilation order by giving more priority to lexical parents which are likely to inline the child thus resulting in better performance sooner rather than waiting for the lexical parent to get hot on its own.
null
otherwise.protected int computeSize()
-1
is returned, the regular
AST size estimate is going to be used. By default this method returns -1
.
The size estimate is guaranteed to be invoked only once when the CallTarget
is
created. This corresponds to calls to RootNode.getCallTarget()
for the first time. This
method will never be invoked after the root node was already executed.