com.oracle.truffle.api.nodes.RootNode Maven / Gradle / Ivy
Show all versions of truffle-api Show documentation
/*
* Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* The Universal Permissive License (UPL), Version 1.0
*
* Subject to the condition set forth below, permission is hereby granted to any
* person obtaining a copy of this software, associated documentation and/or
* data (collectively the "Software"), free of charge and under any and all
* copyright rights in the Software, and any and all patent rights owned or
* freely licensable by each licensor hereunder covering either (i) the
* unmodified Software as contributed to or provided by such licensor, or (ii)
* the Larger Works (as defined below), to deal in both
*
* (a) the Software, and
*
* (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if
* one is included with the Software each a "Larger Work" to which the Software
* is contributed by such licensors),
*
* without restriction, including without limitation the rights to copy, create
* derivative works of, display, perform, and distribute the Software and make,
* use, sell, offer for sale, import, export, have made, and have sold the
* Software and the Larger Work(s), and to sublicense the foregoing rights on
* either these or other terms.
*
* This license is subject to the following condition:
*
* The above copyright notice and either this complete permission notice or at a
* minimum a reference to the UPL must be included in all copies or substantial
* portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.oracle.truffle.api.nodes;
import java.util.concurrent.locks.ReentrantLock;
import com.oracle.truffle.api.CallTarget;
import com.oracle.truffle.api.CompilerAsserts;
import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
import com.oracle.truffle.api.CompilerOptions;
import com.oracle.truffle.api.RootCallTarget;
import com.oracle.truffle.api.TruffleLanguage;
import com.oracle.truffle.api.TruffleLanguage.ContextReference;
import com.oracle.truffle.api.TruffleLanguage.Env;
import com.oracle.truffle.api.TruffleLanguage.ParsingRequest;
import com.oracle.truffle.api.TruffleRuntime;
import com.oracle.truffle.api.TruffleStackTraceElement;
import com.oracle.truffle.api.frame.Frame;
import com.oracle.truffle.api.frame.FrameDescriptor;
import com.oracle.truffle.api.frame.FrameInstance;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.impl.Accessor.EngineSupport;
import com.oracle.truffle.api.impl.DefaultCompilerOptions;
import com.oracle.truffle.api.source.Source;
import com.oracle.truffle.api.source.SourceSection;
/**
* Represents the root node in a Truffle AST. The root node is a {@link Node node} that allows to be
* {@link #execute(VirtualFrame) executed} using a {@link VirtualFrame frame} instance created by
* the framework. Please note that the {@link RootNode} should not be executed directly but using
* {@link CallTarget#call(Object...)}. The structure of the frame is provided by the
* {@link FrameDescriptor frame descriptor} passed in the constructor. A root node has always a
* null
{@link #getParent() parent} and cannot be {@link #replace(Node) replaced}.
*
* Construction
*
* The root node can be constructed with a {@link TruffleLanguage language implementation} if it is
* available. The language implementation instance is obtainable while
* {@link TruffleLanguage#createContext(Env)} or {@link 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 have
* no access to the {@link #getLanguage(Class) language} or its public {@link #getLanguageInfo()
* information}.
*
* Execution
*
* In order to execute a root node, a call target needs to be created using
* {@link TruffleRuntime#createCallTarget(RootNode)}. This allows the runtime system to optimize the
* execution of the AST. The {@link CallTarget} can either be {@link CallTarget#call(Object...)
* called} directly from runtime code or {@link DirectCallNode direct} and {@link IndirectCallNode
* indirect} call nodes can be created, inserted in a child field and
* {@link DirectCallNode#call(Object[]) 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:
*
* - one {@link TruffleLanguage language}
*
- one {@link CallTarget call target}
*
- many {@link TruffleLanguage#createContext(Env) created} language contexts
*
*
* Instrumentation
*
* A root node can be {@linkplain com.oracle.truffle.api.instrumentation instrumented} if the
* following conditions apply:
*
* - A non-null {@link TruffleLanguage language} is passed in the root node constructor.
*
- {@link #isInstrumentable()} is overridden and returns
true
.
* - {@link #getSourceSection()} is overridden and returns a non-null value.
*
- The AST contains at least one node that is annotated with
* {@link com.oracle.truffle.api.instrumentation.Instrumentable}.
*
- It is recommended that children of instrumentable root nodes are tagged with
*
StandardTags
.
*
*
* Note: It is recommended to override {@link #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 {@link Source#createUnavailableSection()}.
*
* @since 0.8 or earlier
*/
public abstract class RootNode extends ExecutableNode {
/*
* Since languages were singletons in the past, we cannot use the Env instance stored in
* TruffleLanguage for languages that are not yet migrated. We use this sourceVM reference
* instead for compatibility.
*/
final Object sourceVM;
private RootCallTarget callTarget;
@CompilationFinal private FrameDescriptor frameDescriptor;
final ReentrantLock lock = new ReentrantLock();
volatile byte instrumentationBits;
/**
* Creates new root node with a given language instance. The language instance is obtainable
* while {@link TruffleLanguage#createContext(Env)} or
* {@link 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 have no access to the
* {@link #getLanguage(Class) language} or its public {@link #getLanguageInfo() information}.
*
* @param language the language this root node is associated with
* @since 0.25
*/
protected RootNode(TruffleLanguage> language) {
this(language, null);
}
/**
* Creates new root node given an language environment and frame descriptor. The language
* instance is obtainable while {@link TruffleLanguage#createContext(Env)} or
* {@link 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 have no access to the
* {@link #getLanguage(Class) language} or its public {@link #getLanguageInfo() information}.
*
* @param language the language this root node is associated with
* @since 0.25
*/
protected RootNode(TruffleLanguage> language, FrameDescriptor frameDescriptor) {
super(language);
CompilerAsserts.neverPartOfCompilation();
if (this.language != null) {
this.sourceVM = Node.ACCESSOR.engineSupport().getVMFromLanguageObject(Node.ACCESSOR.languageSupport().getLanguageInfo(this.language).getEngineObject());
} else {
this.sourceVM = getCurrentVM();
}
this.frameDescriptor = frameDescriptor == null ? new FrameDescriptor() : frameDescriptor;
}
private static Object getCurrentVM() {
EngineSupport engine = Node.ACCESSOR.engineSupport();
if (engine != null) {
return engine.getCurrentVM();
} else {
return null;
}
}
/**
* Returns the current context associated with the root node {@link #getLanguage(Class)
* language} and {@link Thread thread}. The current context is null
if the root
* node is associated with a null
language. This is a short-cut for
* this
. {@link #getLanguage(Class) getLanguage(languageClass)}.
* {@link TruffleLanguage#getContextReference() getContextReference()}.
* {@link ContextReference#get() get()}. If invoked on the fast-path then
* languageClass
must be a compilation final value.
*
* @see #getLanguage(Class)
* @see TruffleLanguage#getContextReference()
* @since 0.27
*/
public final > C getCurrentContext(Class languageClass) {
if (language == null) {
return null;
}
return getLanguage(languageClass).getContextReference().get();
}
/** @since 0.8 or earlier */
@Override
public Node copy() {
RootNode root = (RootNode) super.copy();
root.frameDescriptor = frameDescriptor;
return root;
}
/**
* A description 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.
*
* 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 "{@code ...}". 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.
*
* @return a name that helps guest language programmers identify code corresponding to the AST,
* possibly {@code null} if the language implementation is unable to provide any useful
* information.
* @since 0.15
*/
public String getName() {
return null;
}
/**
* 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 {@link RootNode} is internal if no language was passed in the constructor or if
* the {@link #getSourceSection() 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.
*
* @since 0.27
*/
public boolean isInternal() {
if (getLanguageInfo() == null) {
return true;
}
SourceSection sc = getSourceSection();
if (sc != null) {
return sc.getSource().isInternal();
}
return false;
}
/**
* Returns true
if a TruffleException leaving this node should capture
* {@link 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 {@link TruffleStackTraceElement#getFrame()}
*
* @since 0.31
*/
public boolean isCaptureFramesForTrace() {
return false;
}
/**
* Returns true
if this {@link RootNode} is allowed to be cloned. The runtime
* system might decide to create deep copies of the {@link 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 {@link RootNode}
* .
*
* @return true
if cloning is allowed else false
.
* @since 0.8 or earlier
*/
public boolean isCloningAllowed() {
return false;
}
/**
* Returns true
if {@link #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 {@link RootNode} instance.
*
* @return true
if calls to {@link #cloneUninitialized() uninitialized copies} are
* supported.
* @see #cloneUninitialized()
* @since 0.24
*/
protected boolean isCloneUninitializedSupported() {
return false;
}
/**
* Creates an uninitialized copy of an already initialized/executed root node if it is
* {@link #isCloneUninitializedSupported() supported}. Throws an
* {@link UnsupportedOperationException} exception by default. By default, or if
* {@link #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 {@link #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 {@link Node} tree and derive an
* uninitialized copy from each initialized node.
*
*
* @return an uninitialized copy of this root node if supported.
* @throws UnsupportedOperationException if not supported
* @see #isCloneUninitializedSupported()
* @since 0.24
*/
protected RootNode cloneUninitialized() {
throw new UnsupportedOperationException();
}
/**
* @since 0.8 or earlier
* @deprecated use {@link LoopNode#reportLoopCount(Node,int)} instead
*/
@Deprecated
public final void reportLoopCount(int iterations) {
LoopNode.reportLoopCount(this, iterations);
}
/**
* Executes this function using the specified frame and returns the result value.
*
* @param frame the frame of the currently executing guest language method
* @return the value of the execution
* @since 0.8 or earlier
*/
@Override
public abstract Object execute(VirtualFrame frame);
/** @since 0.8 or earlier */
public final RootCallTarget getCallTarget() {
return callTarget;
}
/** @since 0.8 or earlier */
public final FrameDescriptor getFrameDescriptor() {
return frameDescriptor;
}
/**
* @since 0.8 or earlier
* @deprecated No replacement. Changing {@link CallTarget} of an existing {@link RootNode} isn't
* a supported operation
*/
@Deprecated
public final void setCallTarget(RootCallTarget callTarget) {
this.callTarget = callTarget;
}
/**
* Returns the {@link com.oracle.truffle.api.ExecutionContext} associated with this
* RootNode
. This allows the correct ExecutionContext
to be determined
* for a RootNode
(and so also for a {@link RootCallTarget} and a
* {@link FrameInstance} obtained from the call stack) without prior knowledge of the language
* it has come from.
*
* Returns null
by default.
*
* @since 0.8 or earlier
* @deprecated in 0.25 use {@link #getLanguage(Class) getLanguage(Language.class)}.
* {@link TruffleLanguage#getCurrentContext(Class) getCurrentContext()} instead, and
* {@link RootNode#getCompilerOptions()}.
*/
@SuppressWarnings("deprecation")
@Deprecated
public com.oracle.truffle.api.ExecutionContext getExecutionContext() {
return null;
}
/**
* Get compiler options specific to this RootNode
.
*
* @since 0.8 or earlier
*/
@SuppressWarnings("deprecation")
public CompilerOptions getCompilerOptions() {
final com.oracle.truffle.api.ExecutionContext context = getExecutionContext();
if (context == null) {
return DefaultCompilerOptions.INSTANCE;
} else {
return context.getCompilerOptions();
}
}
/**
* 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
*/
protected boolean isInstrumentable() {
return true;
}
/**
* Helper method to create a root node that always returns the same value. Certain operations
* (especially {@link com.oracle.truffle.api.interop inter-operability} API) require return of
* stable {@link RootNode root nodes}. To simplify creation of such nodes, here is a factory
* method that can create {@link RootNode} that returns always the same value.
*
* @param constant the constant to return
* @return root node returning the constant
* @since 0.8 or earlier
*/
public static RootNode createConstantNode(Object constant) {
return new Constant(constant);
}
private static final class Constant extends RootNode {
private final Object value;
Constant(Object value) {
super(null);
this.value = value;
}
@Override
public Object execute(VirtualFrame frame) {
return value;
}
}
}