Class RootNode

All Implemented Interfaces:
NodeInterface, Cloneable

public abstract class RootNode extends ExecutableNode
Represents the root node in a Truffle AST. The root node is a 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.

Construction

The root node can be constructed with a 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.

Execution

In order to execute a root node, its call target is lazily created and can be accessed via 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.

Cardinalities

One root node instance refers to other classes using the following cardinalities:

Instrumentation

A root node can be instrumented if the following conditions apply:
  • A non-null language is passed in the root node constructor.
  • isInstrumentable() is overridden and returns true.
  • Node.getSourceSection() is overridden and returns a non-null value.
  • The AST contains at least one node that implements InstrumentableNode.
  • It is recommended that children of instrumentable root nodes are tagged with 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().

Since:
0.8 or earlier
  • Constructor Details

  • Method Details

    • copy

      public Node copy()
      Description copied from class: Node
      Creates a shallow copy of this node.
      Overrides:
      copy in class Node
      Returns:
      the new copy
      Since:
      0.8 or earlier
    • getQualifiedName

      public String getQualifiedName()
      Returns a qualified name of the AST that in the best case uniquely identifiers the method. If the qualified name is not specified by the root, then the 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
      Since:
      20.0.0 beta 1
    • getName

      public 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. Can be called on any thread and without a language context. The name of a root node that represents a Java method could consist of the method name. E.g. 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.

      Returns:
      a name that helps guest language programmers identify code corresponding to the AST, possibly null if the language implementation is unable to provide any useful information.
      Since:
      0.15
    • isInternal

      public boolean isInternal()
      Returns 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.

      Since:
      0.27
    • countsTowardsStackTraceLimit

      protected boolean countsTowardsStackTraceLimit()
      Returns true if this root node should count towards AbstractTruffleException.getStackTraceElementLimit().

      By default, returns the negation of 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.

      Since:
      21.2.0
    • isCaptureFramesForTrace

      public boolean isCaptureFramesForTrace()
      Returns 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()
      Since:
      0.31
    • isCloningAllowed

      public boolean isCloningAllowed()
      Returns 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 .
      Returns:
      true if cloning is allowed else false.
      Since:
      0.8 or earlier
    • isCloneUninitializedSupported

      protected boolean isCloneUninitializedSupported()
      Returns true if 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.
      Returns:
      true if calls to uninitialized copies are supported.
      Since:
      0.24
      See Also:
    • cloneUninitialized

      protected RootNode cloneUninitialized()
      Creates an uninitialized copy of an already initialized/executed root node if it is supported. Throws an UnsupportedOperationException exception by default. By default, or if 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 cloneUninitialized() are:

      • Reparsing: Support it by keeping a reference to the original source code including the lexical scope and create the uninitialized copy of the root node by reparsing the source.
      • Resetting: Support it by traversing the Node tree and derive an uninitialized copy from each initialized node.
      Returns:
      an uninitialized copy of this root node if supported.
      Throws:
      UnsupportedOperationException - if not supported
      Since:
      0.24
      See Also:
    • execute

      public abstract Object execute(VirtualFrame frame)
      Executes this function using the specified frame and returns the result value.
      Specified by:
      execute in class ExecutableNode
      Parameters:
      frame - the frame of the currently executing guest language method
      Returns:
      the value of the execution
      Since:
      0.8 or earlier
    • getCallTarget

      public final RootCallTarget getCallTarget()
      Since:
      0.8 or earlier
    • getFrameDescriptor

      public final FrameDescriptor getFrameDescriptor()
      Since:
      0.8 or earlier
    • isInstrumentable

      protected boolean isInstrumentable()
      Does this contain AST content that it is possible to instrument. Can be called on any thread and without a language context.
      Since:
      0.8 or earlier
    • isTrivial

      protected boolean isTrivial()
      Is this root node to be considered trivial by the runtime. A trivial root node is defined as a root node that:
      1. Never increases code size when inlined, i.e. is always less complex then the call.
      2. Never performs guest language calls.
      3. Never contains loops.
      4. Is small (for a language-specific definition of small).
      An good example of trivial root nodes would be getters and setters in java.
      Returns:
      true if this root node should be considered trivial by the runtime. false otherwise.
      Since:
      20.3.0
    • findAsynchronousFrames

      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. The asynchronous frames are expected to be found here when 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.
      Parameters:
      frame - A frame, never null
      Returns:
      a list of TruffleStackTraceElement, or null when no asynchronous stack is available.
      Since:
      20.1.0
      See Also:
    • translateStackTraceElement

      protected Object translateStackTraceElement(TruffleStackTraceElement element)
      Translates the 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.

      Since:
      20.3
      See Also:
    • prepareForAOT

      protected ExecutionSignature prepareForAOT()
      Allows languages to perform actions before a root node is attempted to be compiled without prior call to 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:

      • Initialize local variable types in the FrameDescriptor of the root node. Without that any access to the frame will invalidate the code on first execute.
      • Initialize specializing nodes with profiles that do not invalidate on first execution. For initialization of Truffle DSL nodes see AOTSupport.
      • Compute the expected execution signature of a root node and return it.

      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.

      Since:
      20.3
    • createConstantNode

      public static RootNode createConstantNode(Object constant)
      Helper method to create a root node that always returns the same value. Certain operations (especially 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.
      Parameters:
      constant - the constant to return
      Returns:
      root node returning the constant
      Since:
      0.8 or earlier
    • getParentFrameDescriptor

      protected FrameDescriptor getParentFrameDescriptor()
      If this root node has a lexical scope parent, this method returns its frame descriptor. As an example, consider the following pseudocode:
       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.
      Returns:
      The frame descriptor of the lexical parent scope if it exists. null otherwise.
      Since:
      22.3.0
    • isSameFrame

      protected boolean isSameFrame(Frame frame1, Frame frame2)
      Tests if two frames are the same. This method is mainly used by instruments in case of yield of the execution and later resume. Frame comparison is used to match the particular yielded and resumed execution.

      The default implementation compares the frames identity.

      Since:
      24.0
    • computeSize

      protected int computeSize()
      Computes a size estimate of this root node. This is intended to be overwritten if the size of the root node cannot be estimated from the natural AST size. For example, in case the root node is represented by a bytecode interpreter. If -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 getCallTarget() for the first time. This method will never be invoked after the root node was already executed.

      Since:
      23.0