/*
* Copyright (c) 2014, 2020, 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;
import static com.oracle.truffle.api.LanguageAccessor.ENGINE;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.ref.WeakReference;
import java.net.URI;
import java.nio.file.FileSystemNotFoundException;
import java.nio.file.StandardOpenOption;
import java.nio.file.attribute.FileAttribute;
import java.time.ZoneId;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.ServiceLoader;
import java.util.concurrent.ExecutorService;
import org.graalvm.options.OptionCategory;
import org.graalvm.options.OptionDescriptor;
import org.graalvm.options.OptionDescriptors;
import org.graalvm.options.OptionKey;
import org.graalvm.options.OptionValues;
import org.graalvm.polyglot.Context;
import org.graalvm.polyglot.Context.Builder;
import org.graalvm.polyglot.Engine;
import org.graalvm.polyglot.EnvironmentAccess;
import org.graalvm.polyglot.Language;
import org.graalvm.polyglot.Value;
import org.graalvm.polyglot.io.FileSystem;
import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
import com.oracle.truffle.api.TruffleFile.FileSystemContext;
import com.oracle.truffle.api.TruffleFile.FileTypeDetector;
import com.oracle.truffle.api.TruffleLanguage.Env;
import com.oracle.truffle.api.frame.Frame;
import com.oracle.truffle.api.frame.FrameDescriptor;
import com.oracle.truffle.api.frame.FrameSlot;
import com.oracle.truffle.api.frame.MaterializedFrame;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.impl.ReadOnlyArrayList;
import com.oracle.truffle.api.io.TruffleProcessBuilder;
import com.oracle.truffle.api.nodes.ExecutableNode;
import com.oracle.truffle.api.nodes.LanguageInfo;
import com.oracle.truffle.api.nodes.Node;
import com.oracle.truffle.api.nodes.RootNode;
import com.oracle.truffle.api.source.Source;
import com.oracle.truffle.api.source.SourceSection;
A Truffle language implementation contains all the services a language should provide to make it composable with other languages. Implementation classes must be annotated with Registration
in order to be discoverable by the Polyglot
API. TruffleLanguage
subclasses must provide a public default constructor. Lifecycle
A language implementation becomes available for use by an engine when metadata is added using the Registration
annotation and the implementation's JAR file placed on the host Java Virtual Machine's class path. A newly created engine locates all available language implementations and creates a descriptor for each. The descriptor holds the language's registered metadata, but its execution environment is not initialized until the language is needed for code execution. That execution environment remains initialized for the lifetime of the engine and is isolated from the environment in any other engine instance.
Language global state can be shared between multiple context instances by saving them in a custom field of the TruffleLanguage
subclass. Languages may control sharing between multiple contexts using its context policy
. By default the context policy is exclusive
: each context has its own separate TruffleLanguage instance.
If the context policy is more permissive then the implementation needs to manually ensure data isolation between the contexts. This means that state associated with a context must not be stored in a TruffleLanguage subclass. ASTs and assumptions can be shared across multiple contexts if modifying them does not affect language semantics. Languages are strongly discouraged from using static mutable state in their languages. Instead TruffleLanguage
instances should be used instead to store global state and their sharing should be configured using context policy
.
Whenever an engine is disposed then each initialized language context will be disposed
.
Context Policy
The number of TruffleLanguage
instances per polyglot
context
is configured by the context policy
. By default an exclusive
language
instance is created for every polyglot context
or inner context
. With policy reuse
, language instances will be reused after a language context was disposed
. With policy
shared
, a language will also be reused if active contexts are not yet disposed. Language instances will only be shared or reused if they are compatible
. Language implementations are encouraged to support the most permissive context policy possible. Please see the individual policies
for details on the implications on the language implementation.
The following illustration shows the cardinalities of the individual components:
N: unbounded P: N for exclusive, 1 for shared context policy L: number of installed languages I: number of installed instruments - 1 : Host VM Processs - N : Engine - N : Context - L : Language Context - P * L : TruffleLanguage
- I : Instrument - 1 : TruffleInstrument
Parse Caching
The result of the parsing request
is cached per language instance, source
, argument
names
and environment options
. The scope of the caching is influenced by the context policy
. Caching may be disabled
for certain sources. It is enabled for new sources by default. Language Configuration
On context creation
each language context is provided with information about the environment environment
. Language can optionally declare configurable
options in getOptionDescriptors()
. Polyglot Bindings
Language implementations communicate with one another (and with instrumentation-based tools such as debuggers) by reading/writing named values into the polyglot
bindings
. This bindings object is used to implement guest language export/import statements used for language interoperation.
A language implementation can also import or export a global symbol by name. The scope may be accessed from multiple threads at the same time. Existing keys are overwritten.
Configuration vs. Initialization
To ensure that a Truffle language can be used in a language-agnostic way, the implementation should be designed to decouple its configuration and initialization from language specifics as much as possible. One aspect of this is the initialization and start of execution via the Context
, which should be designed in a generic way. Language-specific entry points, for instance to emulate the command-line interface of an existing implementation, should be handled externally. Multi-threading
There are two kinds of threads that access contexts of Truffle guest languages:
- Internal threads are
created
and managed by a language for a context. All internally created threads need to be stopped when the context is disposed
. - External threads are created and managed by the host application / language launcher. The host application is allowed to use language contexts from changing threads, sequentially or at the same time if the language
allows
it.
By default every context
only allows access from one thread at the same time. Therefore if the context is tried to be accessed from multiple threads at the same time the access will fail. Languages that want to allow multi-threaded access to a context may override isThreadAccessAllowed(Thread, boolean)
and return true
also for multi-threaded accesses. Initialization actions for multi-threaded access can be performed by overriding initializeMultiThreading(Object)
. Threads are initialized
and
disposed
before and after use with a context. Languages may
create
new threads if the environment allows
it.
Type parameters: See Also: Since: 0.8 or earlier
/**
* A Truffle language implementation contains all the services a language should provide to make it
* composable with other languages. Implementation classes must be annotated with
* {@link Registration} in order to be discoverable by the {@linkplain org.graalvm.polyglot Polyglot
* API}.
*
* {@link TruffleLanguage} subclasses must provide a public default constructor.
*
* <h4>Lifecycle</h4>
*
* A language implementation becomes available for use by an engine when metadata is added using the
* {@link Registration} annotation and the implementation's JAR file placed on the host Java Virtual
* Machine's class path.
* <p>
* A newly created engine locates all available language implementations and creates a
* {@linkplain org.graalvm.polyglot.Language descriptor} for each. The descriptor holds the
* language's registered metadata, but its execution environment is not initialized until the
* language is needed for code execution. That execution environment remains initialized for the
* lifetime of the engine and is isolated from the environment in any other engine instance.
* <p>
* Language global state can be shared between multiple context instances by saving them in a custom
* field of the {@link TruffleLanguage} subclass. Languages may control sharing between multiple
* contexts using its {@link Registration#contextPolicy() context policy}. By default the context
* policy is {@link ContextPolicy#EXCLUSIVE exclusive}: each context has its own separate
* TruffleLanguage instance.
* <p>
* If the context policy is more permissive then the implementation needs to manually ensure data
* isolation between the contexts. This means that state associated with a context must not be
* stored in a TruffleLanguage subclass. ASTs and assumptions can be shared across multiple contexts
* if modifying them does not affect language semantics. Languages are strongly discouraged from
* using static mutable state in their languages. Instead {@link TruffleLanguage} instances should
* be used instead to store global state and their sharing should be configured using
* {@link Registration#contextPolicy() context policy}.
* <p>
* Whenever an engine is disposed then each initialized language context will be
* {@link #disposeContext(Object) disposed}.
*
*
* <h4>Context Policy</h4>
*
* The number of {@link TruffleLanguage} instances per polyglot {@link org.graalvm.polyglot.Context
* context} is configured by the {@link Registration#contextPolicy() context policy}. By default an
* {@link ContextPolicy#EXCLUSIVE exclusive} {@link TruffleLanguage language} instance is created
* for every {@link org.graalvm.polyglot.Context polyglot context} or
* {@link TruffleLanguage.Env#newContextBuilder() inner context}. With policy
* {@link ContextPolicy#REUSE reuse}, language instances will be reused after a language context was
* {@link TruffleLanguage#disposeContext(Object) disposed}. With policy {@link ContextPolicy#SHARED
* shared}, a language will also be reused if active contexts are not yet disposed. Language
* instances will only be shared or reused if they are
* {@link TruffleLanguage#areOptionsCompatible(OptionValues, OptionValues) compatible}. Language
* implementations are encouraged to support the most permissive context policy possible. Please see
* the individual {@link ContextPolicy policies} for details on the implications on the language
* implementation.
* <p>
* The following illustration shows the cardinalities of the individual components:
*
* <pre>
* N: unbounded
* P: N for exclusive, 1 for shared context policy
* L: number of installed languages
* I: number of installed instruments
*
* - 1 : Host VM Processs
* - N : {@linkplain org.graalvm.polyglot.Engine Engine}
* - N : {@linkplain org.graalvm.polyglot.Context Context}
* - L : Language Context
* - P * L : {@link TruffleLanguage TruffleLanguage}
* - I : {@linkplain org.graalvm.polyglot.Instrument Instrument}
* - 1 : {@link com.oracle.truffle.api.instrumentation.TruffleInstrument TruffleInstrument}
* </pre>
*
* <h4>Parse Caching</h4>
*
* The result of the {@link #parse(ParsingRequest) parsing request} is cached per language instance,
* {@link ParsingRequest#getSource() source}, {@link ParsingRequest#getArgumentNames() argument
* names} and environment {@link Env#getOptions() options}. The scope of the caching is influenced
* by the {@link Registration#contextPolicy() context policy}. Caching may be
* {@link Source#isCached() disabled} for certain sources. It is enabled for new sources by default.
*
* <h4>Language Configuration</h4>
*
* On {@link #createContext(Env) context creation} each language context is provided with
* information about the environment {@link Env environment }. Language can optionally declare
* {@link org.graalvm.polyglot.Context.Builder#option(String, String) configurable} options in
* {@link #getOptionDescriptors()}.
*
* <h4>Polyglot Bindings</h4>
*
* Language implementations communicate with one another (and with instrumentation-based tools such
* as debuggers) by reading/writing named values into the {@link Env#getPolyglotBindings() polyglot
* bindings}. This bindings object is used to implement guest language export/import statements used
* for <em>language interoperation</em>.
* <p>
* A language implementation can also {@linkplain Env#importSymbol(String) import} or
* {@linkplain Env#exportSymbol(String, Object) export} a global symbol by name. The scope may be
* accessed from multiple threads at the same time. Existing keys are overwritten.
*
* <h4>Configuration vs. Initialization</h4>
*
* To ensure that a Truffle language can be used in a language-agnostic way, the implementation
* should be designed to decouple its configuration and initialization from language specifics as
* much as possible. One aspect of this is the initialization and start of execution via the
* {@link org.graalvm.polyglot.Context}, which should be designed in a generic way.
* Language-specific entry points, for instance to emulate the command-line interface of an existing
* implementation, should be handled externally.
*
* <h4>Multi-threading</h4>
*
* There are two kinds of threads that access contexts of Truffle guest languages:
* <ul>
* <li>Internal threads are {@link Env#createThread(Runnable) created} and managed by a language for
* a context. All internally created threads need to be stopped when the context is
* {@link #disposeContext(Object) disposed}.
* <li>External threads are created and managed by the host application / language launcher. The
* host application is allowed to use language contexts from changing threads, sequentially or at
* the same time if the language {@link #isThreadAccessAllowed(Thread, boolean) allows} it.
* </ul>
* <p>
* By default every {@link #createContext(Env) context} only allows access from one thread at the
* same time. Therefore if the context is tried to be accessed from multiple threads at the same
* time the access will fail. Languages that want to allow multi-threaded access to a context may
* override {@link #isThreadAccessAllowed(Thread, boolean)} and return <code>true</code> also for
* multi-threaded accesses. Initialization actions for multi-threaded access can be performed by
* overriding {@link #initializeMultiThreading(Object)}. Threads are
* {@link #initializeThread(Object, Thread) initialized} and {@link #disposeContext(Object)
* disposed} before and after use with a context. Languages may {@link Env#createThread(Runnable)
* create} new threads if the environment {@link Env#isCreateThreadAllowed() allows} it.
*
* @param <C> internal state of the language associated with every thread that is executing program
* {@link #parse(com.oracle.truffle.api.TruffleLanguage.ParsingRequest) parsed} by the
* language
* @see org.graalvm.polyglot.Context for embedding of Truffle languages in Java host applications.
* @since 0.8 or earlier
*/
@SuppressWarnings({"javadoc"})
public abstract class TruffleLanguage<C> {
// get and isFinal are frequent operations -> cache the engine access call
@CompilationFinal LanguageInfo languageInfo;
@CompilationFinal ContextReference<Object> reference;
@CompilationFinal Object polyglotLanguageInstance;
List<ContextThreadLocal<?>> contextThreadLocals;
List<ContextLocal<?>> contextLocals;
Constructor to be called by subclasses. Language should not create any RootNode
s in its constructor. The RootNodes created in the language constructor are not associated with a Context and they don't respect Context's engine options. The needed RootNodes can be created in the createContext(Env)
. Since: 0.8 or earlier
/**
* Constructor to be called by subclasses. Language should not create any {@link RootNode}s in
* its constructor. The RootNodes created in the language constructor are not associated with a
* Context and they don't respect Context's engine options. The needed RootNodes can be created
* in the {@link #createContext(Env)}.
*
* @since 0.8 or earlier
*/
protected TruffleLanguage() {
}
The annotation to use to register your language to the Polyglot
API
. By annotating your implementation of TruffleLanguage
by this annotation the language can be discovered on the class path. Since: 0.8 or earlier
/**
* The annotation to use to register your language to the {@link org.graalvm.polyglot Polyglot
* API}. By annotating your implementation of {@link TruffleLanguage} by this annotation the
* language can be discovered on the class path.
*
* @since 0.8 or earlier
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Registration {
Unique id of your language. This id will be exposed to users via the getter. It is used
as group identifier for options of the language.
Returns: identifier of your language Since: 0.8 or earlier
/**
* Unique id of your language. This id will be exposed to users via the getter. It is used
* as group identifier for options of the language.
*
* @return identifier of your language
* @since 0.8 or earlier
*/
String id() default "";
Unique name of your language. This name will be exposed to users via the Language.getName()
getter. Returns: identifier of your language Since: 0.8 or earlier
/**
* Unique name of your language. This name will be exposed to users via the
* {@link org.graalvm.polyglot.Language#getName()} getter.
*
* @return identifier of your language
* @since 0.8 or earlier
*/
String name();
Unique name of your language implementation.
Returns: the implementation name of your language Since: 0.8 or earlier
/**
* Unique name of your language implementation.
*
* @return the implementation name of your language
* @since 0.8 or earlier
*/
String implementationName() default "";
Unique string identifying the language version. This name will be exposed to users via the Language.getVersion()
getter. It inherits from Engine.getVersion()
by default. Returns: version of your language Since: 0.8 or earlier
/**
* Unique string identifying the language version. This name will be exposed to users via
* the {@link org.graalvm.polyglot.Language#getVersion()} getter. It inherits from
* {@link org.graalvm.polyglot.Engine#getVersion()} by default.
*
* @return version of your language
* @since 0.8 or earlier
*/
String version() default "inherit";
Since: 0.8 or earlier Deprecated: split up MIME types into character
and byte
based MIME types.
/**
* @since 0.8 or earlier
* @deprecated split up MIME types into {@link #characterMimeTypes() character} and
* {@link #byteMimeTypes() byte} based MIME types.
*/
@Deprecated
String[] mimeType() default {};
Returns the default MIME type of this language. The default MIME type allows embedders and other language or instruments to find out how content is interpreted if no MIME type was specified. The default MIME type must be specified in the list of supported character
or byte
based MIME types. The default MIME type is mandatory if more than one supported MIME type was specified. If no default MIME type and no supported MIME types were specified then all sources for this language will be interpreted as character
based sources.
See Also: Since: 19.0
/**
* Returns the default MIME type of this language. The default MIME type allows embedders
* and other language or instruments to find out how content is interpreted if no MIME type
* was specified. The default MIME type must be specified in the list of supported
* {@link #characterMimeTypes() character} or {@link #byteMimeTypes() byte} based MIME
* types.
* <p>
* The default MIME type is mandatory if more than one supported MIME type was specified. If
* no default MIME type and no supported MIME types were specified then all sources for this
* language will be interpreted as {@link Source#hasCharacters() character} based sources.
*
* @see LanguageInfo#getDefaultMimeType()
* @see Language#getDefaultMimeType()
* @see #characterMimeTypes()
* @see #byteMimeTypes()
* @since 19.0
*/
String defaultMimeType() default "";
List of MIME types supported by this language which sources should be interpreted as character
based sources. Languages may use MIME types to differentiate supported source kinds. If a MIME type is declared as supported then the language needs to be able to parse
sources of this kind. If only one supported MIME type was specified by a language then it will be used as default
MIME type. If no supported character and byte based MIME types are specified then all sources will be interpreted as character
based. See Also: Returns: array of MIME types assigned to your language files Since: 19.0
/**
* List of MIME types supported by this language which sources should be interpreted as
* {@link Source#hasCharacters() character} based sources. Languages may use MIME types to
* differentiate supported source kinds. If a MIME type is declared as supported then the
* language needs to be able to {@link TruffleLanguage#parse(ParsingRequest) parse} sources
* of this kind. If only one supported MIME type was specified by a language then it will be
* used as {@link #defaultMimeType() default} MIME type. If no supported character and byte
* based MIME types are specified then all sources will be interpreted as
* {@link Source#hasCharacters() character} based.
*
* @return array of MIME types assigned to your language files
* @see #defaultMimeType()
* @see #byteMimeTypes()
* @since 19.0
*/
String[] characterMimeTypes() default {};
List of MIME types supported by this language which sources should be interpreted as byte
based sources. Languages may use MIME types to differentiate supported source kinds. If a MIME type is declared as supported then the language needs to be able to parse
sources of this kind. If only one supported MIME type was specified by a language then it will be used as default
MIME type. If no supported character and byte based MIME types are specified then all sources will be interpreted as character
based. See Also: Returns: array of MIME types assigned to your language files Since: 19.0
/**
* List of MIME types supported by this language which sources should be interpreted as
* {@link Source#hasBytes() byte} based sources. Languages may use MIME types to
* differentiate supported source kinds. If a MIME type is declared as supported then the
* language needs to be able to {@link TruffleLanguage#parse(ParsingRequest) parse} sources
* of this kind. If only one supported MIME type was specified by a language then it will be
* used as {@link #defaultMimeType() default} MIME type. If no supported character and byte
* based MIME types are specified then all sources will be interpreted as
* {@link Source#hasCharacters() character} based.
*
* @return array of MIME types assigned to your language files
* @see #defaultMimeType()
* @see #characterMimeTypes()
* @since 19.0
*/
String[] byteMimeTypes() default {};
Specifies if the language is suitable for interactive evaluation of
sources
. Interactive
languages should be displayed in interactive environments and presented to the user. The default value of this attribute is true
assuming majority of the languages is interactive. Change the value to
false
to opt-out and turn your language into non-interactive one.
Returns: true
if the language should be presented to end-user in an
interactive environmentSince: 0.22
/**
* Specifies if the language is suitable for interactive evaluation of {@link Source
* sources}. {@link #interactive() Interactive} languages should be displayed in interactive
* environments and presented to the user. The default value of this attribute is
* <code>true</code> assuming majority of the languages is interactive. Change the value to
* <code>false</code> to opt-out and turn your language into non-interactive one.
*
* @return <code>true</code> if the language should be presented to end-user in an
* interactive environment
* @since 0.22
*/
boolean interactive() default true;
Returns true
if this language is intended for internal use only. Internal
languages cannot be used in the host environment directly, they can only be used from
other languages or from instruments.
Since: 0.27
/**
* Returns <code>true</code> if this language is intended for internal use only. Internal
* languages cannot be used in the host environment directly, they can only be used from
* other languages or from instruments.
*
* @since 0.27
*/
boolean internal() default false;
Specifies a list of languages that this language depends on. Languages are referenced using their id()
. This has the following effects:
- This language always has access to dependent languages if this language is accessible. Languages may not be accessible if language access is
restricted
. - This language is finalized before dependent language contexts are
finalized
. - This language is disposed before dependent language contexts are
disposed
.
Non-internal
languages implicitly depend on all internal languages. Therefore by default non-internal languages are disposed and finalized before internal languages.
Dependent languages should be parsed with Env.parseInternal(Source, String...)
as the embedder might choose to disable access to it for Env.parsePublic(Source, String...)
.
Dependent languages references are optional. If a dependent language is not installed and the language needs to fail in such a case then the language should fail on context initialization
. Cycles in dependencies will cause an IllegalStateException
when one of the cyclic languages is initialized
.
Since: 0.30
/**
* Specifies a list of languages that this language depends on. Languages are referenced
* using their {@link #id()}. This has the following effects:
* <ul>
* <li>This language always has access to dependent languages if this language is
* accessible. Languages may not be accessible if language access is
* {@link org.graalvm.polyglot.Context#create(String...) restricted}.
* <li>This language is finalized before dependent language contexts are
* {@link TruffleLanguage#finalizeContext(Object) finalized}.
* <li>This language is disposed before dependent language contexts are
* {@link TruffleLanguage#disposeContext(Object) disposed}.
* </ul>
* <p>
* {@link #internal() Non-internal} languages implicitly depend on all internal languages.
* Therefore by default non-internal languages are disposed and finalized before internal
* languages.
* <p>
* Dependent languages should be parsed with {@link Env#parseInternal(Source, String...)} as
* the embedder might choose to disable access to it for
* {@link Env#parsePublic(Source, String...)}.
* <p>
* Dependent languages references are optional. If a dependent language is not installed and
* the language needs to fail in such a case then the language should fail on
* {@link TruffleLanguage#initializeContext(Object) context initialization}. Cycles in
* dependencies will cause an {@link IllegalStateException} when one of the cyclic languages
* is {@link org.graalvm.polyglot.Context#initialize(String) initialized}.
*
* @since 0.30
*/
String[] dependentLanguages() default {
};
Defines the supported policy for reusing languages
per context. I.e. the policy specifies the degree of sharing that is allowed between multiple language contexts. The default policy is exclusive
. Every language is encouraged to try to support a context policy that is as permissive as possible, where exclusive
is the least and
shared
is the most permissive policy. Parse
caching
is scoped per language
instance, therefore the context policy influences its behavior. The context policy applies to contexts that were created using the polyglot API
as well as for
inner contexts
. The context policy does not apply to nodes that were created using the Truffle interop protocol. Therefore, interop message nodes always need to be prepared to be used with policy ContextPolicy.SHARED
.
See Also: Since: 19.0
/**
* Defines the supported policy for reusing {@link TruffleLanguage languages} per context.
* I.e. the policy specifies the degree of sharing that is allowed between multiple language
* contexts. The default policy is {@link ContextPolicy#EXCLUSIVE exclusive}. Every language
* is encouraged to try to support a context policy that is as permissive as possible, where
* {@link ContextPolicy#EXCLUSIVE exclusive} is the least and {@link ContextPolicy#SHARED
* shared} is the most permissive policy. {@link TruffleLanguage#parse(ParsingRequest) Parse
* caching} is scoped per {@link TruffleLanguage language} instance, therefore the context
* policy influences its behavior.
* <p>
* The context policy applies to contexts that were created using the
* {@link org.graalvm.polyglot.Context polyglot API} as well as for {@link TruffleContext
* inner contexts}. The context policy does not apply to nodes that were created using the
* Truffle interop protocol. Therefore, interop message nodes always need to be prepared to
* be used with policy {@link ContextPolicy#SHARED}.
*
* @see TruffleLanguage#parse(ParsingRequest)
* @since 19.0
*/
ContextPolicy contextPolicy() default ContextPolicy.EXCLUSIVE;
Declarative list of classes this language is known to provide. The language is supposed to override its
createContext
method and instantiate and
register
all here in defined services. Languages automatically get created but not yet initialized when their registered service is
requested
.
Since: 19.0 Returns: list of service types that this language can provide
/**
* Declarative list of classes this language is known to provide. The language is supposed
* to override its {@link #createContext(com.oracle.truffle.api.TruffleLanguage.Env)
* createContext} method and instantiate and {@link Env#registerService(java.lang.Object)
* register} all here in defined services.
* <p>
* Languages automatically get created but not yet initialized when their registered
* {@link Env#lookup(com.oracle.truffle.api.nodes.LanguageInfo, java.lang.Class) service is
* requested}.
*
* @since 19.0
* @return list of service types that this language can provide
*/
Class<?>[] services() default {};
Declarative list of FileTypeDetector
classes provided by this language. The language has to support all MIME types recognized by the registered file type detectors
.
Returns: list of file type detectors Since: 19.0
/**
* Declarative list of {@link TruffleFile.FileTypeDetector} classes provided by this
* language.
* <p>
* The language has to support all MIME types recognized by the registered
* {@link TruffleFile.FileTypeDetector file type detectors}.
*
* @return list of file type detectors
* @since 19.0
*/
Class<? extends TruffleFile.FileTypeDetector>[] fileTypeDetectors() default {};
}
Used to register a TruffleLanguage
using a ServiceLoader
. This interface is not intended to be implemented directly by a language developer, rather the implementation is generated by the Truffle DSL. The generated implementation has to inherit the Registration
and ProvidedTags
annotations from the TruffleLanguage
. Since: 19.3.0
/**
* Used to register a {@link TruffleLanguage} using a {@link ServiceLoader}. This interface is
* not intended to be implemented directly by a language developer, rather the implementation is
* generated by the Truffle DSL. The generated implementation has to inherit the
* {@link Registration} and {@code ProvidedTags} annotations from the {@link TruffleLanguage}.
*
* @since 19.3.0
*/
public interface Provider {
Returns the name of a class implementing the TruffleLanguage
. Since: 19.3.0
/**
* Returns the name of a class implementing the {@link TruffleLanguage}.
*
* @since 19.3.0
*/
String getLanguageClassName();
Creates a new instance of a TruffleLanguage
. Since: 19.3.0
/**
* Creates a new instance of a {@link TruffleLanguage}.
*
* @since 19.3.0
*/
TruffleLanguage<?> create();
Creates file type detectors used by the TruffleLanguage
. Since: 19.3.0
/**
* Creates file type detectors used by the {@link TruffleLanguage}.
*
* @since 19.3.0
*/
List<FileTypeDetector> createFileTypeDetectors();
Returns the class names of provided services.
Since: 19.3.0
/**
* Returns the class names of provided services.
*
* @since 19.3.0
*/
Collection<String> getServicesClassNames();
}
Returns true
if the combination of two sets of options allow to share
or reuse
the same language instance, else false
. If options are incompatible then a new language instance will be created for a new context. The first language context
created
for a TruffleLanguage
instance always has compatible options, therefore areOptionsCompatible(OptionValues, OptionValues)
will not be invoked for it. The default implementation returns true
.
If the context policy of a language is set to exclusive
(default behavior) then areOptionsCompatible(OptionValues, OptionValues)
will never be invoked as TruffleLanguage
instances will not be shared for multiple contexts. For the other context policies reuse
and
shared
this method can be used to further restrict the reuse of language instances. Compatibility influences parse caching
because it uses the language
instance as a key.
Example usage of areOptionsCompatible if sharing of the language instances and parse caching should be restricted by the script version option: CompatibleLanguage.areOptionsCompatible
Params: - firstOptions – the options used to create the first context, never
null
- newOptions – the options that will be used for the new context, never
null
See Also: Since: 19.0
/**
* Returns <code>true</code> if the combination of two sets of options allow to
* {@link ContextPolicy#SHARED share} or {@link ContextPolicy#REUSE reuse} the same language
* instance, else <code>false</code>. If options are incompatible then a new language instance
* will be created for a new context. The first language context {@link #createContext(Env)
* created} for a {@link TruffleLanguage} instance always has compatible options, therefore
* {@link #areOptionsCompatible(OptionValues, OptionValues)} will not be invoked for it. The
* default implementation returns <code>true</code>.
* <p>
* If the context policy of a language is set to {@link ContextPolicy#EXCLUSIVE exclusive}
* (default behavior) then {@link #areOptionsCompatible(OptionValues, OptionValues)} will never
* be invoked as {@link TruffleLanguage} instances will not be shared for multiple contexts. For
* the other context policies {@link ContextPolicy#REUSE reuse} and {@link ContextPolicy#SHARED
* shared} this method can be used to further restrict the reuse of language instances.
* Compatibility influences {@link #parse(ParsingRequest) parse caching} because it uses the
* {@link TruffleLanguage language} instance as a key.
* <p>
* Example usage of areOptionsCompatible if sharing of the language instances and parse caching
* should be restricted by the script version option:
*
* {@link TruffleLanguageSnippets.CompatibleLanguage#areOptionsCompatible}
*
* @param firstOptions the options used to create the first context, never <code>null</code>
* @param newOptions the options that will be used for the new context, never <code>null</code>
* @see ContextPolicy
* @see #parse(ParsingRequest)
* @since 19.0
*/
protected boolean areOptionsCompatible(OptionValues firstOptions, OptionValues newOptions) {
return true;
}
Creates internal representation of the executing context suitable for given environment. Each time the language
is used by a new Context
, the system calls this method to let the language
prepare for execution. The returned execution
context is completely language specific; it is however expected it will contain reference to
here-in provided env
and adjust itself according to parameters provided by the
env
object.
The context created by this method is accessible using getCurrentContext(Class<TruffleLanguage<Object>>)
. An IllegalStateException
is thrown if the context is tried to be accessed while the createContext method is executed.
This method shouldn't perform any complex operations. The runtime system is just being initialized and for example making calls into
other languages
and assuming your language is already initialized and others can see it would be wrong - until you return from this method, the initialization isn't over. The same is true for instrumentation, the instruments cannot receive any meta data about code executed during context creation. Should there be a need to perform complex initialization, do it by overriding the initializeContext(Object)
method.
Additional services provided by the language must be registered
by this method otherwise IllegalStateException
is thrown.
May return null
if the language does not need any per-context state. Otherwise it should return a new object instance every time it is called.
Params: - env – the environment the language is supposed to operate in
Returns: internal data of the language in given environment or null
Since: 0.8 or earlier
/**
* Creates internal representation of the executing context suitable for given environment. Each
* time the {@link TruffleLanguage language} is used by a new
* {@link org.graalvm.polyglot.Context}, the system calls this method to let the
* {@link TruffleLanguage language} prepare for <em>execution</em>. The returned execution
* context is completely language specific; it is however expected it will contain reference to
* here-in provided <code>env</code> and adjust itself according to parameters provided by the
* <code>env</code> object.
* <p>
* The context created by this method is accessible using {@link #getCurrentContext(Class)}. An
* {@link IllegalStateException} is thrown if the context is tried to be accessed while the
* createContext method is executed.
* <p>
* This method shouldn't perform any complex operations. The runtime system is just being
* initialized and for example making
* {@link Env#parsePublic(com.oracle.truffle.api.source.Source, java.lang.String...) calls into
* other languages} and assuming your language is already initialized and others can see it
* would be wrong - until you return from this method, the initialization isn't over. The same
* is true for instrumentation, the instruments cannot receive any meta data about code executed
* during context creation. Should there be a need to perform complex initialization, do it by
* overriding the {@link #initializeContext(java.lang.Object)} method.
* <p>
* Additional services provided by the language must be
* {@link Env#registerService(java.lang.Object) registered} by this method otherwise
* {@link IllegalStateException} is thrown.
* <p>
* May return {@code null} if the language does not need any per-{@linkplain Context context}
* state. Otherwise it should return a new object instance every time it is called.
*
* @param env the environment the language is supposed to operate in
* @return internal data of the language in given environment or {@code null}
* @since 0.8 or earlier
*/
protected abstract C createContext(Env env);
Perform any complex initialization. The createContext(Env)
factory method shouldn't do any complex operations. Just create the instance of the context, let the runtime system register it properly. Should there be a need to perform complex initialization, override this method and let the runtime call it later to finish any post initialization actions. Example: PostInitLanguage.createContext
Params: - context – the context created by
createContext(Env)
Throws: - Exception – if something goes wrong
Since: 0.17
/**
* Perform any complex initialization. The
* {@link #createContext(com.oracle.truffle.api.TruffleLanguage.Env) } factory method shouldn't
* do any complex operations. Just create the instance of the context, let the runtime system
* register it properly. Should there be a need to perform complex initialization, override this
* method and let the runtime call it <em>later</em> to finish any <em>post initialization</em>
* actions. Example:
*
* {@link TruffleLanguageSnippets.PostInitLanguage#createContext}
*
* @param context the context created by
* {@link #createContext(com.oracle.truffle.api.TruffleLanguage.Env)}
* @throws java.lang.Exception if something goes wrong
* @since 0.17
*/
protected void initializeContext(C context) throws Exception {
}
Performs language context finalization actions that are necessary before language contexts are disposed
. All installed languages must remain usable after finalization. The finalization order can be influenced by specifying language dependencies
. By default internal languages are finalized last, otherwise the default order is unspecified but deterministic.
While finalization code is run, other language contexts may become initialized. In such a
case, the finalization order may be non-deterministic and/or not respect the order specified
by language dependencies.
All threads created
by a language must be stopped and joined during finalizeContext. The languages are responsible for fulfilling that contract, otherwise an AssertionError
is thrown. It's not safe to use the ExecutorService.awaitTermination(long, TimeUnit)
to detect Thread termination as the polyglot thread may be cancelled before executing the executor worker.
Typical implementation looks like: AsyncThreadLanguage.finalizeContext
Params: - context – the context created by
createContext(Env)
See Also: Since: 0.30
/**
* Performs language context finalization actions that are necessary before language contexts
* are {@link #disposeContext(Object) disposed}. All installed languages must remain usable
* after finalization. The finalization order can be influenced by specifying
* {@link Registration#dependentLanguages() language dependencies}. By default internal
* languages are finalized last, otherwise the default order is unspecified but deterministic.
* <p>
* While finalization code is run, other language contexts may become initialized. In such a
* case, the finalization order may be non-deterministic and/or not respect the order specified
* by language dependencies.
* <p>
* All threads {@link Env#createThread(Runnable) created} by a language must be stopped and
* joined during finalizeContext. The languages are responsible for fulfilling that contract,
* otherwise an {@link AssertionError} is thrown. It's not safe to use the
* {@link ExecutorService#awaitTermination(long, java.util.concurrent.TimeUnit)} to detect
* Thread termination as the polyglot thread may be cancelled before executing the executor
* worker.
* <p>
* Typical implementation looks like:
*
* {@link TruffleLanguageSnippets.AsyncThreadLanguage#finalizeContext}
*
* @see Registration#dependentLanguages() for specifying language dependencies.
* @param context the context created by
* {@link #createContext(com.oracle.truffle.api.TruffleLanguage.Env)}
* @since 0.30
*/
protected void finalizeContext(C context) {
}
Since: 19.0 Deprecated: in 1.0. Got renamed to initializeMultipleContexts()
instead. Instead of returning a boolean configure context policy
.
/**
* @since 19.0
* @deprecated in 1.0. Got renamed to {@link #initializeMultipleContexts()} instead. Instead of
* returning a boolean configure {@link Registration#contextPolicy() context policy}
* .
*/
@Deprecated
protected boolean initializeMultiContext() {
return false;
}
Initializes this language instance for use with multiple contexts. Whether a language instance supports being used for multiple contexts depends on its context policy
. With the default context policy exclusive
, this method will never be invoked. This method will be called prior or after the first context was created for this language. In case an explicit
engine
was used to create a context, then this method will be invoked prior to the creation
of the first language context of a language. For inner contexts, this method may be invoked prior to the first inner context
that is created, but after the the first outer context was created. No guest language code must be invoked in this method. This method is called at most once per language instance.
A language may use this method to invalidate assumptions that assume a single context only.
For example, assumptions that are dependent on the language context data. It is required to
invalidate any such assumptions that are used in the AST when this method is invoked.
See Also: Since: 19.0
/**
* Initializes this language instance for use with multiple contexts. Whether a language
* instance supports being used for multiple contexts depends on its
* {@link Registration#contextPolicy() context policy}.
* <p>
* With the default context policy {@link ContextPolicy#EXCLUSIVE exclusive}, this method will
* never be invoked. This method will be called prior or after the first context was created for
* this language. In case an {@link org.graalvm.polyglot.Context.Builder#engine(Engine) explicit
* engine} was used to create a context, then this method will be invoked prior to the
* {@link #createContext(Env) creation} of the first language context of a language. For inner
* contexts, this method may be invoked prior to the first
* {@link TruffleLanguage.Env#newContextBuilder() inner context} that is created, but after the
* the first outer context was created. No guest language code must be invoked in this method.
* This method is called at most once per language instance.
* <p>
* A language may use this method to invalidate assumptions that assume a single context only.
* For example, assumptions that are dependent on the language context data. It is required to
* invalidate any such assumptions that are used in the AST when this method is invoked.
*
* @see #areOptionsCompatible(OptionValues, OptionValues)
* @see ContextPolicy
* @since 19.0
*/
protected void initializeMultipleContexts() {
}
Disposes the context created by createContext(Env)
. A dispose cleans up all resources associated with a context. The context may become unusable after it was disposed. It is not allowed to run guest language code while disposing a context. Finalization code should be run in finalizeContext(Object)
instead. Finalization will be performed prior to context disposal
. The disposal order can be influenced by specifying
language dependencies
. By default internal languages are disposed last, otherwise the default order is unspecified but deterministic. During disposal no other language must be accessed using the language environment
.
Params: - context – the context created by
createContext(Env)
See Also: Since: 0.8 or earlier
/**
* Disposes the context created by
* {@link #createContext(com.oracle.truffle.api.TruffleLanguage.Env)}. A dispose cleans up all
* resources associated with a context. The context may become unusable after it was disposed.
* It is not allowed to run guest language code while disposing a context. Finalization code
* should be run in {@link #finalizeContext(Object)} instead. Finalization will be performed
* prior to context {@link #disposeContext(Object) disposal}.
* <p>
* The disposal order can be influenced by specifying {@link Registration#dependentLanguages()
* language dependencies}. By default internal languages are disposed last, otherwise the
* default order is unspecified but deterministic. During disposal no other language must be
* accessed using the {@link Env language environment}.
*
* @param context the context created by
* {@link #createContext(com.oracle.truffle.api.TruffleLanguage.Env)}
* @see #finalizeContext(Object) to run finalization code for a context.
* @see #disposeThread(Object, Thread) to perform disposal actions when a thread is no longer
* used.
*
* @since 0.8 or earlier
*/
protected void disposeContext(C context) {
}
Parses the provided source
and generates its appropriate AST representation. The parsing should execute no user code, it should only create the Node
tree to represent the source. If the provided
source
does not correspond naturally to a call target
, the returned call target should create and if necessary initialize the corresponding language entity and return it. The result of the parsing request is cached per language instance, source
and
argument names
. It is safe to assume that current language
instance and argument names
will remain unchanged for a parsed CallTarget
. The scope of the caching is influenced by the context policy
and option compatibility
. Caching may be disabled
for sources. It is enabled for new sources by default.
The argumentNames
may contain symbolic names for actual parameters of the call to the returned value. The result should be a call target with method CallTarget.call(Object...)
that accepts as many arguments as were provided via the ParsingRequest.getArgumentNames()
method.
Implement parse(InlineParsingRequest)
to parse source in a specific context location.
Params: - request – request for parsing
Throws: See Also: Returns: a call target to invoke which also keeps in memory the Node
tree representing just parsed code
Since: 0.22
/**
* Parses the {@link ParsingRequest#getSource() provided source} and generates its appropriate
* AST representation. The parsing should execute no user code, it should only create the
* {@link Node} tree to represent the source. If the {@link ParsingRequest#getSource() provided
* source} does not correspond naturally to a {@link CallTarget call target}, the returned call
* target should create and if necessary initialize the corresponding language entity and return
* it.
* <p>
* The result of the parsing request is cached per language instance,
* {@link ParsingRequest#getSource() source} and {@link ParsingRequest#getArgumentNames()
* argument names}. It is safe to assume that current {@link TruffleLanguage language} instance
* and {@link ParsingRequest#getArgumentNames() argument names} will remain unchanged for a
* parsed {@link CallTarget}. The scope of the caching is influenced by the
* {@link Registration#contextPolicy() context policy} and option
* {@link TruffleLanguage#areOptionsCompatible(OptionValues, OptionValues) compatibility}.
* Caching may be {@link Source#isCached() disabled} for sources. It is enabled for new sources
* by default.
* <p>
* The {@code argumentNames} may contain symbolic names for actual parameters of the call to the
* returned value. The result should be a call target with method
* {@link CallTarget#call(java.lang.Object...)} that accepts as many arguments as were provided
* via the {@link ParsingRequest#getArgumentNames()} method.
* <p>
* Implement {@link #parse(com.oracle.truffle.api.TruffleLanguage.InlineParsingRequest)} to
* parse source in a specific context location.
*
* @see TruffleLanguage.Registration#contextPolicy()
* @param request request for parsing
* @return a call target to invoke which also keeps in memory the {@link Node} tree representing
* just parsed <code>code</code>
* @throws Exception exception can be thrown when parsing goes wrong. Here-in thrown exception
* is propagated to the user who called one of <code>eval</code> methods of
* {@link org.graalvm.polyglot.Context}
* @since 0.22
*/
protected CallTarget parse(ParsingRequest request) throws Exception {
throw new UnsupportedOperationException(
String.format("Override parse method of %s, it will be made abstract in future version of Truffle API!", getClass().getName()));
}
Parses the provided source snippet
at the provided location
and generates its appropriate AST representation. The parsing should execute no user code, it should only create the Node
tree to represent the source. The parsing should be performed in a context (specified by InlineParsingRequest.getLocation()
). The result should be an AST fragment with method ExecutableNode.execute(VirtualFrame)
that accepts frames valid at the provided location
.
When not implemented, null
is returned by default.
Params: - request – request for parsing
Throws: - Exception – exception can be thrown when parsing goes wrong.
Returns: a fragment to invoke which also keeps in memory the Node
tree representing just parsed code
, or null
when
inline parsing of code snippets is not implemented Since: 0.31
/**
* Parses the {@link InlineParsingRequest#getSource() provided source snippet} at the
* {@link InlineParsingRequest#getLocation() provided location} and generates its appropriate
* AST representation. The parsing should execute no user code, it should only create the
* {@link Node} tree to represent the source.
* <p>
* The parsing should be performed in a context (specified by
* {@link InlineParsingRequest#getLocation()}). The result should be an AST fragment with method
* {@link ExecutableNode#execute(com.oracle.truffle.api.frame.VirtualFrame)} that accepts frames
* valid at the {@link InlineParsingRequest#getLocation() provided location}.
* <p>
* When not implemented, <code>null</code> is returned by default.
*
* @param request request for parsing
* @return a fragment to invoke which also keeps in memory the {@link Node} tree representing
* just parsed {@link InlineParsingRequest#getSource() code}, or <code>null</code> when
* inline parsing of code snippets is not implemented
* @throws Exception exception can be thrown when parsing goes wrong.
* @since 0.31
*/
protected ExecutableNode parse(InlineParsingRequest request) throws Exception {
return null;
}
Returns a set of option descriptors that are supported by this language. Option values are accessible using the environment
when the context is created
. To construct option descriptors from a list then OptionDescriptors.create(List<OptionDescriptor>)
can be used. Languages must always return the same option descriptors independent of the language instance or side-effects. See Also: Since: 0.27
/**
* Returns a set of option descriptors that are supported by this language. Option values are
* accessible using the {@link Env#getOptions() environment} when the context is
* {@link #createContext(Env) created}. To construct option descriptors from a list then
* {@link OptionDescriptors#create(List)} can be used. Languages must always return the same
* option descriptors independent of the language instance or side-effects.
*
* @see Option For an example of declaring the option descriptor using an annotation.
* @since 0.27
*/
protected OptionDescriptors getOptionDescriptors() {
return OptionDescriptors.EMPTY;
}
Notifies the language with pre-initialized context about Env
change. See Context
for information how to enable the Context pre-initialization. During the pre-initialization (in the native compilation time) the createContext(Env)
and initializeContext(Object)
methods are called. In the image execution time, the patchContext(Object, Env)
is called on all languages whose contexts were created during the pre-initialization a consequence of Context.create(String...)
invocation. The contexts are patched in a topological order starting from dependent languages. If the patchContext(Object, Env)
is successful for all pre-initialized languages the pre-initialized context is used, otherwise a new context is created.
Typical implementation looks like: PreInitializedLanguage.patchContext
Params: - context – the context created by
createContext(Env)
during pre-initialization - newEnv – the new environment replacing the environment used in pre-initialization phase
Returns: true in case of successful environment update. When the context cannot be updated to a new environment return false to create a new context. By default it returns false
to prevent an usage of pre-initialized context by a language which is not aware of context pre-initialization. Since: 0.31
/**
* Notifies the language with pre-initialized context about {@link Env} change. See
* {@link org.graalvm.polyglot.Context} for information how to enable the Context
* pre-initialization.
* <p>
* During the pre-initialization (in the native compilation time) the
* {@link #createContext(com.oracle.truffle.api.TruffleLanguage.Env)} and
* {@link #initializeContext(java.lang.Object)} methods are called. In the image execution time,
* the {@link #patchContext(java.lang.Object, com.oracle.truffle.api.TruffleLanguage.Env)} is
* called on all languages whose contexts were created during the pre-initialization a
* consequence of {@link org.graalvm.polyglot.Context#create(java.lang.String...)} invocation.
* The contexts are patched in a topological order starting from dependent languages. If the
* {@link #patchContext(java.lang.Object, com.oracle.truffle.api.TruffleLanguage.Env)} is
* successful for all pre-initialized languages the pre-initialized context is used, otherwise a
* new context is created.
* <p>
* Typical implementation looks like:
*
* {@link TruffleLanguageSnippets.PreInitializedLanguage#patchContext}
*
* @param context the context created by
* {@link #createContext(com.oracle.truffle.api.TruffleLanguage.Env)} during
* pre-initialization
* @param newEnv the new environment replacing the environment used in pre-initialization phase
* @return true in case of successful environment update. When the context cannot be updated to
* a new environment return false to create a new context. By default it returns
* {@code false} to prevent an usage of pre-initialized context by a language which is
* not aware of context pre-initialization.
* @since 0.31
*/
protected boolean patchContext(C context, Env newEnv) {
return false;
}
Request for parsing. Contains information of what to parse and in which context.
Since: 0.22
/**
* Request for parsing. Contains information of what to parse and in which context.
*
* @since 0.22
*/
public static final class ParsingRequest {
private final Source source;
private final String[] argumentNames;
private boolean disposed;
ParsingRequest(Source source, String... argumentNames) {
Objects.requireNonNull(source);
this.source = source;
this.argumentNames = argumentNames;
}
The source code to parse.
Returns: the source code, never null
Since: 0.22
/**
* The source code to parse.
*
* @return the source code, never <code>null</code>
* @since 0.22
*/
public Source getSource() {
if (disposed) {
throw new IllegalStateException();
}
return source;
}
Argument names. The result of parsing
is an instance of CallTarget
that can be
invoked
without or with some parameters. If the invocation requires some arguments, and the getSource()
references them, it is essential to name them. Example that uses the argument names: TruffleLanguageSnippets.parseWithParams
Returns: symbolic names for parameters of CallTarget.call(Object...)
Since: 0.22
/**
* Argument names. The result of
* {@link #parse(com.oracle.truffle.api.TruffleLanguage.ParsingRequest) parsing} is an
* instance of {@link CallTarget} that {@link CallTarget#call(java.lang.Object...) can be
* invoked} without or with some parameters. If the invocation requires some arguments, and
* the {@link #getSource()} references them, it is essential to name them. Example that uses
* the argument names:
*
* {@link TruffleLanguageSnippets#parseWithParams}
*
* @return symbolic names for parameters of {@link CallTarget#call(java.lang.Object...)}
* @since 0.22
*/
public List<String> getArgumentNames() {
if (disposed) {
throw new IllegalStateException();
}
return argumentNames == null ? Collections.<String> emptyList() : ReadOnlyArrayList.asList(argumentNames, 0, argumentNames.length);
}
void dispose() {
disposed = true;
}
CallTarget parse(TruffleLanguage<?> truffleLanguage) throws Exception {
return truffleLanguage.parse(this);
}
}
Request for inline parsing. Contains information of what to parse and in which context.
Since: 0.31
/**
* Request for inline parsing. Contains information of what to parse and in which context.
*
* @since 0.31
*/
public static final class InlineParsingRequest {
private final Node node;
private final MaterializedFrame frame;
private final Source source;
private boolean disposed;
InlineParsingRequest(Source source, Node node, MaterializedFrame frame) {
Objects.requireNonNull(source);
this.node = node;
this.frame = frame;
this.source = source;
}
The source code to parse.
Returns: the source code, never null
Since: 0.31
/**
* The source code to parse.
*
* @return the source code, never <code>null</code>
* @since 0.31
*/
public Source getSource() {
if (disposed) {
throw new IllegalStateException();
}
return source;
}
Specifies the code location for parsing. The location is specified as an instance of a Node
in the AST. The node can be getInstrumentedNode.getInstrumentedNode()
, for example. Returns: a Node
defining AST context for the parsing, it's never null
Since: 0.31
/**
* Specifies the code location for parsing. The location is specified as an instance of a
* {@link Node} in the AST. The node can be
* {@link com.oracle.truffle.api.instrumentation.EventContext#getInstrumentedNode()}, for
* example.
*
* @return a {@link Node} defining AST context for the parsing, it's never <code>null</code>
* @since 0.31
*/
public Node getLocation() {
if (disposed) {
throw new IllegalStateException();
}
return node;
}
Specifies the execution context for parsing. If the parsing request is used for evaluation during halted execution, for example as in eval.eval(String)
method, this method provides access to current frame
with local variables, etc. Returns: a MaterializedFrame
exposing the current execution state or null
if there is none Since: 0.31
/**
* Specifies the execution context for parsing. If the parsing request is used for
* evaluation during halted execution, for example as in
* {@link com.oracle.truffle.api.debug.DebugStackFrame#eval(String)} method, this method
* provides access to current {@link MaterializedFrame frame} with local variables, etc.
*
* @return a {@link MaterializedFrame} exposing the current execution state or
* <code>null</code> if there is none
* @since 0.31
*/
public MaterializedFrame getFrame() {
if (disposed) {
throw new IllegalStateException();
}
return frame;
}
void dispose() {
disposed = true;
}
ExecutableNode parse(TruffleLanguage<?> truffleLanguage) throws Exception {
return truffleLanguage.parse(this);
}
}
Called when some other language is seeking for a global symbol. This method is supposed to do
lazy binding, e.g. there is no need to export symbols in advance, it is fine to wait until
somebody asks for it (by calling this method).
The exported object can either be TruffleObject
(e.g. a native object from the other language) to support interoperability between languages, String
or one of the Java primitive wrappers ( Integer
, Double
, Short
, Boolean
, etc.).
The way a symbol becomes exported is language dependent. In general it is preferred
to make the export explicit - e.g. call some function or method to register an object under
specific name. Some languages may however decide to support implicit export of symbols (for
example from global scope, if they have one). However explicit exports should always be
preferred. Implicitly exported object of some name should only be used when there is no
explicit export under such globalName
. To ensure so the infrastructure first
asks all known languages for onlyExplicit
symbols and only when none is found,
it does one more round with onlyExplicit
set to false
.
Params: - context – context to locate the global symbol in
- globalName – the name of the global symbol to find
- onlyExplicit – should the language seek for implicitly exported object or only consider
the explicitly exported ones?
Returns: an exported object or null
, if the symbol does not represent anything
meaningful in this language Since: 0.8 or earlier Deprecated: write to the polyglot bindings
object instead when symbols need to be exported. Implicit exported values should be exposed using getScope(Object)
instead.
/**
* Called when some other language is seeking for a global symbol. This method is supposed to do
* lazy binding, e.g. there is no need to export symbols in advance, it is fine to wait until
* somebody asks for it (by calling this method).
* <p>
* The exported object can either be <code>TruffleObject</code> (e.g. a native object from the
* other language) to support interoperability between languages, {@link String} or one of the
* Java primitive wrappers ( {@link Integer}, {@link Double}, {@link Short}, {@link Boolean},
* etc.).
* <p>
* The way a symbol becomes <em>exported</em> is language dependent. In general it is preferred
* to make the export explicit - e.g. call some function or method to register an object under
* specific name. Some languages may however decide to support implicit export of symbols (for
* example from global scope, if they have one). However explicit exports should always be
* preferred. Implicitly exported object of some name should only be used when there is no
* explicit export under such <code>globalName</code>. To ensure so the infrastructure first
* asks all known languages for <code>onlyExplicit</code> symbols and only when none is found,
* it does one more round with <code>onlyExplicit</code> set to <code>false</code>.
*
* @param context context to locate the global symbol in
* @param globalName the name of the global symbol to find
* @param onlyExplicit should the language seek for implicitly exported object or only consider
* the explicitly exported ones?
* @return an exported object or <code>null</code>, if the symbol does not represent anything
* meaningful in this language
* @since 0.8 or earlier
* @deprecated write to the {@link Env#getPolyglotBindings() polyglot bindings} object instead
* when symbols need to be exported. Implicit exported values should be exposed
* using {@link TruffleLanguage#getScope(Object)} instead.
*/
@Deprecated
protected Object findExportedSymbol(C context, String globalName, boolean onlyExplicit) {
return null;
}
Returns true
if code of this language is allowed to be executed on this thread.
The method returns false
to deny execution on this thread. The default implementation denies access to more than one thread at the same time. The current thread
may differ from the passed thread. If this method throws an AbstractTruffleException
the exception interop messages may be executed without a context being entered.
Example multi-threaded language implementation: MultiThreadedLanguage.initializeThread
Params: - thread – the thread that accesses the context for the first time.
- singleThreaded –
true
if the access is considered single-threaded,
false
if more than one thread is active at the same time.
Since: 0.28
/**
* Returns <code>true</code> if code of this language is allowed to be executed on this thread.
* The method returns <code>false</code> to deny execution on this thread. The default
* implementation denies access to more than one thread at the same time. The
* {@link Thread#currentThread() current thread} may differ from the passed thread. If this
* method throws an {@link com.oracle.truffle.api.exception.AbstractTruffleException} the
* exception interop messages may be executed without a context being entered.
* <p>
* <b>Example multi-threaded language implementation:</b>
* {@link TruffleLanguageSnippets.MultiThreadedLanguage#initializeThread}
*
* @param thread the thread that accesses the context for the first time.
* @param singleThreaded <code>true</code> if the access is considered single-threaded,
* <code>false</code> if more than one thread is active at the same time.
* @since 0.28
*/
protected boolean isThreadAccessAllowed(Thread thread, boolean singleThreaded) {
return singleThreaded;
}
Invoked before the context is accessed from multiple threads at the same time. This allows languages to perform actions that are required to support multi-threading. It will never be invoked if isThreadAccessAllowed(Thread, boolean)
is implemented to deny access from multiple threads at the same time. All initialized languages must allow multi-threading for this method to be invoked. If this method throws an AbstractTruffleException
the exception interop messages may be executed without a context being entered.
Example multi-threaded language implementation: MultiThreadedLanguage.initializeThread
Params: - context – the context that should be prepared for multi-threading.
Since: 0.28
/**
* Invoked before the context is accessed from multiple threads at the same time. This allows
* languages to perform actions that are required to support multi-threading. It will never be
* invoked if {@link #isThreadAccessAllowed(Thread, boolean)} is implemented to deny access from
* multiple threads at the same time. All initialized languages must allow multi-threading for
* this method to be invoked. If this method throws an
* {@link com.oracle.truffle.api.exception.AbstractTruffleException} the exception interop
* messages may be executed without a context being entered.
* <p>
* <b>Example multi-threaded language implementation:</b>
* {@link TruffleLanguageSnippets.MultiThreadedLanguage#initializeThread}
*
* @param context the context that should be prepared for multi-threading.
* @since 0.28
*/
protected void initializeMultiThreading(C context) {
}
Invoked before a context is accessed from a new thread. This allows the language to perform initialization actions for each thread before guest language code is executed. Also for languages that deny access from multiple threads at the same time, multiple threads may be initialized if they are used sequentially. This method will be invoked before the context is initialized
for the thread the context will be initialized with. If the thread is stored in the context it must be referenced using WeakReference
to avoid leaking thread objects. The current thread
may differ from the initialized thread.
If this method throws an AbstractTruffleException
the exception interop messages may be executed without a context being entered.
Example multi-threaded language implementation: MultiThreadedLanguage.initializeThread
Params: - context – the context that is entered
- thread – the thread that accesses the context for the first time.
Since: 0.28
/**
* Invoked before a context is accessed from a new thread. This allows the language to perform
* initialization actions for each thread before guest language code is executed. Also for
* languages that deny access from multiple threads at the same time, multiple threads may be
* initialized if they are used sequentially. This method will be invoked before the context is
* {@link #initializeContext(Object) initialized} for the thread the context will be initialized
* with. If the thread is stored in the context it must be referenced using
* {@link WeakReference} to avoid leaking thread objects.
* <p>
* The {@link Thread#currentThread() current thread} may differ from the initialized thread.
* <p>
* If this method throws an {@link com.oracle.truffle.api.exception.AbstractTruffleException}
* the exception interop messages may be executed without a context being entered.
* <p>
* <b>Example multi-threaded language implementation:</b>
* {@link TruffleLanguageSnippets.MultiThreadedLanguage#initializeThread}
*
* @param context the context that is entered
* @param thread the thread that accesses the context for the first time.
*
* @since 0.28
*/
protected void initializeThread(C context, Thread thread) {
}
Invoked the last time code will be executed for this thread and context. This allows the language to perform cleanup actions for each thread and context. Threads might be disposed before after or while a context is disposed. The current
thread
may differ from the disposed thread. Disposal of threads is only guaranteed for threads that were created by guest languages, so called
polyglot threads
. Other threads, created by the embedder, may be collected by the garbage collector before they can be disposed and may therefore not be disposed. See Also: Since: 0.28
/**
* Invoked the last time code will be executed for this thread and context. This allows the
* language to perform cleanup actions for each thread and context. Threads might be disposed
* before after or while a context is disposed. The {@link Thread#currentThread() current
* thread} may differ from the disposed thread. Disposal of threads is only guaranteed for
* threads that were created by guest languages, so called {@link Env#createThread(Runnable)
* polyglot threads}. Other threads, created by the embedder, may be collected by the garbage
* collector before they can be disposed and may therefore not be disposed.
*
* @see #initializeThread(Object, Thread) For usage details.
* @since 0.28
*/
@SuppressWarnings("unused")
protected void disposeThread(C context, Thread thread) {
}
Returns global object for the language.
The object is expected to be TruffleObject
(e.g. a native object from the other language) but technically it can be one of the Java primitive wrappers (Integer
, Double
, Short
, etc.).
Params: - context – context to find the language global in
Returns: the global object or null
if the language does not support such concept Since: 0.8 or earlier Deprecated: in 0.33 implement getScope(Object)
instead.
/**
* Returns global object for the language.
* <p>
* The object is expected to be <code>TruffleObject</code> (e.g. a native object from the other
* language) but technically it can be one of the Java primitive wrappers ({@link Integer},
* {@link Double}, {@link Short}, etc.).
*
* @param context context to find the language global in
* @return the global object or <code>null</code> if the language does not support such concept
* @since 0.8 or earlier
* @deprecated in 0.33 implement {@link #getScope(Object)} instead.
*/
@Deprecated
protected Object getLanguageGlobal(C context) {
return null;
}
Checks whether the object is provided by this language.
Params: - object – the object to check
Returns: true
if this language can deal with such object in native waySince: 0.8 or earlier Deprecated: implement getLanguageView(Object, Object)
and export getLanguage.getLanguage(Object)
instead.
/**
* Checks whether the object is provided by this language.
*
* @param object the object to check
* @return <code>true</code> if this language can deal with such object in native way
* @since 0.8 or earlier
* @deprecated implement {@link #getLanguageView(Object, Object)} and export
* {@link com.oracle.truffle.api.interop.InteropLibrary#getLanguage(Object)}
* instead.
*/
@Deprecated
protected boolean isObjectOfLanguage(Object object) {
return false;
}
Find a hierarchy of local scopes enclosing the given node
. Unless the node is in a global scope, it is expected that there is at least one scope provided, that corresponds to the enclosing function. The language might provide additional block scopes, closure scopes, etc. Global top scopes are provided by getScope(Object)
. The scope hierarchy should correspond with the scope nesting, from the inner-most to the outer-most. The scopes are expected to contain variables valid at the given node.
Scopes may depend on the information provided by the frame.
Lexical scopes are returned when frame
argument is null
.
When not overridden, the enclosing RootNode
's scope with variables read from its FrameDescriptor
's FrameSlot
s is provided by default.
The findLocalScopes.findLocalScopes(Node, Frame)
provides result of this method to instruments.
Params: - context – the current context of the language
- node – a node to find the enclosing scopes for. The node, is inside a
RootNode
associated with this language. - frame – The current frame the node is in, or
null
for lexical access when
the program is not running, or is not suspended at the node's location.
Returns: an iterable with scopes in their nesting order from the inner-most to the outer-most. Since: 0.30 Deprecated: implement NodeLibrary
instead.
/**
* Find a hierarchy of local scopes enclosing the given {@link Node node}. Unless the node is in
* a global scope, it is expected that there is at least one scope provided, that corresponds to
* the enclosing function. The language might provide additional block scopes, closure scopes,
* etc. Global top scopes are provided by {@link #getScope(Object)}. The scope hierarchy should
* correspond with the scope nesting, from the inner-most to the outer-most. The scopes are
* expected to contain variables valid at the given node.
* <p>
* Scopes may depend on the information provided by the frame. <br/>
* Lexical scopes are returned when <code>frame</code> argument is <code>null</code>.
* <p>
* When not overridden, the enclosing {@link RootNode}'s scope with variables read from its
* {@link FrameDescriptor}'s {@link FrameSlot}s is provided by default.
* <p>
* The
* {@link com.oracle.truffle.api.instrumentation.TruffleInstrument.Env#findLocalScopes(com.oracle.truffle.api.nodes.Node, com.oracle.truffle.api.frame.Frame)}
* provides result of this method to instruments.
*
* @param context the current context of the language
* @param node a node to find the enclosing scopes for. The node, is inside a {@link RootNode}
* associated with this language.
* @param frame The current frame the node is in, or <code>null</code> for lexical access when
* the program is not running, or is not suspended at the node's location.
* @return an iterable with scopes in their nesting order from the inner-most to the outer-most.
* @since 0.30
* @deprecated implement {@link com.oracle.truffle.api.interop.NodeLibrary} instead.
*/
@Deprecated
@SuppressWarnings({"unchecked", "deprecation"})
protected Iterable<Scope> findLocalScopes(C context, Node node, Frame frame) {
assert node != null;
return LanguageAccessor.engineAccess().createDefaultLexicalScope(node, frame, (Class<? extends TruffleLanguage<?>>) getClass());
}
Find a hierarchy of top-most scopes of the language, if any. The scopes should be returned
from the inner-most to the outer-most scope order. The language may return an empty iterable
to indicate no scopes. The returned scope objects may be cached by the caller per language
context. Therefore the method should always return equivalent top-scopes and variables
objects for a given language context. Changes to the top scope by executing guest language
code should be reflected by cached scope instances. It is recommended to store the top-scopes
iterable directly in the language context for efficient access.
Interpretation
In most languages, just evaluating an expression like
Math
is equivalent of a lookup with the identifier 'Math' in the top-most scopes
of the language. Looking up the identifier 'Math' should have equivalent semantics as reading
with the key 'Math' from the variables object of one of the top-most scopes of the language.
In addition languages may optionally allow modification and insertion with the variables
object of the returned top-scopes.
Languages may want to specify multiple top-scopes. It is recommended to stay as close as
possible to the set of top-scopes that as is described in the guest language specification,
if available. For example, in JavaScript, there is a 'global environment' and a 'global
object' scope. While the global environment scope contains class declarations and is not
insertable, the global object scope is used to insert new global variable values and is
therefore insertable.
Use Cases
- Top scopes are accessible to instruments with
findTopScopes.findTopScopes(String)
. They are used by debuggers to access the top-most scopes of the language. - Top scopes available in the
polyglot API
as context bindings
object. When members of the bindings object are read
then the first scope where the key exists is read. If a member is modified
in the bindings object, then the value will be written to the first scope where the key exists. If a new member is added to the bindings object then it is added to the first variables object where the key is insertable. If a member is removed, it is only tried to be removed from the first scope of where such a key exists. If member keys
are requested from the bindings object, then the variable object keys are returned sorted from first to last.
When not overridden then a single read-only scope named 'global' without any keys will be
returned.
Params: - context – the current context of the language
Returns: an iterable with scopes in their nesting order from the inner-most to the outer-most. Since: 0.30 Deprecated: implement getScope(Object)
instead.
/**
* Find a hierarchy of top-most scopes of the language, if any. The scopes should be returned
* from the inner-most to the outer-most scope order. The language may return an empty iterable
* to indicate no scopes. The returned scope objects may be cached by the caller per language
* context. Therefore the method should always return equivalent top-scopes and variables
* objects for a given language context. Changes to the top scope by executing guest language
* code should be reflected by cached scope instances. It is recommended to store the top-scopes
* iterable directly in the language context for efficient access.
* <p>
* <h3>Interpretation</h3> In most languages, just evaluating an expression like
* <code>Math</code> is equivalent of a lookup with the identifier 'Math' in the top-most scopes
* of the language. Looking up the identifier 'Math' should have equivalent semantics as reading
* with the key 'Math' from the variables object of one of the top-most scopes of the language.
* In addition languages may optionally allow modification and insertion with the variables
* object of the returned top-scopes.
* <p>
* Languages may want to specify multiple top-scopes. It is recommended to stay as close as
* possible to the set of top-scopes that as is described in the guest language specification,
* if available. For example, in JavaScript, there is a 'global environment' and a 'global
* object' scope. While the global environment scope contains class declarations and is not
* insertable, the global object scope is used to insert new global variable values and is
* therefore insertable.
* <p>
* <h3>Use Cases</h3>
* <ul>
* <li>Top scopes are accessible to instruments with
* {@link com.oracle.truffle.api.instrumentation.TruffleInstrument.Env#findTopScopes(java.lang.String)}
* . They are used by debuggers to access the top-most scopes of the language.
* <li>Top scopes available in the {@link org.graalvm.polyglot polyglot API} as context
* {@link Context#getBindings(String) bindings} object. When members of the bindings object are
* {@link Value#getMember(String) read} then the first scope where the key exists is read. If a
* member is {@link Value#putMember(String, Object) modified} in the bindings object, then the
* value will be written to the first scope where the key exists. If a new member is added to
* the bindings object then it is added to the first variables object where the key is
* insertable. If a member is removed, it is only tried to be removed from the first scope of
* where such a key exists. If {@link Value#getMemberKeys() member keys} are requested from the
* bindings object, then the variable object keys are returned sorted from first to last.
* </ul>
* <p>
* When not overridden then a single read-only scope named 'global' without any keys will be
* returned.
*
* @param context the current context of the language
* @return an iterable with scopes in their nesting order from the inner-most to the outer-most.
* @since 0.30
* @deprecated implement {@link #getScope(Object)} instead.
*/
@SuppressWarnings("deprecation")
@Deprecated
protected Iterable<Scope> findTopScopes(C context) {
Object global = getLanguageGlobal(context);
return LanguageAccessor.engineAccess().createDefaultTopScope(global);
}
Get a top scope of the language, if any. The returned object must be an interop scope object
and may have
parent scopes
. The scope object exposes all top scopes variables as flattened members
. Top scopes are independent of a Frame
. See isScope.isScope(Object)
for details.
The returned scope objects may be cached by the caller per language context. Therefore the
method should always return equivalent top-scopes and variables objects for a given language
context. Changes to the top scope by executing guest language code should be reflected by
cached scope instances. It is recommended to store the top-scope directly in the language
context for efficient access.
Interpretation
In most languages, just evaluating an expression like
Math
is equivalent of a lookup with the identifier 'Math' in the top-most scopes
of the language. Looking up the identifier 'Math' should have equivalent semantics as reading
with the key 'Math' from the variables object of one of the top-most scopes of the language.
In addition languages may optionally allow modification and insertion with the variables
object of the returned top-scopes.
Languages may want to specify multiple parent top-scopes. It is recommended to stay as close
as possible to the set of top-scopes that as is described in the guest language
specification, if available. For example, in JavaScript, there is a 'global environment' and
a 'global object' scope. While the global environment scope contains class declarations and
is not insertable, the global object scope is used to insert new global variable values and
is therefore insertable.
Use Cases
- Top scopes are accessible to instruments with
getScope.getScope(LanguageInfo)
. They are used by debuggers to access the top-most scopes of the language. - Top scopes available in the
polyglot API
as context bindings
object. Access to members of the bindings object is applied to the returned scope object via interop.
Params: - context – the context to find the language top scope in
Returns: the scope object or null
if the language does not support such concept Since: 20.3
/**
* Get a top scope of the language, if any. The returned object must be an
* {@link com.oracle.truffle.api.interop.InteropLibrary#isScope(Object) interop scope object}
* and may have {@link com.oracle.truffle.api.interop.InteropLibrary#hasScopeParent(Object)
* parent scopes}. The scope object exposes all top scopes variables as flattened
* {@link com.oracle.truffle.api.interop.InteropLibrary#getMembers(Object) members}. Top scopes
* are independent of a {@link Frame}. See
* {@link com.oracle.truffle.api.interop.InteropLibrary#isScope(Object)} for details.
* <p>
* The returned scope objects may be cached by the caller per language context. Therefore the
* method should always return equivalent top-scopes and variables objects for a given language
* context. Changes to the top scope by executing guest language code should be reflected by
* cached scope instances. It is recommended to store the top-scope directly in the language
* context for efficient access.
* <p>
* <h3>Interpretation</h3> In most languages, just evaluating an expression like
* <code>Math</code> is equivalent of a lookup with the identifier 'Math' in the top-most scopes
* of the language. Looking up the identifier 'Math' should have equivalent semantics as reading
* with the key 'Math' from the variables object of one of the top-most scopes of the language.
* In addition languages may optionally allow modification and insertion with the variables
* object of the returned top-scopes.
* <p>
* Languages may want to specify multiple parent top-scopes. It is recommended to stay as close
* as possible to the set of top-scopes that as is described in the guest language
* specification, if available. For example, in JavaScript, there is a 'global environment' and
* a 'global object' scope. While the global environment scope contains class declarations and
* is not insertable, the global object scope is used to insert new global variable values and
* is therefore insertable.
* <p>
* <h3>Use Cases</h3>
* <ul>
* <li>Top scopes are accessible to instruments with
* {@link com.oracle.truffle.api.instrumentation.TruffleInstrument.Env#getScope(LanguageInfo)}.
* They are used by debuggers to access the top-most scopes of the language.
* <li>Top scopes available in the {@link org.graalvm.polyglot polyglot API} as context
* {@link Context#getBindings(String) bindings} object. Access to members of the bindings object
* is applied to the returned scope object via interop.
* </ul>
* <p>
*
* @param context the context to find the language top scope in
* @return the scope object or <code>null</code> if the language does not support such concept
* @since 20.3
*/
@SuppressWarnings({"deprecation", "unchecked"})
protected Object getScope(C context) {
Iterable<Scope> legacyScopes = findTopScopes(context);
return LanguageAccessor.engineAccess().legacyScopes2ScopeObject(null, legacyScopes.iterator(), (Class<? extends TruffleLanguage<?>>) getClass());
}
Generates language specific textual representation of a value. Each language may have special formating conventions - even primitive values may not follow the traditional Java formating rules. As such when Value.toString()
is requested, it consults the language that produced the value by calling this method. By default this method calls Objects.toString(Object)
. Params: - context – the execution context for doing the conversion
- value – the value to convert. Either primitive type or
TruffleObject
Returns: textual representation of the value in this language Since: 0.8 or earlier Deprecated: implement getLanguageView(Object, Object)
and toDisplayString.toDisplayString(Object)
instead.
/**
* Generates language specific textual representation of a value. Each language may have special
* formating conventions - even primitive values may not follow the traditional Java formating
* rules. As such when {@link org.graalvm.polyglot.Value#toString()} is requested, it consults
* the language that produced the value by calling this method. By default this method calls
* {@link Objects#toString(java.lang.Object)}.
*
* @param context the execution context for doing the conversion
* @param value the value to convert. Either primitive type or
* {@link com.oracle.truffle.api.interop.TruffleObject}
* @return textual representation of the value in this language
* @since 0.8 or earlier
* @deprecated implement {@link #getLanguageView(Object, Object)} and
* {@link com.oracle.truffle.api.interop.InteropLibrary#toDisplayString(Object)}
* instead.
*/
@Deprecated
protected String toString(C context, Object value) {
return Objects.toString(value);
}
Decides whether the result of evaluating an interactive source should be printed to stdout.
By default this methods returns true
claiming all values are visible.
This method affects behavior of Context.eval(Source)
- when evaluating an interactive source
the result of the evaluation is tested for visibility
and if the value is found visible, it gets converted to string and printed to standard output
.
A language can control whether a value is or isn't printed by overriding this method and
returning false
for some or all values. In such case it is up to the language itself to use the Env.out()
, Env.err()
and Env.in()
streams of the environment. When evaluation is called with an interactive source
of a language that controls its interactive behavior, it is the responsibility of the language itself to print the result to use the Env.out()
, Env.err()
and Env.in()
streams of the environment.
Params: - context – the execution context for doing the conversion
- value – the value to check. Either primitive type or
TruffleObject
Returns: true
if the language implements an interactive response to evaluation of
interactive sources.Since: 0.22
/**
* Decides whether the result of evaluating an interactive source should be printed to stdout.
* By default this methods returns <code>true</code> claiming all values are visible.
* <p>
* This method affects behavior of
* {@link org.graalvm.polyglot.Context#eval(org.graalvm.polyglot.Source)} - when evaluating an
* {@link Source#isInteractive() interactive source} the result of the evaluation is tested for
* {@link #isVisible(java.lang.Object, java.lang.Object) visibility} and if the value is found
* visible, it gets converted to string and printed to
* {@link org.graalvm.polyglot.Context.Builder#out(OutputStream) standard output}.
* <p>
* A language can control whether a value is or isn't printed by overriding this method and
* returning <code>false</code> for some or all values. In such case it is up to the language
* itself to use the {@link Env#out()}, {@link Env#err()} and {@link Env#in()} streams of the
* environment.
*
* When evaluation is called with an {@link Source#isInteractive() interactive source} of a
* language that controls its interactive behavior, it is the responsibility of the language
* itself to print the result to use the {@link Env#out()}, {@link Env#err()} and
* {@link Env#in()} streams of the environment.
*
* @param context the execution context for doing the conversion
* @param value the value to check. Either primitive type or
* {@link com.oracle.truffle.api.interop.TruffleObject}
* @return <code>true</code> if the language implements an interactive response to evaluation of
* interactive sources.
* @since 0.22
*/
protected boolean isVisible(C context, Object value) {
return true;
}
Wraps the value to provide language-specific information for primitive and foreign values. Foreign values should be enhanced to look like the most generic object type of the language. The wrapper needs to introduce any "virtual" methods and properties that are commonly used in language constructs and in algorithms that are written to work on this generic object type. The wrapper may add or remove existing interop traits, but it is not allowed to change the interop type
. For example, it is not allowed to change the type from number to string. If the behavior of an existing trait is modified then all writes on the mapper need to be forwarded to the underlying object, apart from the virtual members. Writes to the virtual members should be persisted in the wrapper if this is the behavior of the object type that is being mapped to. Every language view wrapper must return the current language as their associated language
. An AssertionError
is thrown when a language view is requested if this contract is violated.
Example modifications language view wrappers may perform:
- Provide a language specific
display string
for primitive and foreign values. - Return a language specific
metaobject
for primitive or foreign values. - Add virtual members to the object for the view. For example, any JavaScript object is
expected to have an implicit __proto__ member. Foreign objects, even if they do not have such
a member, are interpreted as if they have.
- There are languages where all scalar values are also vectors. In such a case the array
element trait may be added using the language wrapper to such values.
The default implementation returns null
. If null
is returned then the default language view will be used. The default language view wraps the value and returns the current language as their associated language. With the default view wrapper all interop library messages will be forwarded to the delegate value, except the messages for metaobjects
and display strings
.
This following example shows a simplified language view. For a full implementation including
an example of metaobjects can be found in the Truffle examples language "SimpleLanguage".
@ExportLibrary(value = InteropLibrary.class, delegateTo = "delegate")
final class ExampleLanguageView implements TruffleObject {
protected final Object delegate;
ExampleLanguageView(Object delegate) {
this.delegate = delegate;
}
@ExportMessage
boolean hasLanguage() {
return true;
}
@ExportMessage
Class<? extends TruffleLanguage<?>> getLanguage() {
return MyLanguage.class;
}
@ExportMessage
Object toDisplayString(boolean allowSideEffects,
@CachedLibrary("this.delegate") InteropLibrary dLib) {
try {
if (dLib.isString(this.delegate)) {
return dLib.asString(this.delegate);
} else if (dLib.isBoolean(this.delegate)) {
return dLib.asBoolean(this.delegate) ? "TRUE" : "FALSE";
} else if (dLib.fitsInLong(this.delegate)) {
return longToString(dLib.asLong(this.delegate));
} else {
// full list truncated for this language
return "Unsupported value";
}
} catch (UnsupportedMessageException e) {
CompilerDirectives.transferToInterpreter();
throw new AssertionError(e);
}
}
@TruffleBoundary
private static String longToString(long value) {
return String.valueOf(value);
}
@ExportMessage
boolean hasMetaObject(@CachedLibrary("this.delegate") InteropLibrary dLib) {
return dLib.isString(this.delegate)//
|| dLib.fitsInLong(this.delegate)//
|| dLib.isBoolean(this.delegate);
}
@ExportMessage
Object getMetaObject(@CachedLibrary("this.delegate") InteropLibrary dLib)
throws UnsupportedMessageException {
if (dLib.isString(this.delegate)) {
return MyMetaObject.PRIMITIVE_STRING;
} else if (dLib.isBoolean(this.delegate)) {
return MyMetaObject.PRIMITIVE_LONG;
} else if (dLib.fitsInLong(this.delegate)) {
return MyMetaObject.PRIMITIVE_BOOLEAN;
} else {
// no associable metaobject
throw UnsupportedMessageException.create();
}
}
}
Params: - context – the current context.
- value – the value
Since: 20.1
/**
* Wraps the value to provide language-specific information for primitive and foreign values.
* Foreign values should be enhanced to look like the most generic object type of the language.
* The wrapper needs to introduce any "virtual" methods and properties that are commonly used in
* language constructs and in algorithms that are written to work on this generic object type.
* The wrapper may add or remove existing interop traits, but it is not allowed to change the
* {@link com.oracle.truffle.api.interop.InteropLibrary interop type}. For example, it is not
* allowed to change the type from number to string. If the behavior of an existing trait is
* modified then all writes on the mapper need to be forwarded to the underlying object, apart
* from the virtual members. Writes to the virtual members should be persisted in the wrapper if
* this is the behavior of the object type that is being mapped to.
* <p>
* Every language view wrapper must return the current language as their associated
* {@link com.oracle.truffle.api.interop.InteropLibrary#getLanguage(Object) language}. An
* {@link AssertionError} is thrown when a language view is requested if this contract is
* violated.
* <p>
* Example modifications language view wrappers may perform:
* <ul>
* <li>Provide a language specific
* {@link com.oracle.truffle.api.interop.InteropLibrary#toDisplayString(Object) display string}
* for primitive and foreign values.
* <li>Return a language specific
* {@link com.oracle.truffle.api.interop.InteropLibrary#getMetaObject(Object) metaobject} for
* primitive or foreign values.
* <li>Add virtual members to the object for the view. For example, any JavaScript object is
* expected to have an implicit __proto__ member. Foreign objects, even if they do not have such
* a member, are interpreted as if they have.
* <li>There are languages where all scalar values are also vectors. In such a case the array
* element trait may be added using the language wrapper to such values.
* </ul>
* <p>
* The default implementation returns <code>null</code>. If <code>null</code> is returned then
* the default language view will be used. The default language view wraps the value and returns
* the current language as their associated language. With the default view wrapper all interop
* library messages will be forwarded to the delegate value, except the messages for
* {@link com.oracle.truffle.api.interop.InteropLibrary#getMetaObject(Object) metaobjects} and
* {@link com.oracle.truffle.api.interop.InteropLibrary#toDisplayString(Object) display strings}
* .
* <p>
* This following example shows a simplified language view. For a full implementation including
* an example of metaobjects can be found in the Truffle examples language "SimpleLanguage".
*
* <pre>
* @ExportLibrary(value = InteropLibrary.class, delegateTo = "delegate")
* final class ExampleLanguageView implements TruffleObject {
*
* protected final Object delegate;
*
* ExampleLanguageView(Object delegate) {
* this.delegate = delegate;
* }
*
* @ExportMessage
* boolean hasLanguage() {
* return true;
* }
*
* @ExportMessage
* Class<? extends TruffleLanguage<?>> getLanguage() {
* return MyLanguage.class;
* }
*
* @ExportMessage
* Object toDisplayString(boolean allowSideEffects,
* @CachedLibrary("this.delegate") InteropLibrary dLib) {
* try {
* if (dLib.isString(this.delegate)) {
* return dLib.asString(this.delegate);
* } else if (dLib.isBoolean(this.delegate)) {
* return dLib.asBoolean(this.delegate) ? "TRUE" : "FALSE";
* } else if (dLib.fitsInLong(this.delegate)) {
* return longToString(dLib.asLong(this.delegate));
* } else {
* // full list truncated for this language
* return "Unsupported value";
* }
* } catch (UnsupportedMessageException e) {
* CompilerDirectives.transferToInterpreter();
* throw new AssertionError(e);
* }
* }
*
* @TruffleBoundary
* private static String longToString(long value) {
* return String.valueOf(value);
* }
*
* @ExportMessage
* boolean hasMetaObject(@CachedLibrary("this.delegate") InteropLibrary dLib) {
* return dLib.isString(this.delegate)//
* || dLib.fitsInLong(this.delegate)//
* || dLib.isBoolean(this.delegate);
* }
*
* @ExportMessage
* Object getMetaObject(@CachedLibrary("this.delegate") InteropLibrary dLib)
* throws UnsupportedMessageException {
* if (dLib.isString(this.delegate)) {
* return MyMetaObject.PRIMITIVE_STRING;
* } else if (dLib.isBoolean(this.delegate)) {
* return MyMetaObject.PRIMITIVE_LONG;
* } else if (dLib.fitsInLong(this.delegate)) {
* return MyMetaObject.PRIMITIVE_BOOLEAN;
* } else {
* // no associable metaobject
* throw UnsupportedMessageException.create();
* }
* }
* }
* </pre>
*
* @param context the current context.
* @param value the value
* @since 20.1
*/
protected Object getLanguageView(C context, Object value) {
return null;
}
Wraps the value to filter or add scoping specific information for values associated with the
current language and location in the code. Allows the language to augment the perspective
tools have on values depending on location and frame. This may be useful to apply local
specific visibility rules. By default this method does return the passed value, not applying
any scope information to the value. If a language does not implement any scoping and/or has
not concept of visibility then this method typically can stay without an implementation. A
typical implementation of this method may do the following:
- Apply visiblity and scoping rules to the value hiding or removing members from the
object.
- Add or remove implicit members that are only available within this source location.
This method is only invoked with values that are associated with the current language
. For values without language the language view
is requested first before the scoped view is requested. If this method needs an implementation then getLanguageView(Object, Object)
should be implemented as well.
Scoped views may be implemented in a very similar way to language views
. Please refer to the examples from this method.
Params: - context – the current context.
- location – the current source location. Guaranteed to be a node from a
RootNode
associated with this language. Never null
. - frame – the current active frame. Guaranteed to be a frame from a
RootNode
associated with this language. Never null
. - value – the value to provide scope information for. Never
null
. Always
associated with this language.
Since: 20.1 Deprecated: in 20.3, implement getView.getView(Object, Frame, Object)
instead.
/**
* Wraps the value to filter or add scoping specific information for values associated with the
* current language and location in the code. Allows the language to augment the perspective
* tools have on values depending on location and frame. This may be useful to apply local
* specific visibility rules. By default this method does return the passed value, not applying
* any scope information to the value. If a language does not implement any scoping and/or has
* not concept of visibility then this method typically can stay without an implementation. A
* typical implementation of this method may do the following:
* <ul>
* <li>Apply visiblity and scoping rules to the value hiding or removing members from the
* object.
* <li>Add or remove implicit members that are only available within this source location.
* </ul>
* <p>
* This method is only invoked with values that are associated with the current
* {@link com.oracle.truffle.api.interop.InteropLibrary#getLanguage(Object) language}. For
* values without language the {@link #getLanguageView(Object, Object) language view} is
* requested first before the scoped view is requested. If this method needs an implementation
* then {@link #getLanguageView(Object, Object)} should be implemented as well.
* <p>
* Scoped views may be implemented in a very similar way to
* {@link #getLanguageView(Object, Object) language views}. Please refer to the examples from
* this method.
*
* @param context the current context.
* @param location the current source location. Guaranteed to be a node from a {@link RootNode}
* associated with this language. Never <code>null</code>.
* @param frame the current active frame. Guaranteed to be a frame from a {@link RootNode}
* associated with this language. Never <code>null</code>.
* @param value the value to provide scope information for. Never <code>null</code>. Always
* associated with this language.
* @since 20.1
* @deprecated in 20.3, implement
* {@link com.oracle.truffle.api.interop.NodeLibrary#getView(Object, Frame, Object)}
* instead.
*/
@Deprecated
@SuppressWarnings("unused")
protected Object getScopedView(C context, Node location, Frame frame, Object value) {
return value;
}
Find a metaobject of a value, if any. The metaobject represents a description of the object,
reveals it's kind and it's features. Some information that a metaobject might define includes
the base object's type, interface, class, methods, attributes, etc.
A programmatic textual representation
should be provided for metaobjects, when possible. The metaobject may have properties describing their structure.
NOTE: Allocating the meta object must not be treated as or cause any reported guest language
value allocations
When no metaobject is known, return null
. The default implementation returns
null
. The metaobject should be an interop value. An interop value can be either
a TruffleObject
(e.g. a native object from the other language) to support interoperability between languages or a String
.
It can be beneficial for performance to return the same value for each guest type (i.e. cache
the metaobjects per context).
Params: - context – the execution context
- value – a value to find the metaobject of
Returns: the metaobject, or null
Since: 0.22 Deprecated: implement getLanguageView(Object, Object)
and export getMetaObject.getMetaObject(Object)
instead.
/**
* Find a metaobject of a value, if any. The metaobject represents a description of the object,
* reveals it's kind and it's features. Some information that a metaobject might define includes
* the base object's type, interface, class, methods, attributes, etc.
* <p>
* A programmatic {@link #toString(java.lang.Object, java.lang.Object) textual representation}
* should be provided for metaobjects, when possible. The metaobject may have properties
* describing their structure.
* <p>
* NOTE: Allocating the meta object must not be treated as or cause any
* {@link com.oracle.truffle.api.instrumentation.AllocationListener reported guest language
* value allocations}
* <p>
* When no metaobject is known, return <code>null</code>. The default implementation returns
* <code>null</code>. The metaobject should be an interop value. An interop value can be either
* a <code>TruffleObject</code> (e.g. a native object from the other language) to support
* interoperability between languages or a {@link String}.
* <p>
* It can be beneficial for performance to return the same value for each guest type (i.e. cache
* the metaobjects per context).
*
* @param context the execution context
* @param value a value to find the metaobject of
* @return the metaobject, or <code>null</code>
* @since 0.22
* @deprecated implement {@link #getLanguageView(Object, Object)} and export
* {@link com.oracle.truffle.api.interop.InteropLibrary#getMetaObject(Object)}
* instead.
*/
@Deprecated
protected Object findMetaObject(C context, Object value) {
return null;
}
Find a source location where a value is declared, if any. This is often useful especially for retrieval of source locations of metaobjects
. The default implementation returns null
.
Params: - context – the execution context
- value – a value to get the source location for
Returns: a source location of the object, or null
Since: 0.22 Deprecated: implement getLanguageView(Object, Object)
and export getSourceLocation.getSourceLocation(Object)
instead.
/**
* Find a source location where a value is declared, if any. This is often useful especially for
* retrieval of source locations of {@link #findMetaObject metaobjects}. The default
* implementation returns <code>null</code>.
*
* @param context the execution context
* @param value a value to get the source location for
* @return a source location of the object, or <code>null</code>
* @since 0.22
* @deprecated implement {@link #getLanguageView(Object, Object)} and export
* {@link com.oracle.truffle.api.interop.InteropLibrary#getSourceLocation(Object)}
* instead.
*/
@Deprecated
protected SourceSection findSourceLocation(C context, Object value) {
return null;
}
Deprecated: in 19.3 as this method is inefficient in many situations. The most efficient context lookup can be achieved knowing the current AST in which it is used. As this method does not know the current node
it must be unnecessarily conservative about the lookup and therefore inefficient. More efficient context reference versions are available for fast-paths by calling Node.lookupContextReference(Class<TruffleLanguage<Object>>)
or for slow-paths getCurrentContext(Class<TruffleLanguage<Object>>)
. Truffle DSL has support for context lookup with
CachedContext
that uses the most efficient lookup automatically. Since: 0.25
/**
* @deprecated in 19.3 as this method is inefficient in many situations. The most efficient
* context lookup can be achieved knowing the current AST in which it is used. As
* this method does not know the current {@link Node node} it must be unnecessarily
* conservative about the lookup and therefore inefficient. More efficient context
* reference versions are available for fast-paths by calling
* {@link Node#lookupContextReference(Class)} or for slow-paths
* {@link TruffleLanguage#getCurrentContext(Class)}. Truffle DSL has support for
* context lookup with {@link com.oracle.truffle.api.dsl.CachedContext
* CachedContext} that uses the most efficient lookup automatically.
*
* @since 0.25
*/
@SuppressWarnings("unchecked")
@Deprecated
public final ContextReference<C> getContextReference() {
if (reference == null) {
throw new IllegalStateException("TruffleLanguage instance is not initialized. Cannot get the current context reference.");
}
return (ContextReference<C>) reference;
}
CallTarget parse(Source source, String... argumentNames) {
ParsingRequest request = new ParsingRequest(source, argumentNames);
CallTarget target;
try {
target = request.parse(this);
} catch (RuntimeException ex) {
throw ex;
} catch (Exception ex) {
throw new RuntimeException(ex);
} finally {
request.dispose();
}
return target;
}
ExecutableNode parseInline(Source source, Node context, MaterializedFrame frame) {
assert context != null;
InlineParsingRequest request = new InlineParsingRequest(source, context, frame);
ExecutableNode snippet;
try {
snippet = request.parse(this);
} catch (RuntimeException ex) {
throw ex;
} catch (Exception ex) {
throw new RuntimeException(ex);
} finally {
request.dispose();
}
return snippet;
}
Returns the current language instance for the current thread
. If a
node
is accessible then Node.lookupLanguageReference(Class<TruffleLanguage>)
should be used instead. Throws an IllegalStateException
if the language is not yet initialized or not executing on this thread. If invoked on the fast-path then languageClass
must be
a compilation final value.
Params: - languageClass – the exact language class needs to be provided for the lookup.
Type parameters: - <T> – the language type
See Also: - Node.lookupLanguageReference(Class<TruffleLanguage>)
- CachedLanguage
Since: 0.27
/**
* Returns the current language instance for the current {@link Thread thread}. If a {@link Node
* node} is accessible then {@link Node#lookupLanguageReference(Class)} should be used instead.
* Throws an {@link IllegalStateException} if the language is not yet initialized or not
* executing on this thread. If invoked on the fast-path then <code>languageClass</code> must be
* a compilation final value.
*
* @param <T> the language type
* @param languageClass the exact language class needs to be provided for the lookup.
* @see Node#lookupLanguageReference(Class)
* @see com.oracle.truffle.api.dsl.CachedLanguage
* @since 0.27
*/
protected static <T extends TruffleLanguage<?>> T getCurrentLanguage(Class<T> languageClass) {
try {
return LanguageAccessor.engineAccess().getCurrentLanguage(languageClass);
} catch (Throwable t) {
CompilerDirectives.transferToInterpreter();
throw Env.engineToLanguageException(t);
}
}
Returns the current language context entered on the current thread. If a node
is accessible then Node.lookupContextReference(Class<TruffleLanguage<Object>>)
should be used instead. An IllegalStateException
is thrown if the language is not yet initialized or not executing on this thread. If invoked on the fast-path then languageClass
must be
a compilation final value.
Params: - languageClass – the exact language class needs to be provided for the lookup.
Type parameters: See Also: Since: 0.27
/**
* Returns the current language context entered on the current thread. If a {@link Node node} is
* accessible then {@link Node#lookupContextReference(Class)} should be used instead. An
* {@link IllegalStateException} is thrown if the language is not yet initialized or not
* executing on this thread. If invoked on the fast-path then <code>languageClass</code> must be
* a compilation final value.
*
* @param <C> the context type
* @param <T> the language type
* @param languageClass the exact language class needs to be provided for the lookup.
* @see Node#lookupContextReference(Class)
* @see com.oracle.truffle.api.dsl.CachedContext
* @since 0.27
*/
protected static <C, T extends TruffleLanguage<C>> C getCurrentContext(Class<T> languageClass) {
try {
return ENGINE.getCurrentContext(languageClass);
} catch (Throwable t) {
CompilerDirectives.transferToInterpreter();
throw Env.engineToLanguageException(t);
}
}
Creates a new context local reference for this Truffle language. Context locals for languages
allow to store additional top-level values for each context besides the language context. The
advantage of context locals compared to storing the value in a field of the language context
is that reading a context local requires one indirection less. It is recommended to use
context locals for languages only if the read is critical for performance.
Context local references must be created during the invocation in the TruffleLanguage
constructor. Calling this method at a later point in time will throw an IllegalStateException
. For each registered TruffleLanguage
subclass it is required to always produce the same number of context local references. The values produced by the factory must not be null
and use a stable exact value type for each
instance of a registered language class. If the return value of the factory is not stable or
null
then an IllegalStateException
is thrown. These restrictions allow the Truffle runtime to read the value more efficiently.
Usage example:
@TruffleLanguage.Registration(id = "example", name = "ExampleLanguage")
public final class ExampleLanguage extends TruffleLanguage {
final ContextLocal contextLocal = createContextLocal(ExampleLocal::new);
@Override
protected Env createContext(Env env) {
return env;
}
@Override
protected CallTarget parse(ParsingRequest request) throws Exception {
return Truffle.getRuntime().createCallTarget(new RootNode(this) {
@Override
public Object execute(VirtualFrame frame) {
// fast read
ExampleLocal local = contextLocal.get();
// access local
return "";
}
});
}
static final class ExampleLocal {
final Env env;
ExampleLocal(Env env) {
this.env = env;
}
}
}
Since: 20.3
/**
* Creates a new context local reference for this Truffle language. Context locals for languages
* allow to store additional top-level values for each context besides the language context. The
* advantage of context locals compared to storing the value in a field of the language context
* is that reading a context local requires one indirection less. It is recommended to use
* context locals for languages only if the read is critical for performance.
* <p>
* Context local references must be created during the invocation in the {@link TruffleLanguage}
* constructor. Calling this method at a later point in time will throw an
* {@link IllegalStateException}. For each registered {@link TruffleLanguage} subclass it is
* required to always produce the same number of context local references. The values produced
* by the factory must not be <code>null</code> and use a stable exact value type for each
* instance of a registered language class. If the return value of the factory is not stable or
* <code>null</code> then an {@link IllegalStateException} is thrown. These restrictions allow
* the Truffle runtime to read the value more efficiently.
* <p>
* Usage example:
*
* <pre>
* @TruffleLanguage.Registration(id = "example", name = "ExampleLanguage")
* public final class ExampleLanguage extends TruffleLanguage<Env> {
*
* final ContextLocal<ExampleLocal> contextLocal = createContextLocal(ExampleLocal::new);
*
* @Override
* protected Env createContext(Env env) {
* return env;
* }
*
* @Override
* protected CallTarget parse(ParsingRequest request) throws Exception {
* return Truffle.getRuntime().createCallTarget(new RootNode(this) {
* @Override
* public Object execute(VirtualFrame frame) {
* // fast read
* ExampleLocal local = contextLocal.get();
* // access local
* return "";
* }
* });
* }
*
* static final class ExampleLocal {
*
* final Env env;
*
* ExampleLocal(Env env) {
* this.env = env;
* }
*
* }
* }
* </pre>
*
* @since 20.3
*/
protected final <T> ContextLocal<T> createContextLocal(ContextLocalFactory<C, T> factory) {
ContextLocal<T> local = ENGINE.createLanguageContextLocal(factory);
if (contextLocals == null) {
contextLocals = new ArrayList<>();
}
try {
contextLocals.add(local);
} catch (UnsupportedOperationException e) {
throw new IllegalStateException("The set of context locals is frozen. Context locals can only be created during construction of the TruffleLanguage subclass.");
}
return local;
}
Creates a new context thread local reference for this Truffle language. Context thread locals
for languages allow to store additional top-level values for each context and thread. The
factory may be invoked on any thread other than the thread of the context thread local value.
Context thread local references must be created during the invocation in the TruffleLanguage
constructor. Calling this method at a later point in time will throw an IllegalStateException
. For each registered TruffleLanguage
subclass it is required to always produce the same number of context thread local references. The values produces by the factory must not be null
and use a stable exact value type for
each instance of a registered language class. If the return value of the factory is not
stable or null
then an IllegalStateException
is thrown. These restrictions allow the Truffle runtime to read the value more efficiently.
Context thread locals should not contain a strong reference to the provided thread. Use a
weak reference instance for that purpose.
Usage example:
@TruffleLanguage.Registration(id = "example", name = "ExampleLanguage")
public static class ExampleLanguage extends TruffleLanguage {
final ContextThreadLocal threadLocal = createContextThreadLocal(ExampleLocal::new);
@Override
protected Env createContext(Env env) {
return env;
}
@Override
protected CallTarget parse(ParsingRequest request) throws Exception {
return Truffle.getRuntime().createCallTarget(new RootNode(this) {
@Override
public Object execute(VirtualFrame frame) {
// fast read
ExampleLocal local = threadLocal.get();
// access local
return "";
}
});
}
static final class ExampleLocal {
final Env env;
final WeakReference thread;
ExampleLocal(Env env, Thread thread) {
this.env = env;
this.thread = new WeakReference<>(thread);
}
}
}
Since: 20.3
/**
* Creates a new context thread local reference for this Truffle language. Context thread locals
* for languages allow to store additional top-level values for each context and thread. The
* factory may be invoked on any thread other than the thread of the context thread local value.
* <p>
* Context thread local references must be created during the invocation in the
* {@link TruffleLanguage} constructor. Calling this method at a later point in time will throw
* an {@link IllegalStateException}. For each registered {@link TruffleLanguage} subclass it is
* required to always produce the same number of context thread local references. The values
* produces by the factory must not be <code>null</code> and use a stable exact value type for
* each instance of a registered language class. If the return value of the factory is not
* stable or <code>null</code> then an {@link IllegalStateException} is thrown. These
* restrictions allow the Truffle runtime to read the value more efficiently.
* <p>
* Context thread locals should not contain a strong reference to the provided thread. Use a
* weak reference instance for that purpose.
* <p>
* Usage example:
*
* <pre>
* @TruffleLanguage.Registration(id = "example", name = "ExampleLanguage")
* public static class ExampleLanguage extends TruffleLanguage<Env> {
*
* final ContextThreadLocal<ExampleLocal> threadLocal = createContextThreadLocal(ExampleLocal::new);
*
* @Override
* protected Env createContext(Env env) {
* return env;
* }
*
* @Override
* protected CallTarget parse(ParsingRequest request) throws Exception {
* return Truffle.getRuntime().createCallTarget(new RootNode(this) {
* @Override
* public Object execute(VirtualFrame frame) {
* // fast read
* ExampleLocal local = threadLocal.get();
* // access local
* return "";
* }
* });
* }
*
* static final class ExampleLocal {
*
* final Env env;
* final WeakReference<Thread> thread;
*
* ExampleLocal(Env env, Thread thread) {
* this.env = env;
* this.thread = new WeakReference<>(thread);
* }
*
* }
* }
* </pre>
*
* @since 20.3
*/
protected final <T> ContextThreadLocal<T> createContextThreadLocal(ContextThreadLocalFactory<C, T> factory) {
ContextThreadLocal<T> local = ENGINE.createLanguageContextThreadLocal(factory);
if (contextThreadLocals == null) {
contextThreadLocals = new ArrayList<>();
}
try {
contextThreadLocals.add(local);
} catch (UnsupportedOperationException e) {
throw new IllegalStateException("The set of context thread locals is frozen. Context thread locals can only be created during construction of the TruffleLanguage subclass.");
}
return local;
}
Returns the home location for this language. This corresponds to the directory in which the
Jar file is located, if run from a Jar file. For an AOT compiled binary, this corresponds to
the location of the language files in the default GraalVM distribution layout. executable or
shared library.
Since: 19.0
/**
* Returns the home location for this language. This corresponds to the directory in which the
* Jar file is located, if run from a Jar file. For an AOT compiled binary, this corresponds to
* the location of the language files in the default GraalVM distribution layout. executable or
* shared library.
*
* @since 19.0
*/
protected final String getLanguageHome() {
try {
return LanguageAccessor.engineAccess().getLanguageHome(LanguageAccessor.nodesAccess().getPolyglotLanguage(languageInfo));
} catch (Throwable t) {
throw Env.engineToLanguageException(t);
}
}
Get the depth of asynchronous stack. When zero, the language should not sacrifice performance
to be able to provide asynchronous stack. When the depth is non-zero, the language should
provide asynchronous stack up to that depth. The language may provide more asynchronous
frames than this depth if it's of no performance penalty, or if requested by other (e.g.
language-specific) options. The returned depth may change at any time.
Override RootNode.findAsynchronousFrames(Frame)
to provide the asynchronous stack frames.
See Also: Since: 20.1.0
/**
* Get the depth of asynchronous stack. When zero, the language should not sacrifice performance
* to be able to provide asynchronous stack. When the depth is non-zero, the language should
* provide asynchronous stack up to that depth. The language may provide more asynchronous
* frames than this depth if it's of no performance penalty, or if requested by other (e.g.
* language-specific) options. The returned depth may change at any time.
* <p>
* Override {@link RootNode#findAsynchronousFrames(Frame)} to provide the asynchronous stack
* frames.
*
* @see RootNode#findAsynchronousFrames(Frame)
* @since 20.1.0
*/
protected final int getAsynchronousStackDepth() {
return LanguageAccessor.engineAccess().getAsynchronousStackDepth(LanguageAccessor.nodesAccess().getPolyglotLanguage(languageInfo));
}
Context local factory for Truffle languages. Creates a new value per context.
Since: 20.3
/**
* Context local factory for Truffle languages. Creates a new value per context.
*
* @since 20.3
*/
@FunctionalInterface
protected interface ContextLocalFactory<C, T> {
Returns a new value for a context local of a language. The returned value must not be
null
and must return a stable and exact type per registered language. A thread local must always return the same class
, even for multiple instances of the same TruffleLanguage
. If this method throws an AbstractTruffleException
the exception interop messages may be executed without a context being entered. See Also: Since: 20.3
/**
* Returns a new value for a context local of a language. The returned value must not be
* <code>null</code> and must return a stable and exact type per registered language. A
* thread local must always return the same {@link Object#getClass() class}, even for
* multiple instances of the same {@link TruffleLanguage}. If this method throws an
* {@link com.oracle.truffle.api.exception.AbstractTruffleException} the exception interop
* messages may be executed without a context being entered.
*
* @see TruffleLanguage#createContextLocal(ContextLocalFactory)
* @since 20.3
*/
T create(C context);
}
Context thread local factory for Truffle languages. Creates a new value per context and
thread.
Since: 20.3
/**
* Context thread local factory for Truffle languages. Creates a new value per context and
* thread.
*
* @since 20.3
*/
@FunctionalInterface
protected interface ContextThreadLocalFactory<C, T> {
Returns a new value for a context thread local for a language context and thread. The
returned value must not be null
and must return a stable and exact type per TruffleLanguage subclass. A thread local must always return the same class
, even for multiple instances of the same TruffleLanguage
. If this method throws an AbstractTruffleException
the exception interop messages may be executed without a context being entered. See Also: Since: 20.3
/**
* Returns a new value for a context thread local for a language context and thread. The
* returned value must not be <code>null</code> and must return a stable and exact type per
* TruffleLanguage subclass. A thread local must always return the same
* {@link Object#getClass() class}, even for multiple instances of the same
* {@link TruffleLanguage}. If this method throws an
* {@link com.oracle.truffle.api.exception.AbstractTruffleException} the exception interop
* messages may be executed without a context being entered.
*
* @see TruffleLanguage#createContextThreadLocal(ContextThreadLocalFactory)
* @since 20.3
*/
T create(C context, Thread thread);
}
Represents execution environment of the TruffleLanguage
. Each active TruffleLanguage
receives instance of the environment before any code is executed upon it. The environment has knowledge of all active languages and can exchange symbols between them. Since: 0.8 or earlier
/**
* Represents execution environment of the {@link TruffleLanguage}. Each active
* {@link TruffleLanguage} receives instance of the environment before any code is executed upon
* it. The environment has knowledge of all active languages and can exchange symbols between
* them.
*
* @since 0.8 or earlier
*/
public static final class Env {
static final Object UNSET_CONTEXT = new Object();
final Object polyglotLanguageContext; // PolylgotLanguageContext
final TruffleLanguage<Object> spi;
private final InputStream in;
private final OutputStream err;
private final OutputStream out;
private final Map<String, Object> config;
private final OptionValues options;
private final String[] applicationArguments;
@CompilationFinal volatile List<Object> services;
@CompilationFinal volatile Object context = UNSET_CONTEXT;
@CompilationFinal volatile Assumption contextUnchangedAssumption = Truffle.getRuntime().createAssumption("Language context unchanged");
@CompilationFinal volatile boolean initialized = false;
@CompilationFinal private volatile Assumption initializedUnchangedAssumption = Truffle.getRuntime().createAssumption("Language context initialized unchanged");
@CompilationFinal volatile boolean valid;
volatile List<Object> languageServicesCollector;
@SuppressWarnings("unchecked")
Env(Object polyglotLanguageContext, TruffleLanguage<?> language, OutputStream out, OutputStream err, InputStream in, Map<String, Object> config, OptionValues options,
String[] applicationArguments) {
this.polyglotLanguageContext = polyglotLanguageContext;
this.spi = (TruffleLanguage<Object>) language;
this.in = in;
this.err = err;
this.out = out;
this.config = config;
this.options = options;
this.applicationArguments = applicationArguments == null ? new String[0] : applicationArguments;
this.valid = true;
}
TruffleFile.FileSystemContext getPublicFileSystemContext() {
return (TruffleFile.FileSystemContext) LanguageAccessor.engineAccess().getPublicFileSystemContext(polyglotLanguageContext);
}
TruffleFile.FileSystemContext getInternalFileSystemContext() {
return (TruffleFile.FileSystemContext) LanguageAccessor.engineAccess().getInternalFileSystemContext(polyglotLanguageContext);
}
Object getPolyglotLanguageContext() {
return polyglotLanguageContext;
}
TruffleLanguage<Object> getSpi() {
return spi;
}
void checkDisposed() {
if (LanguageAccessor.engineAccess().isDisposed(polyglotLanguageContext)) {
throw new IllegalStateException("Language environment is already disposed.");
}
if (!valid) {
throw new IllegalStateException("Language environment is already invalidated.");
}
}
Returns option values for the options described in TruffleLanguage.getOptionDescriptors()
. The returned options are never null
.
Since: 0.27
/**
* Returns option values for the options described in
* {@link TruffleLanguage#getOptionDescriptors()}. The returned options are never
* <code>null</code>.
*
* @since 0.27
*/
public OptionValues getOptions() {
return options;
}
Returns the application arguments that were provided for this context. The arguments
array and its elements are never null
. It is up to the language
implementation whether and how they are accessible within the guest language scripts.
Since: 0.27
/**
* Returns the application arguments that were provided for this context. The arguments
* array and its elements are never <code>null</code>. It is up to the language
* implementation whether and how they are accessible within the guest language scripts.
*
* @since 0.27
*/
public String[] getApplicationArguments() {
return applicationArguments;
}
Returns true
if the creation of new threads is allowed in the current
environment.
See Also: - createThread(Runnable)
Since: 0.28
/**
* Returns <code>true</code> if the creation of new threads is allowed in the current
* environment.
*
* @see #createThread(Runnable)
* @since 0.28
*/
public boolean isCreateThreadAllowed() {
try {
return LanguageAccessor.engineAccess().isCreateThreadAllowed(polyglotLanguageContext);
} catch (Throwable t) {
throw engineToLanguageException(t);
}
}
Creates a new thread that has access to the current language context. See createThread(Runnable, TruffleContext, ThreadGroup, long)
for a detailed description of the parameters. The group
is null and stackSize
set to 0.
Since: 0.28
/**
* Creates a new thread that has access to the current language context. See
* {@link #createThread(Runnable, TruffleContext, ThreadGroup, long)} for a detailed
* description of the parameters. The <code>group</code> is null and <code>stackSize</code>
* set to 0.
*
* @since 0.28
*/
@TruffleBoundary
public Thread createThread(Runnable runnable) {
return createThread(runnable, null);
}
Creates a new thread that has access to the given context. See createThread(Runnable, TruffleContext, ThreadGroup, long)
for a detailed description of the parameters. The group
is null and stackSize
set to 0.
See Also: Since: 0.28
/**
* Creates a new thread that has access to the given context. See
* {@link #createThread(Runnable, TruffleContext, ThreadGroup, long)} for a detailed
* description of the parameters. The <code>group</code> is null and <code>stackSize</code>
* set to 0.
*
* @see #getContext()
* @see #newContextBuilder()
* @since 0.28
*/
@TruffleBoundary
public Thread createThread(Runnable runnable, @SuppressWarnings("hiding") TruffleContext context) {
return createThread(runnable, context, null, 0);
}
Creates a new thread that has access to the given context. See createThread(Runnable, TruffleContext, ThreadGroup, long)
for a detailed description of the parameters. The stackSize
set to 0.
See Also: Since: 0.28
/**
* Creates a new thread that has access to the given context. See
* {@link #createThread(Runnable, TruffleContext, ThreadGroup, long)} for a detailed
* description of the parameters. The <code>stackSize</code> set to 0.
*
* @see #getContext()
* @see #newContextBuilder()
* @since 0.28
*/
@TruffleBoundary
public Thread createThread(Runnable runnable, @SuppressWarnings("hiding") TruffleContext context, ThreadGroup group) {
return createThread(runnable, context, group, 0);
}
Creates a new thread that has access to the given context. A thread is initialized
when it is started
and
disposed
as soon as the thread finished the execution. It is recommended to set an
uncaught exception handler
for the created thread. For example the thread can throw an uncaught exception if one of the initialized language contexts don't support execution on this thread.
The language that created and started the thread is responsible to stop and join it during the finalizeContext
, otherwise an AssertionError
is thrown. It's not safe to use the ExecutorService.awaitTermination(long, TimeUnit)
to detect Thread termination as the polyglot thread may be cancelled before executing the executor worker.
A typical implementation looks like: AsyncThreadLanguage.finalizeContext
The TruffleContext
can be either an inner context created by newContextBuilder()
.build()
, or the context associated with this environment obtained from getContext()
.
Params: - runnable – the runnable to run on this thread.
- context – the context to enter and leave when the thread is started.
- group – the thread group, passed on to the underlying
Thread
. - stackSize – the desired stack size for the new thread, or zero if this parameter is
to be ignored.
Throws: - IllegalStateException – if thread creation is not
allowed
.
See Also: Since: 0.28
/**
* Creates a new thread that has access to the given context. A thread is
* {@link TruffleLanguage#initializeThread(Object, Thread) initialized} when it is
* {@link Thread#start() started} and {@link TruffleLanguage#disposeThread(Object, Thread)
* disposed} as soon as the thread finished the execution.
* <p>
* It is recommended to set an
* {@link Thread#setUncaughtExceptionHandler(java.lang.Thread.UncaughtExceptionHandler)
* uncaught exception handler} for the created thread. For example the thread can throw an
* uncaught exception if one of the initialized language contexts don't support execution on
* this thread.
* <p>
* The language that created and started the thread is responsible to stop and join it
* during the {@link TruffleLanguage#finalizeContext(Object) finalizeContext}, otherwise an
* {@link AssertionError} is thrown. It's not safe to use the
* {@link ExecutorService#awaitTermination(long, java.util.concurrent.TimeUnit)} to detect
* Thread termination as the polyglot thread may be cancelled before executing the executor
* worker.<br/>
* A typical implementation looks like:
* {@link TruffleLanguageSnippets.AsyncThreadLanguage#finalizeContext}
* <p>
* The {@link TruffleContext} can be either an inner context created by
* {@link #newContextBuilder()}.{@link TruffleContext.Builder#build() build()}, or the
* context associated with this environment obtained from {@link #getContext()}.
*
* @param runnable the runnable to run on this thread.
* @param context the context to enter and leave when the thread is started.
* @param group the thread group, passed on to the underlying {@link Thread}.
* @param stackSize the desired stack size for the new thread, or zero if this parameter is
* to be ignored.
* @throws IllegalStateException if thread creation is not {@link #isCreateThreadAllowed()
* allowed}.
* @see #getContext()
* @see #newContextBuilder()
* @since 0.28
*/
@TruffleBoundary
public Thread createThread(Runnable runnable, @SuppressWarnings("hiding") TruffleContext context, ThreadGroup group, long stackSize) {
try {
return LanguageAccessor.engineAccess().createThread(polyglotLanguageContext, runnable, context != null ? context.polyglotContext : null, group, stackSize);
} catch (Throwable t) {
throw engineToLanguageException(t);
}
}
Returns a new context builder useful to create inner context instances.
See Also: - for details on language inner contexts.
Since: 0.27
/**
* Returns a new context builder useful to create inner context instances.
*
* @see TruffleContext for details on language inner contexts.
* @since 0.27
*/
public TruffleContext.Builder newContextBuilder() {
return TruffleContext.EMPTY.new Builder(this);
}
Returns a TruffleObject that represents the polyglot bindings. The polyglot bindings
consists of a set of symbols that have been exported explicitly by the languages or the
embedder. This set of symbols allows for data exchange between polyglot languages. The
polyglot bindings is separate from language bindings. The symbols can by read using
string identifiers, a list of symbols may be requested with the keys message. Existing
identifiers are removable, modifiable, readable and any new identifiers are insertable.
Throws: - SecurityException – if polyglot access is not enabled
See Also: Since: 0.32
/**
* Returns a TruffleObject that represents the polyglot bindings. The polyglot bindings
* consists of a set of symbols that have been exported explicitly by the languages or the
* embedder. This set of symbols allows for data exchange between polyglot languages. The
* polyglot bindings is separate from language bindings. The symbols can by read using
* string identifiers, a list of symbols may be requested with the keys message. Existing
* identifiers are removable, modifiable, readable and any new identifiers are insertable.
*
* @throws SecurityException if polyglot access is not enabled
* @see #isPolyglotBindingsAccessAllowed()
* @since 0.32
*/
@TruffleBoundary
public Object getPolyglotBindings() {
try {
if (!isPolyglotBindingsAccessAllowed()) {
throw new SecurityException("Polyglot bindings are not accessible for this language. Use --polyglot or allowPolyglotAccess when building the context.");
}
return LanguageAccessor.engineAccess().getPolyglotBindingsForLanguage(polyglotLanguageContext);
} catch (Throwable t) {
throw engineToLanguageException(t);
}
}
Explicitly imports a symbol from the polyglot bindings. The behavior of this method is equivalent to sending a READ message to the polyglot
bindings
object. Reading a symbol that does not exist will return null
.
The returned symbol value can either be a TruffleObject
(e.g. a native object from the other language) to support interoperability between languages, String
or one of the Java primitive wrappers ( Integer
, Double
, Byte
, Boolean
, etc.).
Polyglot symbols can only be imported if the
polyglot bindings access
is allowed.
Params: - symbolName – the name of the symbol to search for
Throws: - SecurityException – if importing polyglot symbols is not allowed
Returns: object representing the symbol or null
if it does not exist Since: 0.8 or earlier
/**
* Explicitly imports a symbol from the polyglot bindings. The behavior of this method is
* equivalent to sending a READ message to the {@link #getPolyglotBindings() polyglot
* bindings} object. Reading a symbol that does not exist will return <code>null</code>.
* <p>
* The returned symbol value can either be a <code>TruffleObject</code> (e.g. a native
* object from the other language) to support interoperability between languages,
* {@link String} or one of the Java primitive wrappers ( {@link Integer}, {@link Double},
* {@link Byte}, {@link Boolean}, etc.).
* <p>
* Polyglot symbols can only be imported if the {@link #isPolyglotBindingsAccessAllowed()
* polyglot bindings access} is allowed.
*
* @param symbolName the name of the symbol to search for
* @return object representing the symbol or <code>null</code> if it does not exist
* @throws SecurityException if importing polyglot symbols is not allowed
* @since 0.8 or earlier
*/
@TruffleBoundary
public Object importSymbol(String symbolName) {
try {
if (!isPolyglotBindingsAccessAllowed()) {
throw new SecurityException("Polyglot bindings are not accessible for this language. Use --polyglot or allowPolyglotAccess when building the context.");
}
return LanguageAccessor.engineAccess().importSymbol(polyglotLanguageContext, this, symbolName);
} catch (Throwable t) {
throw engineToLanguageException(t);
}
}
Explicitly exports a symbol to the polyglot bindings object. The behavior of this method is equivalent to sending a WRITE message to the polyglot
bindings
object. Exporting a symbol with a null
value will remove the
symbol from the polyglot object.
The exported symbol value can either be a TruffleObject
(e.g. a native object from the other language) to support interoperability between languages, String
or one of the Java primitive wrappers ( Integer
, Double
, Byte
, Boolean
, etc.).
Polyglot symbols can only be export if the
polyglot bindings access
is allowed.
Params: - symbolName – the name with which the symbol should be exported into the polyglot
scope
- value – the value to export for
Throws: - SecurityException – if exporting polyglot symbols is not allowed
Since: 0.27
/**
* Explicitly exports a symbol to the polyglot bindings object. The behavior of this method
* is equivalent to sending a WRITE message to the {@link #getPolyglotBindings() polyglot
* bindings} object. Exporting a symbol with a <code>null</code> value will remove the
* symbol from the polyglot object.
* <p>
* The exported symbol value can either be a <code>TruffleObject</code> (e.g. a native
* object from the other language) to support interoperability between languages,
* {@link String} or one of the Java primitive wrappers ( {@link Integer}, {@link Double},
* {@link Byte}, {@link Boolean}, etc.).
* <p>
* Polyglot symbols can only be export if the {@link #isPolyglotBindingsAccessAllowed()
* polyglot bindings access} is allowed.
*
* @param symbolName the name with which the symbol should be exported into the polyglot
* scope
* @param value the value to export for
* @throws SecurityException if exporting polyglot symbols is not allowed
* @since 0.27
*/
@TruffleBoundary
public void exportSymbol(String symbolName, Object value) {
try {
if (!isPolyglotBindingsAccessAllowed()) {
throw new SecurityException("Polyglot bindings are not accessible for this language. Use --polyglot or allowPolyglotAccess when building the context.");
}
LanguageAccessor.engineAccess().exportSymbol(polyglotLanguageContext, symbolName, value);
} catch (Throwable t) {
throw engineToLanguageException(t);
}
}
Returns true
if host access is generally allowed. If this method returns
false
then lookupHostSymbol(String)
will always fail. Host lookup is generally disallowed if the embedder provided a null
host class filter
. Since: 0.27
/**
* Returns <code>true</code> if host access is generally allowed. If this method returns
* <code>false</code> then {@link #lookupHostSymbol(String)} will always fail. Host lookup
* is generally disallowed if the embedder provided a null
* {@link org.graalvm.polyglot.Context.Builder#allowHostClassLookup(java.util.function.Predicate)
* host class filter}.
*
* @since 0.27
*/
@TruffleBoundary
public boolean isHostLookupAllowed() {
try {
return LanguageAccessor.engineAccess().isHostAccessAllowed(polyglotLanguageContext, this);
} catch (Throwable t) {
throw engineToLanguageException(t);
}
}
Adds an entry to the Java host class loader. All classes looked up with lookupHostSymbol(String)
will lookup classes with this new entry. If the entry was already added then calling this method again for the same entry has no effect. Given entry must not be null
.
Throws: - SecurityException – if the file is not
readable
.
Since: 19.0
/**
* Adds an entry to the Java host class loader. All classes looked up with
* {@link #lookupHostSymbol(String)} will lookup classes with this new entry. If the entry
* was already added then calling this method again for the same entry has no effect. Given
* entry must not be <code>null</code>.
*
* @throws SecurityException if the file is not {@link TruffleFile#isReadable() readable}.
* @since 19.0
*/
@TruffleBoundary
public void addToHostClassPath(TruffleFile entry) {
try {
Objects.requireNonNull(entry);
LanguageAccessor.engineAccess().addToHostClassPath(polyglotLanguageContext, entry);
} catch (Throwable t) {
throw engineToLanguageException(t);
}
}
Looks up a Java class in the top-most scope the host environment. Throws an error if no symbol was found or the symbol was not accessible. Symbols might not be accessible if a
host class filter
prevents access. The returned object is always a TruffleObject
that represents the class symbol.
Params: - symbolName – the qualified class name in the host language.
Since: 0.27
/**
* Looks up a Java class in the top-most scope the host environment. Throws an error if no
* symbol was found or the symbol was not accessible. Symbols might not be accessible if a
* {@link org.graalvm.polyglot.Context.Builder#allowHostClassLookup(java.util.function.Predicate)
* host class filter} prevents access. The returned object is always a
* <code>TruffleObject</code> that represents the class symbol.
*
* @param symbolName the qualified class name in the host language.
* @since 0.27
*/
@TruffleBoundary
public Object lookupHostSymbol(String symbolName) {
try {
return LanguageAccessor.engineAccess().lookupHostSymbol(polyglotLanguageContext, this, symbolName);
} catch (Throwable t) {
throw engineToLanguageException(t);
}
}
Returns true
if the argument is Java host language object wrapped using
Truffle interop.
See Also: - asHostObject(Object)
Since: 19.0
/**
* Returns <code>true</code> if the argument is Java host language object wrapped using
* Truffle interop.
*
* @see #asHostObject(Object)
* @since 19.0
*/
@SuppressWarnings("static-method")
public boolean isHostObject(Object value) {
try {
return LanguageAccessor.engineAccess().isHostObject(value);
} catch (Throwable t) {
throw engineToLanguageException(t);
}
}
Returns the java host representation of a Truffle guest object if it represents a Java host language object. Throws ClassCastException
if the provided argument is not a host object
. Since: 19.0
/**
* Returns the java host representation of a Truffle guest object if it represents a Java
* host language object. Throws {@link ClassCastException} if the provided argument is not a
* {@link #isHostObject(Object) host object}.
*
* @since 19.0
*/
public Object asHostObject(Object value) {
if (!isHostObject(value)) {
CompilerDirectives.transferToInterpreterAndInvalidate();
throw new ClassCastException();
}
try {
return LanguageAccessor.engineAccess().asHostObject(value);
} catch (Throwable t) {
throw engineToLanguageException(t);
}
}
Converts a existing Java host object to a guest language value. If the value is already an interop value, then no conversion will be performed. Otherwise, the returned wraps the host object and provides support for the interop contract to access the java members. The interpretation of converted objects is described in Context.asValue(Object)
. This method should be used exclusively to convert already allocated Java objects to a guest language representation. To allocate new host objects users should use lookupHostSymbol(String)
to lookup the class and then send a NEW interop message to that object to instantiate it. This method does not respect configured
class filters
.
Params: - hostObject – the host object to convert
Since: 19.0
/**
* Converts a existing Java host object to a guest language value. If the value is already
* an interop value, then no conversion will be performed. Otherwise, the returned wraps the
* host object and provides support for the interop contract to access the java members. The
* interpretation of converted objects is described in {@link Context#asValue(Object)}.
* <p>
* This method should be used exclusively to convert already allocated Java objects to a
* guest language representation. To allocate new host objects users should use
* {@link #lookupHostSymbol(String)} to lookup the class and then send a NEW interop message
* to that object to instantiate it. This method does not respect configured
* {@link org.graalvm.polyglot.Context.Builder#allowHostClassLookup(java.util.function.Predicate)
* class filters}.
*
* @param hostObject the host object to convert
* @since 19.0
*/
public Object asGuestValue(Object hostObject) {
try {
return LanguageAccessor.engineAccess().toGuestValue(hostObject, polyglotLanguageContext);
} catch (Throwable t) {
throw engineToLanguageException(t);
}
}
Wraps primitive interop values in a TruffleObject exposing their methods as members. By default primitive host values are not wrapped in TruffleObjects to expose their members. This method is intended for compatibility with existing Java interop APIs that expect such behavior. This method boxes the following primitive interop values: Boolean
, Byte
, Short
, Integer
, Long
, Float
, Double
, Character
, String
. If the provided value is already boxed then the current value will be returned. If the provided value is not an interop value then an IllegalArgumentException
will be thrown. Params: - guestObject – the primitive guest value to box
Throws: - IllegalArgumentException – if value is an invalid interop value.
See Also: Since: 19.0
/**
* Wraps primitive interop values in a TruffleObject exposing their methods as members. By
* default primitive host values are not wrapped in TruffleObjects to expose their members.
* This method is intended for compatibility with existing Java interop APIs that expect
* such behavior. This method boxes the following primitive interop values: {@link Boolean},
* {@link Byte}, {@link Short}, {@link Integer}, {@link Long}, {@link Float}, {@link Double}
* , {@link Character}, {@link String}. If the provided value is already boxed then the
* current value will be returned. If the provided value is not an interop value then an
* {@link IllegalArgumentException} will be thrown.
*
* @throws IllegalArgumentException if value is an invalid interop value.
* @param guestObject the primitive guest value to box
* @see #asGuestValue(Object)
* @since 19.0
*/
public Object asBoxedGuestValue(Object guestObject) {
try {
return LanguageAccessor.engineAccess().asBoxedGuestValue(guestObject, polyglotLanguageContext);
} catch (Throwable t) {
throw engineToLanguageException(t);
}
}
Returns true
if the argument is a Java host language function wrapped using
Truffle interop.
Since: 19.0
/**
* Returns <code>true</code> if the argument is a Java host language function wrapped using
* Truffle interop.
*
* @since 19.0
*/
@SuppressWarnings("static-method")
public boolean isHostFunction(Object value) {
try {
return LanguageAccessor.engineAccess().isHostFunction(value);
} catch (Throwable t) {
throw engineToLanguageException(t);
}
}
Find a metaobject of a value, if any. The metaobject represents a description of the
object, reveals it's kind and it's features. Some information that a metaobject might
define includes the base object's type, interface, class, methods, attributes, etc.
When no metaobject is known, returns null
. The metaobject is an interop
value. An interop value can be either a TruffleObject
(e.g. a native object from the other language) to support interoperability between languages or a String
.
Params: - value – the value to find the meta object for.
Since: 19.0
/**
* Find a metaobject of a value, if any. The metaobject represents a description of the
* object, reveals it's kind and it's features. Some information that a metaobject might
* define includes the base object's type, interface, class, methods, attributes, etc.
* <p>
* When no metaobject is known, returns <code>null</code>. The metaobject is an interop
* value. An interop value can be either a <code>TruffleObject</code> (e.g. a native object
* from the other language) to support interoperability between languages or a
* {@link String}.
*
* @param value the value to find the meta object for.
* @since 19.0
*/
public Object findMetaObject(Object value) {
try {
return LanguageAccessor.engineAccess().findMetaObjectForLanguage(polyglotLanguageContext, value);
} catch (Throwable t) {
throw engineToLanguageException(t);
}
}
Tests whether an exception is a host exception thrown by a Java Interop method invocation. Host exceptions may be thrown by interoperability messages. The host exception may be unwrapped using asHostException(Throwable)
. Params: - exception – the
Throwable
to test
See Also: Returns: true
if the exception
is a host exception, false
otherwiseSince: 19.0
/**
* Tests whether an exception is a host exception thrown by a Java Interop method
* invocation.
*
* Host exceptions may be thrown by interoperability messages. The host exception may be
* unwrapped using {@link #asHostException(Throwable)}.
*
* @param exception the {@link Throwable} to test
* @return {@code true} if the {@code exception} is a host exception, {@code false}
* otherwise
* @see #asHostException(Throwable)
* @since 19.0
*/
@SuppressWarnings("static-method")
public boolean isHostException(Throwable exception) {
try {
return LanguageAccessor.engineAccess().isHostException(exception);
} catch (Throwable t) {
throw engineToLanguageException(t);
}
}
Unwraps a host exception thrown by a Java method invocation. Host exceptions may be thrown by interoperability messages. The host exception may be unwrapped using asHostException(Throwable)
. Params: - exception – the host exception to unwrap
Throws: - IllegalArgumentException – if the
exception
is not a host exception
See Also: Returns: the original Java exception Since: 19.0
/**
* Unwraps a host exception thrown by a Java method invocation.
*
* Host exceptions may be thrown by interoperability messages. The host exception may be
* unwrapped using {@link #asHostException(Throwable)}.
*
* @param exception the host exception to unwrap
* @return the original Java exception
* @throws IllegalArgumentException if the {@code exception} is not a host exception
* @see #isHostException(Throwable)
* @since 19.0
*/
@SuppressWarnings("static-method")
public Throwable asHostException(Throwable exception) {
try {
return LanguageAccessor.engineAccess().asHostException(exception);
} catch (Throwable t) {
throw engineToLanguageException(t);
}
}
Returns true
if the argument is a host symbol, representing the constructor and static members of a Java class, as obtained by e.g. lookupHostSymbol
. See Also: Since: 19.0
/**
* Returns {@code true} if the argument is a host symbol, representing the constructor and
* static members of a Java class, as obtained by e.g. {@link #lookupHostSymbol}.
*
* @see #lookupHostSymbol(String)
* @since 19.0
*/
@SuppressWarnings("static-method")
public boolean isHostSymbol(Object guestObject) {
try {
return LanguageAccessor.engineAccess().isHostSymbol(guestObject);
} catch (Throwable t) {
throw engineToLanguageException(t);
}
}
Converts a Java class to a host symbol as if by lookupHostSymbol(symbolClass.getName())
but without an actual lookup. Must not be used with Truffle or guest language classes. See Also: Since: 19.0
/**
* Converts a Java class to a host symbol as if by
* {@code lookupHostSymbol(symbolClass.getName())} but without an actual lookup. Must not be
* used with Truffle or guest language classes.
*
* @see #lookupHostSymbol(String)
* @since 19.0
*/
@TruffleBoundary
public Object asHostSymbol(Class<?> symbolClass) {
try {
return LanguageAccessor.engineAccess().asHostSymbol(polyglotLanguageContext, symbolClass);
} catch (Throwable t) {
throw engineToLanguageException(t);
}
}
Returns true
if access to native code is generally allowed. If this method
returns false
then loading native libraries with the Truffle NFI will fail.
Since: 19.0
/**
* Returns <code>true</code> if access to native code is generally allowed. If this method
* returns <code>false</code> then loading native libraries with the Truffle NFI will fail.
*
* @since 19.0
*/
@TruffleBoundary
public boolean isNativeAccessAllowed() {
try {
return LanguageAccessor.engineAccess().isNativeAccessAllowed(polyglotLanguageContext, this);
} catch (Throwable t) {
throw engineToLanguageException(t);
}
}
Since: 19.0 Deprecated: use either isPolyglotEvalAllowed()
or isPolyglotBindingsAccessAllowed()
instead
/**
* @since 19.0
* @deprecated use either {@link #isPolyglotEvalAllowed()} or
* {@link #isPolyglotBindingsAccessAllowed()} instead
*/
@Deprecated
public boolean isPolyglotAccessAllowed() {
return isPolyglotEvalAllowed() || isPolyglotBindingsAccessAllowed();
}
Returns true
if polyglot evaluation is allowed, else false
.
Guest languages should hide or disable all polyglot evaluation builtins if this flag is
set to false
. Note that if polyglot evaluation access is disabled, then the available languages list
only shows the current language, dependent languages
and internal languages
. See Also: Since: 19.2
/**
* Returns <code>true</code> if polyglot evaluation is allowed, else <code>false</code>.
* Guest languages should hide or disable all polyglot evaluation builtins if this flag is
* set to <code>false</code>. Note that if polyglot evaluation access is disabled, then the
* {@link #getInternalLanguages() available languages list} only shows the current language,
* {@link Registration#dependentLanguages() dependent languages} and
* {@link Registration#internal() internal languages}.
*
* @see org.graalvm.polyglot.Context.Builder#allowPolyglotAccess(org.graalvm.polyglot.PolyglotAccess)
* @since 19.2
*/
@TruffleBoundary
public boolean isPolyglotEvalAllowed() {
try {
return LanguageAccessor.engineAccess().isPolyglotEvalAllowed(polyglotLanguageContext);
} catch (Throwable t) {
throw engineToLanguageException(t);
}
}
Returns true
if polyglot bindings access is allowed, else false
. Guest languages should hide or disable all polyglot bindings builtins if this flag is
set to false
. If polyglot bindings access is disabled then getPolyglotBindings()
, importSymbol(String)
or exportSymbol(String, Object)
fails with a SecurityException. See Also: Since: 19.2
/**
* Returns <code>true</code> if polyglot bindings access is allowed, else <code>false</code>
* . Guest languages should hide or disable all polyglot bindings builtins if this flag is
* set to <code>false</code>. If polyglot bindings access is disabled then
* {@link #getPolyglotBindings()}, {@link #importSymbol(String)} or
* {@link #exportSymbol(String, Object)} fails with a SecurityException.
*
* @see org.graalvm.polyglot.Context.Builder#allowPolyglotAccess(org.graalvm.polyglot.PolyglotAccess)
* @since 19.2
*/
@TruffleBoundary
public boolean isPolyglotBindingsAccessAllowed() {
try {
return LanguageAccessor.engineAccess().isPolyglotBindingsAccessAllowed(polyglotLanguageContext);
} catch (Throwable t) {
throw engineToLanguageException(t);
}
}
Allows it to be determined if this Context
can execute code written in a language with a given MIME type. See Also: Returns: a boolean that indicates if the MIME type is supported Since: 0.11
/**
* Allows it to be determined if this {@link org.graalvm.polyglot.Context} can execute code
* written in a language with a given MIME type.
*
* @see Source#getMimeType()
* @see #parsePublic(Source, String...)
*
* @return a boolean that indicates if the MIME type is supported
* @since 0.11
*/
@TruffleBoundary
public boolean isMimeTypeSupported(String mimeType) {
checkDisposed();
try {
return LanguageAccessor.engineAccess().isMimeTypeSupported(polyglotLanguageContext, mimeType);
} catch (Throwable t) {
throw engineToLanguageException(t);
}
}
Throws: - IllegalStateException – if polyglot context associated with this environment is not
entered
Since: 0.8 or earlier Deprecated: use parseInternal(Source, String...)
or parsePublic(Source, String...)
instead.
/**
* @throws IllegalStateException if polyglot context associated with this environment is not
* entered
* @since 0.8 or earlier
* @deprecated use {@link #parseInternal(Source, String...)} or
* {@link #parsePublic(Source, String...)} instead.
*/
@TruffleBoundary
@Deprecated
public CallTarget parse(Source source, String... argumentNames) {
CompilerAsserts.neverPartOfCompilation();
checkDisposed();
try {
return LanguageAccessor.engineAccess().parseForLanguage(polyglotLanguageContext, source, argumentNames, true);
} catch (Throwable t) {
throw engineToLanguageException(t);
}
}
Parses the source of a public or internal language and returns the parse result as CallTarget
. The language id
is used to identify the TruffleLanguage
to use to perform the TruffleLanguage.parse(ParsingRequest)
. The names of arguments are parameters for the resulting {#link CallTarget} that allow the source
to reference the actual parameters passed to CallTarget.call(Object...)
. Compared to parsePublic(Source, String...)
this method provides also access to internal
and dependent languages in addition to public languages. For example, in JavaScript, a call to the eval builtin should forward to parsePublic(Source, String...)
as it contains code provided by the guest language user. Parsing regular expressions with the internal regular expression engine should call parseInternal(Source, String...)
instead, as this is considered an implementation detail of the language.
It is recommended that the language uses parsePublic(Source, String...)
or parseInternal(Source, String...)
instead of directly passing the Source to the parser, in order to support code caching with ContextPolicy.SHARED
and ContextPolicy.REUSE
.
Params: - source – the source to evaluate
- argumentNames – the names of
CallTarget.call(Object...)
arguments that can be referenced from the source
Throws: - IllegalStateException – if polyglot context associated with this environment is not
entered
See Also: Returns: the call target representing the parsed result Since: 19.2
/**
* Parses the source of a public or internal language and returns the parse result as
* {@link CallTarget}. The {@link Source#getLanguage() language id} is used to identify the
* {@link TruffleLanguage} to use to perform the
* {@link #parse(com.oracle.truffle.api.TruffleLanguage.ParsingRequest)}. The names of
* arguments are parameters for the resulting {#link CallTarget} that allow the
* <code>source</code> to reference the actual parameters passed to
* {@link CallTarget#call(java.lang.Object...)}.
* <p>
* Compared to {@link #parsePublic(Source, String...)} this method provides also access to
* {@link TruffleLanguage.Registration#internal() internal} and dependent languages in
* addition to public languages. For example, in JavaScript, a call to the eval builtin
* should forward to {@link #parsePublic(Source, String...)} as it contains code provided by
* the guest language user. Parsing regular expressions with the internal regular expression
* engine should call {@link #parseInternal(Source, String...)} instead, as this is
* considered an implementation detail of the language.
* <p>
* It is recommended that the language uses {@link Env#parsePublic(Source, String...)} or
* {@link Env#parseInternal(Source, String...)} instead of directly passing the Source to
* the parser, in order to support code caching with {@link ContextPolicy#SHARED} and
* {@link ContextPolicy#REUSE}.
*
* @param source the source to evaluate
* @param argumentNames the names of {@link CallTarget#call(java.lang.Object...)} arguments
* that can be referenced from the source
* @return the call target representing the parsed result
* @throws IllegalStateException if polyglot context associated with this environment is not
* entered
* @see #parsePublic(Source, String...)
* @since 19.2
*/
@TruffleBoundary
public CallTarget parseInternal(Source source, String... argumentNames) {
CompilerAsserts.neverPartOfCompilation();
checkDisposed();
try {
return LanguageAccessor.engineAccess().parseForLanguage(polyglotLanguageContext, source, argumentNames, true);
} catch (Throwable t) {
throw engineToLanguageException(t);
}
}
Parses the source of a public language and returns the parse result as CallTarget
. The language id
is used to identify the TruffleLanguage
to use to perform the TruffleLanguage.parse(ParsingRequest)
. The names of arguments are parameters for the resulting {#link CallTarget} that allow the source
to reference the actual parameters passed to CallTarget.call(Object...)
. Compared to parseInternal(Source, String...)
this method does only provide access to non internal, non dependent, public languages. Public languages are configured by the embedder to be accessible to the guest language program. For example, in JavaScript, a call to the eval builtin should forward to parsePublic(Source, String...)
as it contains code provided by the guest language user. Parsing regular expressions with the internal regular expression engine should call parseInternal(Source, String...)
instead, as this is considered an implementation detail of the language.
It is recommended that the language uses parsePublic(Source, String...)
or parseInternal(Source, String...)
instead of directly passing the Source to the parser, in order to support code caching with ContextPolicy.SHARED
and ContextPolicy.REUSE
.
Params: - source – the source to evaluate
- argumentNames – the names of
CallTarget.call(Object...)
arguments that can be referenced from the source
Throws: - IllegalStateException – if polyglot context associated with this environment is not
entered
See Also: Returns: the call target representing the parsed result Since: 19.2
/**
* Parses the source of a public language and returns the parse result as {@link CallTarget}
* . The {@link Source#getLanguage() language id} is used to identify the
* {@link TruffleLanguage} to use to perform the
* {@link #parse(com.oracle.truffle.api.TruffleLanguage.ParsingRequest)}. The names of
* arguments are parameters for the resulting {#link CallTarget} that allow the
* <code>source</code> to reference the actual parameters passed to
* {@link CallTarget#call(java.lang.Object...)}.
* <p>
* Compared to {@link #parseInternal(Source, String...)} this method does only provide
* access to non internal, non dependent, public languages. Public languages are configured
* by the embedder to be accessible to the guest language program. For example, in
* JavaScript, a call to the eval builtin should forward to
* {@link #parsePublic(Source, String...)} as it contains code provided by the guest
* language user. Parsing regular expressions with the internal regular expression engine
* should call {@link #parseInternal(Source, String...)} instead, as this is considered an
* implementation detail of the language.
* <p>
* It is recommended that the language uses {@link Env#parsePublic(Source, String...)} or
* {@link Env#parseInternal(Source, String...)} instead of directly passing the Source to
* the parser, in order to support code caching with {@link ContextPolicy#SHARED} and
* {@link ContextPolicy#REUSE}.
*
* @param source the source to evaluate
* @param argumentNames the names of {@link CallTarget#call(java.lang.Object...)} arguments
* that can be referenced from the source
* @return the call target representing the parsed result
* @throws IllegalStateException if polyglot context associated with this environment is not
* entered
* @see #parseInternal(Source, String...)
* @since 19.2
*/
@TruffleBoundary
public CallTarget parsePublic(Source source, String... argumentNames) {
CompilerAsserts.neverPartOfCompilation();
checkDisposed();
try {
return LanguageAccessor.engineAccess().parseForLanguage(polyglotLanguageContext, source, argumentNames, false);
} catch (Throwable t) {
throw engineToLanguageException(t);
}
}
Input stream provided by Builder.in(InputStream)
this language is being executed in. Returns: reader, never null
Since: 0.8 or earlier
/**
* Input stream provided by {@link org.graalvm.polyglot.Context.Builder#in(InputStream)}
* this language is being executed in.
*
* @return reader, never <code>null</code>
* @since 0.8 or earlier
*/
@TruffleBoundary
public InputStream in() {
checkDisposed();
return in;
}
Standard output writer provided by Builder.out(OutputStream)
this language is being executed in. Returns: writer, never null
Since: 0.8 or earlier
/**
* Standard output writer provided by
* {@link org.graalvm.polyglot.Context.Builder#out(OutputStream)} this language is being
* executed in.
*
* @return writer, never <code>null</code>
* @since 0.8 or earlier
*/
@TruffleBoundary
public OutputStream out() {
checkDisposed();
return out;
}
Standard error writer provided by Builder.err(OutputStream)
this language is being executed in. Returns: writer, never null
Since: 0.8 or earlier
/**
* Standard error writer provided by
* {@link org.graalvm.polyglot.Context.Builder#err(OutputStream)} this language is being
* executed in.
*
* @return writer, never <code>null</code>
* @since 0.8 or earlier
*/
@TruffleBoundary
public OutputStream err() {
checkDisposed();
return err;
}
Looks additional service up. An environment for a particular
language
may also be associated with additional services. One can request implementations of such services by calling this method with the type identifying the requested service and its API. Services that can be obtained via this method include Instrumenter
and others. Params: - type – class of requested service
Type parameters: - <T> – type of requested service
Returns: instance of T or null
if there is no such service available Since: 0.12
/**
* Looks additional service up. An environment for a particular {@link TruffleLanguage
* language} may also be associated with additional services. One can request
* implementations of such services by calling this method with the type identifying the
* requested service and its API.
*
* Services that can be obtained via this method include
* {@link com.oracle.truffle.api.instrumentation.Instrumenter} and others.
*
* @param <T> type of requested service
* @param type class of requested service
* @return instance of T or <code>null</code> if there is no such service available
* @since 0.12
*/
@TruffleBoundary
public <T> T lookup(Class<T> type) {
checkDisposed();
for (Object obj : services) {
if (type.isInstance(obj)) {
return type.cast(obj);
}
}
return null;
}
Returns an additional service provided by this instrument, specified by type. If an
instrument is not enabled, it will be enabled automatically by requesting a supported
service. If the instrument does not provide a service for a given type it will not be
enabled automatically.
Params: - instrument – identification of the instrument to query
- type – the class of the requested type
Type parameters: - <S> – the requested type
Returns: the registered service or null
if none is found Since: 0.26
/**
* Returns an additional service provided by this instrument, specified by type. If an
* instrument is not enabled, it will be enabled automatically by requesting a supported
* service. If the instrument does not provide a service for a given type it will not be
* enabled automatically.
*
* @param <S> the requested type
* @param instrument identification of the instrument to query
* @param type the class of the requested type
* @return the registered service or <code>null</code> if none is found
* @since 0.26
*/
@SuppressWarnings("static-method")
@TruffleBoundary
public <S> S lookup(InstrumentInfo instrument, Class<S> type) {
if (isPreInitialization()) {
throw new IllegalStateException("Instrument lookup is not allowed during context pre-initialization.");
}
try {
return LanguageAccessor.engineAccess().lookup(instrument, type);
} catch (Throwable t) {
throw engineToLanguageException(t);
}
}
Returns an additional service provided by the given language, specified by type. For services registered by Registration.services()
the service lookup will ensure that the language is loaded and services are registered. The provided langauge and type must not be null
.
Params: - language – the language to query
- type – the class of the requested type
Type parameters: - <S> – the requested type
Returns: the registered service or null
if none is found Since: 0.26 Since: 19.0 supports services registered by
registerService
/**
* Returns an additional service provided by the given language, specified by type. For
* services registered by {@link Registration#services()} the service lookup will ensure
* that the language is loaded and services are registered. The provided langauge and type
* must not be <code>null</code>.
*
* @param <S> the requested type
* @param language the language to query
* @param type the class of the requested type
* @return the registered service or <code>null</code> if none is found
* @since 0.26
* @since 19.0 supports services registered by {@link Env#registerService(java.lang.Object)
* registerService}
*/
@TruffleBoundary
public <S> S lookup(LanguageInfo language, Class<S> type) {
if (this.getSpi().languageInfo == language) {
throw new IllegalArgumentException("Cannot request services from the current language.");
}
try {
Objects.requireNonNull(language);
return LanguageAccessor.engineAccess().lookupService(polyglotLanguageContext, language, this.getSpi().languageInfo, type);
} catch (Throwable t) {
throw engineToLanguageException(t);
}
}
Ensures that the target language is initialized. This method firstly verifies that the target language is accessible from this language. If not the SecurityException
is thrown. Then the target language initialization is performed if not already done. Params: - targetLanguage – the language to initialize
Throws: - SecurityException – if an access to
targetLanguage
is not permitted
Since: 20.1.0
/**
* Ensures that the target language is initialized. This method firstly verifies that the
* target language is accessible from this language. If not the {@link SecurityException} is
* thrown. Then the target language initialization is performed if not already done.
*
* @param targetLanguage the language to initialize
* @throws SecurityException if an access to {@code targetLanguage} is not permitted
* @since 20.1.0
*/
@TruffleBoundary
public boolean initializeLanguage(LanguageInfo targetLanguage) {
Objects.requireNonNull(targetLanguage, "TargetLanguage must be non null.");
try {
return LanguageAccessor.engineAccess().initializeLanguage(polyglotLanguageContext, targetLanguage);
} catch (Throwable t) {
throw engineToLanguageException(t);
}
}
Since: 0.26 Deprecated:
/**
* @since 0.26
* @deprecated
*/
@Deprecated
@TruffleBoundary
public Map<String, LanguageInfo> getLanguages() {
try {
return LanguageAccessor.engineAccess().getInternalLanguages(polyglotLanguageContext);
} catch (Throwable t) {
throw engineToLanguageException(t);
}
}
Returns all languages that are installed and internally accessible in the environment. Using the language instance additional services can be looked up
. parseInternal(Source, String...)
is allowed for all languages returned by this method. This list of languages should not be exposed to guest language programs, as it lists internal languages. See Also: Since: 19.2
/**
* Returns all languages that are installed and internally accessible in the environment.
* Using the language instance additional services can be
* {@link #lookup(LanguageInfo, Class) looked up}. {@link #parseInternal(Source, String...)}
* is allowed for all languages returned by this method. This list of languages should not
* be exposed to guest language programs, as it lists internal languages.
*
* @see #lookup(LanguageInfo, Class)
* @see #parseInternal(Source, String...)
* @since 19.2
*/
@TruffleBoundary
public Map<String, LanguageInfo> getInternalLanguages() {
try {
return LanguageAccessor.engineAccess().getInternalLanguages(polyglotLanguageContext);
} catch (Throwable t) {
throw engineToLanguageException(t);
}
}
Returns all languages that are installed and publicly accessible in the environment. Using the language instance additional services can be looked up
. parsePublic(Source, String...)
is allowed for all languages returned by this method. This list of languages may be exposed ot the guest language program. See Also: Since: 19.2
/**
* Returns all languages that are installed and publicly accessible in the environment.
* Using the language instance additional services can be
* {@link #lookup(LanguageInfo, Class) looked up}. {@link #parsePublic(Source, String...)}
* is allowed for all languages returned by this method. This list of languages may be
* exposed ot the guest language program.
*
* @see #parsePublic(Source, String...)
* @since 19.2
*/
@TruffleBoundary
public Map<String, LanguageInfo> getPublicLanguages() {
try {
return LanguageAccessor.engineAccess().getPublicLanguages(polyglotLanguageContext);
} catch (Throwable t) {
throw engineToLanguageException(t);
}
}
Returns a map instrument-id to instrument instance of all instruments that are installed in the environment. Using the instrument instance additional services can be looked up
. Since: 0.26
/**
* Returns a map instrument-id to instrument instance of all instruments that are installed
* in the environment. Using the instrument instance additional services can be
* {@link #lookup(InstrumentInfo, Class) looked up} .
*
* @since 0.26
*/
@TruffleBoundary
public Map<String, InstrumentInfo> getInstruments() {
try {
return LanguageAccessor.engineAccess().getInstruments(polyglotLanguageContext);
} catch (Throwable t) {
throw engineToLanguageException(t);
}
}
Returns the default time zone of this environment. If the time-zone was not explicitly set by the embedder then the system default
time-zone will be returned. See Also: Since: 19.2
/**
* Returns the default time zone of this environment. If the time-zone was not explicitly
* set by the embedder then the {@link ZoneId#systemDefault() system default} time-zone will
* be returned.
*
* @see ZoneId#systemDefault()
* @since 19.2
*/
public ZoneId getTimeZone() {
checkDisposed();
try {
return LanguageAccessor.engineAccess().getTimeZone(polyglotLanguageContext);
} catch (Throwable t) {
throw engineToLanguageException(t);
}
}
Configuration arguments passed from an outer language context to an inner language context. Inner language contexts can be created using newContextBuilder()
. See Also: Since: 0.11
/**
* Configuration arguments passed from an outer language context to an inner language
* context. Inner language contexts can be created using {@link #newContextBuilder()}.
*
* @see TruffleContext to create inner contexts.
* @see TruffleContext.Builder#config(String, Object) to pass configuration objects to the
* inner context.
* @since 0.11
*/
@TruffleBoundary
public Map<String, Object> getConfig() {
checkDisposed();
return config;
}
Returns the polyglot context associated with this environment.
Returns: the polyglot context Since: 0.30
/**
* Returns the polyglot context associated with this environment.
*
* @return the polyglot context
* @since 0.30
*/
public TruffleContext getContext() {
try {
return LanguageAccessor.engineAccess().getTruffleContext(polyglotLanguageContext);
} catch (Throwable t) {
throw engineToLanguageException(t);
}
}
Returns true
if this Context
is being pre-initialized. For a given environment
, the return value of this method never changes. See Also: - initializeContext(Object)
- patchContext(Object, Env)
Since: 19.0
/**
* Returns <code>true</code> if this {@link org.graalvm.polyglot.Context} is being
* pre-initialized. For a given {@link Env environment}, the return value of this method
* never changes.
*
* @see #initializeContext(Object)
* @see #patchContext(Object, Env)
* @since 19.0
*/
@TruffleBoundary
public boolean isPreInitialization() {
try {
return LanguageAccessor.engineAccess().inContextPreInitialization(polyglotLanguageContext);
} catch (Throwable t) {
throw engineToLanguageException(t);
}
}
Returns a TruffleFile
for given path. Params: - path – the absolute or relative path to create
TruffleFile
for
Returns: TruffleFile
Since: 19.0 Deprecated: use getInternalTruffleFile
for language standard library files or getPublicTruffleFile
for user files.
/**
* Returns a {@link TruffleFile} for given path.
*
* @param path the absolute or relative path to create {@link TruffleFile} for
* @return {@link TruffleFile}
* @since 19.0
* @deprecated use {@link #getInternalTruffleFile(java.lang.String) getInternalTruffleFile}
* for language standard library files or
* {@link #getPublicTruffleFile(java.lang.String) getPublicTruffleFile} for user
* files.
*/
@TruffleBoundary
@Deprecated
public TruffleFile getTruffleFile(String path) {
return getInternalTruffleFile(path);
}
Returns a TruffleFile
for given URI
. Params: - uri – the
URI
to create TruffleFile
for
Returns: TruffleFile
Since: 19.0 Deprecated: use getInternalTruffleFile
for language standard library files or getPublicTruffleFile
for user files.
/**
* Returns a {@link TruffleFile} for given {@link URI}.
*
* @param uri the {@link URI} to create {@link TruffleFile} for
* @return {@link TruffleFile}
* @since 19.0
* @deprecated use {@link #getInternalTruffleFile(java.lang.String) getInternalTruffleFile}
* for language standard library files or
* {@link #getPublicTruffleFile(java.lang.String) getPublicTruffleFile} for user
* files.
*/
@TruffleBoundary
@Deprecated
public TruffleFile getTruffleFile(URI uri) {
return getInternalTruffleFile(uri);
}
Returns a public TruffleFile
for given path. The access to public files depends on Context's IO policy
. When IO is not enabled by the Context
the TruffleFile
operations throw SecurityException
. The getPublicTruffleFile
method should be used to access user files or to implement language IO builtins. Params: - path – the absolute or relative path to create
TruffleFile
for
Returns: TruffleFile
Since: 19.3.0
/**
* Returns a public {@link TruffleFile} for given path. The access to public files depends
* on {@link Builder#allowIO(boolean) Context's IO policy}. When IO is not enabled by the
* {@code Context} the {@link TruffleFile} operations throw {@link SecurityException}. The
* {@code getPublicTruffleFile} method should be used to access user files or to implement
* language IO builtins.
*
* @param path the absolute or relative path to create {@link TruffleFile} for
* @return {@link TruffleFile}
* @since 19.3.0
*/
@TruffleBoundary
public TruffleFile getPublicTruffleFile(String path) {
checkDisposed();
FileSystemContext fs = getPublicFileSystemContext();
try {
return new TruffleFile(fs, fs.fileSystem.parsePath(path));
} catch (UnsupportedOperationException e) {
throw e;
} catch (Throwable t) {
throw TruffleFile.wrapHostException(t, fs.fileSystem);
}
}
Returns a public TruffleFile
for given URI
. The access to public files depends on Context's IO policy
. When IO is not enabled by the Context
the TruffleFile
operations throw SecurityException
. The getPublicTruffleFile
method should be used to access user files or to implement language IO builtins. Params: - uri – the
URI
to create TruffleFile
for
Returns: TruffleFile
Since: 19.3.0
/**
* Returns a public {@link TruffleFile} for given {@link URI}. The access to public files
* depends on {@link Builder#allowIO(boolean) Context's IO policy}. When IO is not enabled
* by the {@code Context} the {@link TruffleFile} operations throw {@link SecurityException}
* . The {@code getPublicTruffleFile} method should be used to access user files or to
* implement language IO builtins.
*
* @param uri the {@link URI} to create {@link TruffleFile} for
* @return {@link TruffleFile}
* @since 19.3.0
*/
@TruffleBoundary
public TruffleFile getPublicTruffleFile(URI uri) {
checkDisposed();
FileSystemContext fs = getPublicFileSystemContext();
try {
return new TruffleFile(fs, fs.fileSystem.parsePath(uri));
} catch (UnsupportedOperationException e) {
throw new FileSystemNotFoundException("FileSystem for: " + uri.getScheme() + " scheme is not supported.");
} catch (Throwable t) {
throw TruffleFile.wrapHostException(t, fs.fileSystem);
}
}
Returns a public or internal TruffleFile
for given path. Unlike getPublicTruffleFile
the TruffleFile
returned by this method for a file in a language home is readable even when IO is not enabled by the Context
. The getInternalTruffleFile
method should be used to read language standard libraries in a language home. For security reasons the language should check that the file is a language source file in language standard libraries folder before using this method for a file in a language home. Params: - path – the absolute or relative path to create
TruffleFile
for
See Also: Returns: TruffleFile
Since: 19.3.0
/**
* Returns a public or internal {@link TruffleFile} for given path. Unlike
* {@link #getPublicTruffleFile(java.lang.String) getPublicTruffleFile} the
* {@link TruffleFile} returned by this method for a file in a language home is readable
* even when IO is not enabled by the {@code Context}. The {@code getInternalTruffleFile}
* method should be used to read language standard libraries in a language home. For
* security reasons the language should check that the file is a language source file in
* language standard libraries folder before using this method for a file in a language
* home.
*
* @param path the absolute or relative path to create {@link TruffleFile} for
* @return {@link TruffleFile}
* @since 19.3.0
* @see #getPublicTruffleFile(java.lang.String)
*/
@TruffleBoundary
public TruffleFile getInternalTruffleFile(String path) {
checkDisposed();
FileSystemContext fs = getInternalFileSystemContext();
try {
return new TruffleFile(fs, fs.fileSystem.parsePath(path));
} catch (UnsupportedOperationException e) {
throw e;
} catch (Throwable t) {
throw TruffleFile.wrapHostException(t, fs.fileSystem);
}
}
Returns a public or internal TruffleFile
for given URI
. Unlike getPublicTruffleFile
the TruffleFile
returned by this method for a file in a language home is readable even when IO is not enabled by the Context
. The getInternalTruffleFile
method should be used to read language standard libraries in a language home. For security reasons the language should check that the file is a language source file in language standard libraries folder before using this method for a file in a language home. Params: - uri – the
URI
to create TruffleFile
for
See Also: Returns: TruffleFile
Since: 19.3.0
/**
* Returns a public or internal {@link TruffleFile} for given {@link URI}. Unlike
* {@link #getPublicTruffleFile(java.lang.String) getPublicTruffleFile} the
* {@link TruffleFile} returned by this method for a file in a language home is readable
* even when IO is not enabled by the {@code Context}. The {@code getInternalTruffleFile}
* method should be used to read language standard libraries in a language home. For
* security reasons the language should check that the file is a language source file in
* language standard libraries folder before using this method for a file in a language
* home.
*
* @param uri the {@link URI} to create {@link TruffleFile} for
* @return {@link TruffleFile}
* @since 19.3.0
* @see #getPublicTruffleFile(java.net.URI)
*/
@TruffleBoundary
public TruffleFile getInternalTruffleFile(URI uri) {
checkDisposed();
FileSystemContext fs = getInternalFileSystemContext();
try {
return new TruffleFile(fs, fs.fileSystem.parsePath(uri));
} catch (UnsupportedOperationException e) {
throw new FileSystemNotFoundException("FileSystem for: " + uri.getScheme() + " scheme is not supported.");
} catch (Throwable t) {
throw TruffleFile.wrapHostException(t, fs.fileSystem);
}
}
Gets the current working directory. The current working directory is used to resolve non absolute paths in TruffleFile
methods. Throws: - SecurityException – if the
filesystem
denies reading of the current working directory
Returns: the current working directory Since: 19.0
/**
* Gets the current working directory. The current working directory is used to resolve non
* absolute paths in {@link TruffleFile} methods.
*
* @return the current working directory
* @throws SecurityException if the {@link FileSystem filesystem} denies reading of the
* current working directory
* @since 19.0
*/
@TruffleBoundary
public TruffleFile getCurrentWorkingDirectory() {
return getPublicTruffleFile("").getAbsoluteFile();
}
Sets the current working directory. The current working directory is used to resolve non absolute paths in TruffleFile
methods. Params: - currentWorkingDirectory – the new current working directory
Throws: - UnsupportedOperationException – if setting of the current working directory is not
supported
- IllegalArgumentException – if the
currentWorkingDirectory
is not a valid current working directory - SecurityException – if
currentWorkingDirectory
is not readable
Since: 19.0
/**
* Sets the current working directory. The current working directory is used to resolve non
* absolute paths in {@link TruffleFile} methods.
*
* @param currentWorkingDirectory the new current working directory
* @throws UnsupportedOperationException if setting of the current working directory is not
* supported
* @throws IllegalArgumentException if the {@code currentWorkingDirectory} is not a valid
* current working directory
* @throws SecurityException if {@code currentWorkingDirectory} is not readable
* @since 19.0
*/
@TruffleBoundary
public void setCurrentWorkingDirectory(TruffleFile currentWorkingDirectory) {
checkDisposed();
Objects.requireNonNull(currentWorkingDirectory, "Current working directory must be non null.");
if (!currentWorkingDirectory.isAbsolute()) {
throw new IllegalArgumentException("Current working directory must be absolute.");
}
if (!currentWorkingDirectory.isDirectory()) {
throw new IllegalArgumentException("Current working directory must be directory.");
}
FileSystemContext fileSystemContext = getPublicFileSystemContext();
FileSystemContext internalFileSystemContext = getInternalFileSystemContext();
try {
fileSystemContext.fileSystem.setCurrentWorkingDirectory(currentWorkingDirectory.getSPIPath());
if (fileSystemContext.fileSystem != internalFileSystemContext.fileSystem) {
internalFileSystemContext.fileSystem.setCurrentWorkingDirectory(currentWorkingDirectory.getSPIPath());
}
} catch (UnsupportedOperationException | IllegalArgumentException | SecurityException e) {
throw e;
} catch (Throwable t) {
throw TruffleFile.wrapHostException(t, fileSystemContext.fileSystem);
}
}
Returns the name separator used to separate names in TruffleFile
's path string. Returns: the name separator Since: 19.0
/**
* Returns the name separator used to separate names in {@link TruffleFile}'s path string.
*
* @return the name separator
* @since 19.0
*/
@TruffleBoundary
public String getFileNameSeparator() {
checkDisposed();
FileSystemContext fs = getPublicFileSystemContext();
try {
return fs.fileSystem.getSeparator();
} catch (Throwable t) {
throw TruffleFile.wrapHostException(t, fs.fileSystem);
}
}
Returns the path separator used to separate filenames in a path list. On UNIX the path separator is ':'
. On Windows it's ';'
. Returns: the path separator Since: 19.1.0
/**
* Returns the path separator used to separate filenames in a path list. On UNIX the path
* separator is {@code ':'}. On Windows it's {@code ';'}.
*
* @return the path separator
* @since 19.1.0
*/
@TruffleBoundary
public String getPathSeparator() {
checkDisposed();
FileSystemContext fs = getPublicFileSystemContext();
try {
return fs.fileSystem.getPathSeparator();
} catch (Throwable t) {
throw TruffleFile.wrapHostException(t, fs.fileSystem);
}
}
Registers additional services provided by the language. The registered services are made available to users via lookup(LanguageInfo, Class<Object>)
query method. For each service interface enumerated in language
registration
the language has to register a single service implementation.
This method can be called only during the execution of the createContext method
, then the services are collected and cannot be changed anymore.
Params: - service – a service to be returned from associated
lookup method
Throws: - IllegalStateException – if the method is called outside of
TruffleLanguage.createContext(Env)
method
Since: 19.0
/**
* Registers additional services provided by the language. The registered services are made
* available to users via
* {@link #lookup(com.oracle.truffle.api.nodes.LanguageInfo, java.lang.Class)} query method.
* <p>
* For each service interface enumerated in {@link Registration#services() language
* registration} the language has to register a single service implementation.
* <p>
* This method can be called only during the execution of the
* {@link #createContext(com.oracle.truffle.api.TruffleLanguage.Env) createContext method},
* then the services are collected and cannot be changed anymore.
*
* @param service a service to be returned from associated
* {@link Env#lookup(com.oracle.truffle.api.nodes.LanguageInfo, java.lang.Class)
* lookup method}
* @throws IllegalStateException if the method is called outside of
* {@link #createContext(com.oracle.truffle.api.TruffleLanguage.Env)} method
* @since 19.0
*/
public void registerService(Object service) {
if (languageServicesCollector == null) {
throw new IllegalStateException("The registerService method can only be called during the execution of the Env.createContext method.");
}
languageServicesCollector.add(service);
}
Returns true
if the creation of a sub-process is allowed in the current environment. See Also: Since: 19.1.0
/**
* Returns {@code true} if the creation of a sub-process is allowed in the current
* environment.
*
* @see #newProcessBuilder(java.lang.String...)
* @since 19.1.0
*/
public boolean isCreateProcessAllowed() {
try {
return LanguageAccessor.engineAccess().isCreateProcessAllowed(polyglotLanguageContext);
} catch (Throwable t) {
throw engineToLanguageException(t);
}
}
Creates a new process builder with the specified operating program and arguments.
Params: - command – the executable and its arguments
Throws: - SecurityException – when process creation is not allowed
Since: 19.1.0
/**
* Creates a new process builder with the specified operating program and arguments.
*
* @param command the executable and its arguments
* @throws SecurityException when process creation is not allowed
* @since 19.1.0
*/
@TruffleBoundary
public TruffleProcessBuilder newProcessBuilder(String... command) {
if (!isCreateProcessAllowed()) {
throw new SecurityException("Process creation is not allowed, to enable it set Context.Builder.allowCreateProcess(true).");
}
FileSystemContext fs = getPublicFileSystemContext();
List<String> cmd = new ArrayList<>(command.length);
Collections.addAll(cmd, command);
return LanguageAccessor.ioAccess().createProcessBuilder(polyglotLanguageContext, fs.fileSystem, cmd);
}
Returns an unmodifiable map of the process environment. When the Context
is configured with EnvironmentAccess.INHERIT
it returns the System.getenv()
and the environment variables configured on the Context
. For the EnvironmentAccess.NONE
only the environment variables configured on the Context
are returned. Returns: the process environment as a map of variable names to values Since: 19.1.0
/**
* Returns an unmodifiable map of the process environment. When the {@code Context} is
* configured with {@link EnvironmentAccess#INHERIT} it returns the {@link System#getenv()}
* and the environment variables configured on the {@code Context}. For the
* {@link EnvironmentAccess#NONE} only the environment variables configured on the
* {@code Context} are returned.
*
* @return the process environment as a map of variable names to values
* @since 19.1.0
*/
@TruffleBoundary
public Map<String, String> getEnvironment() {
try {
return LanguageAccessor.engineAccess().getProcessEnvironment(polyglotLanguageContext);
} catch (Throwable t) {
throw engineToLanguageException(t);
}
}
Creates a new empty file in the specified or default temporary directory, using the given
prefix and suffix to generate its name.
This method provides only part of a temporary file facility. To arrange for a file created by this method to be deleted automatically the resulting file must be opened using the DELETE_ON_CLOSE
option. In this case the file is deleted when the appropriate close
method is invoked. Alternatively, a shutdown hook
may be used to delete the file automatically.
Params: - dir – the directory in which the file should be created or
null
for a default temporary directory - prefix – the prefix to generate the file's name or
null
- suffix – the suffix to generate the file's name or
null
in which case ".tmp
" is used - attrs – the optional attributes to set atomically when creating the file
Throws: - IOException – in case of IO error
- IllegalArgumentException – if the prefix or suffix cannot be used to generate a
valid file name
- UnsupportedOperationException – if the attributes contain an attribute which cannot be set atomically or
FileSystem
does not support default temporary directory - SecurityException – if the
FileSystem
denied the operation
Returns: the TruffleFile
representing the newly created file that did not exist before this method was invoked Since: 19.3.0
/**
* Creates a new empty file in the specified or default temporary directory, using the given
* prefix and suffix to generate its name.
* <p>
* This method provides only part of a temporary file facility. To arrange for a file
* created by this method to be deleted automatically the resulting file must be opened
* using the {@link StandardOpenOption#DELETE_ON_CLOSE DELETE_ON_CLOSE} option. In this case
* the file is deleted when the appropriate {@code close} method is invoked. Alternatively,
* a {@link Runtime#addShutdownHook shutdown hook} may be used to delete the file
* automatically.
*
* @param dir the directory in which the file should be created or {@code null} for a
* default temporary directory
* @param prefix the prefix to generate the file's name or {@code null}
* @param suffix the suffix to generate the file's name or {@code null} in which case
* "{@code .tmp}" is used
* @param attrs the optional attributes to set atomically when creating the file
* @return the {@link TruffleFile} representing the newly created file that did not exist
* before this method was invoked
* @throws IOException in case of IO error
* @throws IllegalArgumentException if the prefix or suffix cannot be used to generate a
* valid file name
* @throws UnsupportedOperationException if the attributes contain an attribute which cannot
* be set atomically or {@link FileSystem} does not support default temporary
* directory
* @throws SecurityException if the {@link FileSystem} denied the operation
* @since 19.3.0
*/
@TruffleBoundary
public TruffleFile createTempFile(TruffleFile dir, String prefix, String suffix, FileAttribute<?>... attrs) throws IOException {
FileSystemContext fs = getPublicFileSystemContext();
try {
TruffleFile useDir = dir == null ? new TruffleFile(fs, fs.fileSystem.getTempDirectory()) : dir;
return TruffleFile.createTempFile(useDir, prefix, suffix, false, attrs);
} catch (UnsupportedOperationException | IllegalArgumentException | IOException | SecurityException e) {
throw e;
} catch (Throwable t) {
throw TruffleFile.wrapHostException(t, fs.fileSystem);
}
}
Creates a new directory in the specified or default temporary directory, using the given
prefix to generate its name.
This method provides only part of a temporary file facility. A shutdown hook
may be used to delete the directory automatically.
Params: - dir – the directory in which the directory should be created or
null
for a default temporary directory - prefix – the prefix to generate the directory's name or
null
- attrs – the optional attributes to set atomically when creating the directory
Throws: - IOException – in case of IO error
- IllegalArgumentException – if the prefix cannot be used to generate a valid file
name
- UnsupportedOperationException – if the attributes contain an attribute which cannot be set atomically or
FileSystem
does not support default temporary directory - SecurityException – if the
FileSystem
denied the operation
Returns: the TruffleFile
representing the newly created directory that did not exist before this method was invoked Since: 19.3.0
/**
* Creates a new directory in the specified or default temporary directory, using the given
* prefix to generate its name.
* <p>
* This method provides only part of a temporary file facility. A
* {@link Runtime#addShutdownHook shutdown hook} may be used to delete the directory
* automatically.
*
* @param dir the directory in which the directory should be created or {@code null} for a
* default temporary directory
* @param prefix the prefix to generate the directory's name or {@code null}
* @param attrs the optional attributes to set atomically when creating the directory
* @return the {@link TruffleFile} representing the newly created directory that did not
* exist before this method was invoked
* @throws IOException in case of IO error
* @throws IllegalArgumentException if the prefix cannot be used to generate a valid file
* name
* @throws UnsupportedOperationException if the attributes contain an attribute which cannot
* be set atomically or {@link FileSystem} does not support default temporary
* directory
* @throws SecurityException if the {@link FileSystem} denied the operation
* @since 19.3.0
*/
@TruffleBoundary
public TruffleFile createTempDirectory(TruffleFile dir, String prefix, FileAttribute<?>... attrs) throws IOException {
FileSystemContext fs = getPublicFileSystemContext();
try {
TruffleFile useDir = dir == null ? new TruffleFile(fs, fs.fileSystem.getTempDirectory()) : dir;
return TruffleFile.createTempFile(useDir, prefix, null, true, attrs);
} catch (UnsupportedOperationException | IllegalArgumentException | IOException | SecurityException e) {
throw e;
} catch (Throwable t) {
throw TruffleFile.wrapHostException(t, fs.fileSystem);
}
}
Creates a Java host adapter class that can be instantiated with a guest object (as the last argument) in order to create adapter instances of the provided host types, (non-final) methods of which delegate to the guest object's invocable members. Implementations must be allowed for these types. The returned adapter class is also a meta object, so isMetaInstance
can be used to check if an object is an instance of this adapter class. See usage example below.
A host class is generated as follows:
For every protected or public constructor in the extended class, the adapter class will
have one public constructor (visibility of protected constructors in the extended class
is promoted to public).
For every super constructor, a constructor taking a trailing Value
argument preceded by original constructor's arguments is generated. When such a constructor is invoked, the passed Value
's member functions are used to implement and/or override methods on the original class, dispatched by name. A single invocable member will act as the implementation for all overloaded methods of the same name. When methods on an adapter instance are invoked, the functions are invoked having the Value
passed in the instance constructor as their receiver. Subsequent changes to the members of that Value
(reassignment or removal of its functions) are reflected in the adapter instance; the method implementations are not bound to functions at constructor invocation time.
The generated host class extends all non-final public or protected methods, and forwards their invocations to the guest object provided to the constructor. If the guest object does not contain an invocable member with that name, the super/default method is invoked instead. If the super method is abstract, an AbstractMethodError
is thrown.
If the original types collectively have only one abstract method, or have several of them, but all share the same name, the constructor(s) will check if the Value
is executable, and if so, will use the passed function as the implementation for all abstract methods. For consistency, any concrete methods sharing the single abstract method name will also be overridden by the function.
For non-void methods, all the conversions supported by Value.as
will be in effect to coerce the guest methods' return value to the expected Java return type.
Instances of the host class have the following additional special members:
super
: provides access to the super methods of the host class via a wrapper object. Can be used to call super methods from guest method overrides. this
: returns the original guest object.
Example:
Object hostClass = env.createHostAdapterClass(new Class[]{Superclass.class, Interface.class});
// generates a class along the lines of:
public class Adapter extends Superclass implements Interface {
private Value delegate;
public Adapter(Value delegate) { this.delegate = delegate; }
public method(Object... args) {
if (delegate.canInvokeMember("method") {
return delegate.invokeMember("method", args);
} else {
return super.method(args);
}
}
}
// and can be instantiated as follows:
Object instance = InteropLibrary.getUncached().instantiate(hostClass, guestObject);
assert InteropLibrary.getUncached().isMetaInstance(hostClass, instance);
Params: - types – the types to extend. Must be non-null and contain at least one extensible
superclass or interface, and at most one superclass. All types must be public,
accessible, and allow implementation.
Throws: - IllegalArgumentException – if the types are not extensible or more than one
superclass is given.
- SecurityException – if host access does not allow creating adapter classes for
these types.
- UnsupportedOperationException – if creating adapter classes is not supported on
this runtime at all, which is currently the case for native images.
- NullPointerException – if
types
is null
See Also: Returns: a host class that can be instantiated to create instances of a host class that
extends all the provided host types. The host class may be cached. Since: 20.3.0
/**
* Creates a Java host adapter class that can be
* {@linkplain com.oracle.truffle.api.interop.InteropLibrary#instantiate instantiated} with
* a guest object (as the last argument) in order to create adapter instances of the
* provided host types, (non-final) methods of which delegate to the guest object's
* {@linkplain com.oracle.truffle.api.interop.InteropLibrary#isMemberInvocable invocable}
* members. Implementations must be
* {@linkplain org.graalvm.polyglot.HostAccess.Builder#allowImplementations(Class) allowed}
* for these types. The returned adapter class is also a
* {@linkplain com.oracle.truffle.api.interop.InteropLibrary#isMetaObject meta object}, so
* {@link com.oracle.truffle.api.interop.InteropLibrary#isMetaInstance isMetaInstance} can
* be used to check if an object is an instance of this adapter class. See usage example
* below.
* <p>
* A host class is generated as follows:
* <p>
* For every protected or public constructor in the extended class, the adapter class will
* have one public constructor (visibility of protected constructors in the extended class
* is promoted to public).
* <p>
* For every super constructor, a constructor taking a trailing {@link Value} argument
* preceded by original constructor's arguments is generated. When such a constructor is
* invoked, the passed {@link Value}'s member functions are used to implement and/or
* override methods on the original class, dispatched by name. A single invocable member
* will act as the implementation for all overloaded methods of the same name. When methods
* on an adapter instance are invoked, the functions are invoked having the {@link Value}
* passed in the instance constructor as their receiver. Subsequent changes to the members
* of that {@link Value} (reassignment or removal of its functions) are reflected in the
* adapter instance; the method implementations are not bound to functions at constructor
* invocation time.
* <p>
* The generated host class extends all non-final public or protected methods, and forwards
* their invocations to the guest object provided to the constructor. If the guest object
* does not contain an invocable member with that name, the super/default method is invoked
* instead. If the super method is abstract, an {@link AbstractMethodError} is thrown.
* <p>
* If the original types collectively have only one abstract method, or have several of
* them, but all share the same name, the constructor(s) will check if the {@link Value} is
* executable, and if so, will use the passed function as the implementation for all
* abstract methods. For consistency, any concrete methods sharing the single abstract
* method name will also be overridden by the function.
* <p>
* For non-void methods, all the conversions supported by {@link Value#as} will be in effect
* to coerce the guest methods' return value to the expected Java return type.
* <p>
* Instances of the host class have the following additional special members:
* <ul>
* <li>{@code super}: provides access to the super methods of the host class via a wrapper
* object. Can be used to call super methods from guest method overrides.
* <li>{@code this}: returns the original guest object.
* </ul>
* <p>
* Example:<br>
*
* <pre>
* <code>
* Object hostClass = env.createHostAdapterClass(new Class<?>[]{Superclass.class, Interface.class});
* // generates a class along the lines of:
*
* public class Adapter extends Superclass implements Interface {
* private Value delegate;
*
* public Adapter(Value delegate) { this.delegate = delegate; }
*
* public method(Object... args) {
* if (delegate.canInvokeMember("method") {
* return delegate.invokeMember("method", args);
* } else {
* return super.method(args);
* }
* }
* }
*
* // and can be instantiated as follows:
* Object instance = InteropLibrary.getUncached().instantiate(hostClass, guestObject);
* assert InteropLibrary.getUncached().isMetaInstance(hostClass, instance);
* </code>
* </pre>
*
* @param types the types to extend. Must be non-null and contain at least one extensible
* superclass or interface, and at most one superclass. All types must be public,
* accessible, and allow implementation.
* @return a host class that can be instantiated to create instances of a host class that
* extends all the provided host types. The host class may be cached.
* @throws IllegalArgumentException if the types are not extensible or more than one
* superclass is given.
* @throws SecurityException if host access does not allow creating adapter classes for
* these types.
* @throws UnsupportedOperationException if creating adapter classes is not supported on
* this runtime at all, which is currently the case for native images.
* @throws NullPointerException if {@code types} is null
*
* @see #createHostAdapterClassWithStaticOverrides(Class[], Object)
* @since 20.3.0
*/
@TruffleBoundary
public Object createHostAdapterClass(Class<?>[] types) {
Objects.requireNonNull(types, "types");
return createHostAdapterClassImpl(types, null);
}
Like createHostAdapterClass(Class<?>[])
but creates a Java host adapter class with class-level overrides, i.e., the guest object provided as classOverrides
is statically bound to the class rather than instances of the class. Returns a host class that can be
instantiated to create instances of the provided host types
, (non-final) methods of which delegate to the guest object provided as classOverrides
.
Allows creating host adapter class hierarchies, i.e., the returned class can be used as a
superclass of other host adapter classes. Note that classes created with method cannot be
cached. Therefore, this feature should be used sparingly.
See createHostAdapterClass(Class<?>[])
for more details.
Params: - types – the types to extend. Must be non-null and contain at least one extensible
superclass or interface, and at most one superclass. All types must be public,
accessible, and allow implementation.
- classOverrides – a guest object with class-level overrides. If not null, the object
is bound to the class, not to any instance. Consequently, the generated
constructors are changed to not take an object; all instances will share the
same overrides object. Note that since a new class has to be generated for
every overrides object instance and cannot be shared, use of this feature is
discouraged; it is provided only for compatibility reasons.
Throws: - IllegalArgumentException – if the types are not extensible or more than one
superclass is given.
- SecurityException – if host access does not allow creating adapter classes for
these types.
- UnsupportedOperationException – if creating adapter classes is not supported on
this runtime at all, which is currently the case for native images.
- NullPointerException – if either
types
or classOverrides
is null.
See Also: Returns: a host class symbol that can be instantiated to create instances of a host class
that extends all the provided host types. Since: 20.3.0
/**
* Like {@link #createHostAdapterClass(Class[])} but creates a Java host adapter class with
* class-level overrides, i.e., the guest object provided as {@code classOverrides} is
* statically bound to the class rather than instances of the class. Returns a host class
* that can be {@linkplain com.oracle.truffle.api.interop.InteropLibrary#instantiate
* instantiated} to create instances of the provided host {@code types}, (non-final) methods
* of which delegate to the guest object provided as {@code classOverrides}.
* <p>
* Allows creating host adapter class hierarchies, i.e., the returned class can be used as a
* superclass of other host adapter classes. Note that classes created with method cannot be
* cached. Therefore, this feature should be used sparingly.
* <p>
* See {@link #createHostAdapterClass(Class[])} for more details.
*
* @param types the types to extend. Must be non-null and contain at least one extensible
* superclass or interface, and at most one superclass. All types must be public,
* accessible, and allow implementation.
* @param classOverrides a guest object with class-level overrides. If not null, the object
* is bound to the class, not to any instance. Consequently, the generated
* constructors are changed to not take an object; all instances will share the
* same overrides object. Note that since a new class has to be generated for
* every overrides object instance and cannot be shared, use of this feature is
* discouraged; it is provided only for compatibility reasons.
* @return a host class symbol that can be instantiated to create instances of a host class
* that extends all the provided host types.
* @throws IllegalArgumentException if the types are not extensible or more than one
* superclass is given.
* @throws SecurityException if host access does not allow creating adapter classes for
* these types.
* @throws UnsupportedOperationException if creating adapter classes is not supported on
* this runtime at all, which is currently the case for native images.
* @throws NullPointerException if either {@code types} or {@code classOverrides} is null.
*
* @see #createHostAdapterClass(Class[])
* @since 20.3.0
*/
@TruffleBoundary
public Object createHostAdapterClassWithStaticOverrides(Class<?>[] types, Object classOverrides) {
Objects.requireNonNull(types, "types");
Objects.requireNonNull(classOverrides, "classOverrides");
return createHostAdapterClassImpl(types, classOverrides);
}
private Object createHostAdapterClassImpl(Class<?>[] types, Object classOverrides) {
checkDisposed();
try {
if (types.length == 0) {
throw new IllegalArgumentException("Expected at least one type.");
}
return LanguageAccessor.engineAccess().createHostAdapterClass(polyglotLanguageContext, types, classOverrides);
} catch (Throwable t) {
throw engineToLanguageException(t);
}
}
@SuppressWarnings("rawtypes")
@TruffleBoundary
<E extends TruffleLanguage> E getLanguage(Class<E> languageClass) {
checkDisposed();
if (languageClass != getSpi().getClass()) {
throw new IllegalArgumentException("Invalid access to language " + languageClass + ".");
}
return languageClass.cast(getSpi());
}
Object findExportedSymbol(String globalName, boolean onlyExplicit) {
Object c = getLanguageContext();
if (c != UNSET_CONTEXT) {
return getSpi().findExportedSymbol(c, globalName, onlyExplicit);
} else {
return null;
}
}
Object getLanguageGlobal() {
Object c = getLanguageContext();
if (c != UNSET_CONTEXT) {
return getSpi().getLanguageGlobal(c);
} else {
return null;
}
}
Object findMetaObjectImpl(Object obj) {
Object c = getLanguageContext();
if (c != UNSET_CONTEXT) {
return getSpi().findMetaObject(c, obj);
} else {
return null;
}
}
SourceSection findSourceLocation(Object obj) {
Object c = getLanguageContext();
if (c != UNSET_CONTEXT) {
return getSpi().findSourceLocation(c, obj);
} else {
return null;
}
}
boolean isObjectOfLanguage(Object obj) {
return getSpi().isObjectOfLanguage(obj);
}
@SuppressWarnings("deprecation")
Iterable<Scope> findLocalScopes(Node node, Frame frame) {
assert node != null;
return getSpi().findLocalScopes(context, node, frame);
}
@SuppressWarnings("deprecation")
Iterable<Scope> findTopScopes() {
return getSpi().findTopScopes(context);
}
void dispose() {
Object c = getLanguageContext();
if (c != UNSET_CONTEXT) {
getSpi().disposeContext(c);
} else {
throw new IllegalStateException("Disposing while context has not been set yet.");
}
}
@TruffleBoundary
void postInit() {
try {
getSpi().initializeContext(context);
} catch (RuntimeException ex) {
throw ex;
} catch (Exception ex) {
throw new RuntimeException(ex);
} finally {
initialized = true;
Assumption old = initializedUnchangedAssumption;
initializedUnchangedAssumption = Truffle.getRuntime().createAssumption("Language context initialized unchanged");
old.invalidate();
}
}
boolean isInitialized() {
if (CompilerDirectives.isPartialEvaluationConstant(this)) {
boolean localInitialized = initialized;
if (initializedUnchangedAssumption.isValid()) {
return localInitialized;
} else {
CompilerDirectives.transferToInterpreterAndInvalidate();
return initialized;
}
} else {
return initialized;
}
}
boolean isVisible(Object value) {
Object c = getLanguageContext();
if (c != UNSET_CONTEXT) {
return getSpi().isVisible(c, value);
} else {
return false;
}
}
String toStringIfVisible(Object value, boolean checkVisibility) {
Object c = getLanguageContext();
if (c != UNSET_CONTEXT) {
if (checkVisibility) {
if (!getSpi().isVisible(c, value)) {
return null;
}
}
return getSpi().toString(c, value);
} else {
return null;
}
}
Object getLanguageContext() {
if (CompilerDirectives.isPartialEvaluationConstant(this)) {
Object languageContext = this.context;
if (contextUnchangedAssumption.isValid()) {
return languageContext;
} else {
CompilerDirectives.transferToInterpreterAndInvalidate();
return context;
}
} else {
return this.context;
}
}
@SuppressWarnings("unchecked")
@TruffleBoundary
static <T extends RuntimeException> RuntimeException engineToLanguageException(Throwable t) {
return LanguageAccessor.engineAccess().engineToLanguageException(t);
}
}
Represents a reference to the language to be stored in an AST. A reference can be accessed using Node.lookupLanguageReference(Class<TruffleLanguage>)
and the current language can be accessed using the get()
method of the returned reference. The current language might vary between executions
if the reference is used with interoperability APIs in the AST of a foreign language.
Since: 19.0
/**
* Represents a reference to the language to be stored in an AST. A reference can be accessed
* using {@link Node#lookupLanguageReference(Class)} and the current language can be accessed
* using the {@link LanguageReference#get()} method of the returned reference.
* <p>
* The current language might vary between {@link RootNode#execute(VirtualFrame) executions} if
* the reference is used with interoperability APIs in the AST of a foreign language.
*
* @since 19.0
*/
@SuppressWarnings("rawtypes")
public abstract static class LanguageReference<L extends TruffleLanguage> {
Constructors for subclasses.
Since: 19.0
/**
* Constructors for subclasses.
*
* @since 19.0
*/
protected LanguageReference() {
}
Returns the current language of the current execution context. If a context is accessed during context creation
or in the language class constructor an IllegalStateException
is thrown. This methods is designed to be called safely from compiled code paths. The current language might vary between executions
if the reference is used with interoperability APIs in the AST of a foreign language.
Since: 19.0
/**
* Returns the current language of the current execution context. If a context is accessed
* during {@link TruffleLanguage#createContext(Env) context creation} or in the language
* class constructor an {@link IllegalStateException} is thrown. This methods is designed to
* be called safely from compiled code paths.
* <p>
* The current language might vary between {@link RootNode#execute(VirtualFrame) executions}
* if the reference is used with interoperability APIs in the AST of a foreign language.
*
* @since 19.0
*/
public abstract L get();
}
Represents a reference to the current context to be stored in an AST. A reference can be accessed using Node.lookupContextReference(Class<TruffleLanguage<Object>>)
and the current context can be accessed using the get()
method of the returned reference. The current context might vary between executions
if resources or code is shared between multiple contexts.
Since: 0.25
/**
* Represents a reference to the current context to be stored in an AST. A reference can be
* accessed using {@link Node#lookupContextReference(Class)} and the current context can be
* accessed using the {@link ContextReference#get()} method of the returned reference.
* <p>
* The current context might vary between {@link RootNode#execute(VirtualFrame) executions} if
* resources or code is shared between multiple contexts.
*
* @since 0.25
*/
public abstract static class ContextReference<C> {
Constructors for subclasses.
Since: 19.0
/**
* Constructors for subclasses.
*
* @since 19.0
*/
protected ContextReference() {
}
Returns the current language context of the current execution context. If a context is accessed during context creation
or in the language class constructor an IllegalStateException
is thrown. This methods is designed to be called safely from compiled code paths. The current context might vary between executions
if resources or code is shared between multiple contexts.
Since: 0.25
/**
* Returns the current language context of the current execution context. If a context is
* accessed during {@link TruffleLanguage#createContext(Env) context creation} or in the
* language class constructor an {@link IllegalStateException} is thrown. This methods is
* designed to be called safely from compiled code paths.
* <p>
* The current context might vary between {@link RootNode#execute(VirtualFrame) executions}
* if resources or code is shared between multiple contexts.
*
* @since 0.25
*/
@SuppressWarnings("unchecked")
public abstract C get();
}
Defines the supported policy for reusing languages
per context. I.e. the policy specifies the degree of sharing that is allowed between multiple language contexts. The default policy is exclusive
. Every language is encouraged to try to support a context policy that is as permissive as possible, where
exclusive
is the least and shared
is the most permissive policy. Parse caching
is scoped per language
instance, therefore the context policy influences its behavior. The context policy applies to contexts that were created using the polyglot API as well as for inner contexts
. The context policy does not apply to nodes that were created using the Truffle interop protocol. Therefore, interop message nodes always need to be prepared to be used with policy SHARED
.
See Also: Since: 19.0
/**
* Defines the supported policy for reusing {@link TruffleLanguage languages} per context. I.e.
* the policy specifies the degree of sharing that is allowed between multiple language
* contexts. The default policy is {@link #EXCLUSIVE exclusive}. Every language is encouraged to
* try to support a context policy that is as permissive as possible, where {@link #EXCLUSIVE
* exclusive} is the least and {@link #SHARED shared} is the most permissive policy.
* {@link TruffleLanguage#parse(ParsingRequest) Parse caching} is scoped per
* {@link TruffleLanguage language} instance, therefore the context policy influences its
* behavior.
* <p>
* The context policy applies to contexts that were created using the polyglot API as well as
* for {@link TruffleContext inner contexts}. The context policy does not apply to nodes that
* were created using the Truffle interop protocol. Therefore, interop message nodes always need
* to be prepared to be used with policy {@link ContextPolicy#SHARED}.
*
* @see Registration#contextPolicy() To configure context policy for a language.
* @see TruffleLanguage#parse(ParsingRequest)
* @since 19.0
*/
public enum ContextPolicy {
Use one exclusive TruffleLanguage
instance per language context instance.
Using this policy has the following implications:
Parse caching
is scoped per language
instance. This means the language context instance may be directly stored in instance fields of AST nodes without the use of ContextReference
. The use of ContextReference
is still recommended to simplify migration to more permissive policies. - If the language does not allow
multi-threading
(default behavior) then the language instance is guaranteed to be used from one thread at a time only. Cached ASTs will not be used from multiple threads at the same time. TruffleLanguage.initializeMultipleContexts()
is guaranteed to never be invoked.
Since: 19.0
/**
* Use one exclusive {@link TruffleLanguage} instance per language context instance.
* <p>
* Using this policy has the following implications:
* <ul>
* <li>{@link TruffleLanguage#parse(ParsingRequest) Parse caching} is scoped per
* {@link TruffleLanguage language} instance. This means the language context instance may
* be directly stored in instance fields of AST nodes without the use of
* {@link ContextReference}. The use of {@link ContextReference} is still recommended to
* simplify migration to more permissive policies.
* <li>If the language does not allow
* {@link TruffleLanguage#isThreadAccessAllowed(Thread, boolean) multi-threading} (default
* behavior) then the language instance is guaranteed to be used from one thread at a time
* only. Cached ASTs will not be used from multiple threads at the same time.
* <li>{@link TruffleLanguage#initializeMultipleContexts()} is guaranteed to never be
* invoked.
* </ul>
*
* @since 19.0
*/
EXCLUSIVE,
Use a single TruffleLanguage
instance per context instance, but allow the reuse of a language instance when a context was
disposed
. This policy is useful when parsed ASTs should be shared, but multiple thread execution of the AST is not yet supported by the language.
Using this policy has the following implications:
Parse caching
is scoped per language
instance. This means language context instances must NOT be directly stored in instance fields of AST nodes and the ContextReference
must be used instead. - If the language does not
allow
access from multiple threads (default behavior) then the language instance is guaranteed to be used from one thread at a time only. In this case also cached ASTs will not be used from multiple threads at the same time. If the language allows access from multiple threads then also ASTs may be used from multiple threads at the same time. TruffleLanguage.initializeMultipleContexts()
will be invoked to notify the language that multiple contexts will be used with one language instance. Language
instance fields must only be used for data that can be shared across multiple contexts.
Since: 19.0
/**
* Use a single {@link TruffleLanguage} instance per context instance, but allow the reuse
* of a language instance when a context was {@link TruffleLanguage#disposeContext(Object)
* disposed}. This policy is useful when parsed ASTs should be shared, but multiple thread
* execution of the AST is not yet supported by the language.
* <p>
* Using this policy has the following implications:
* <ul>
* <li>{@link TruffleLanguage#parse(ParsingRequest) Parse caching} is scoped per
* {@link TruffleLanguage language} instance. This means language context instances must NOT
* be directly stored in instance fields of AST nodes and the {@link ContextReference} must
* be used instead.
* <li>If the language does not
* {@link TruffleLanguage#isThreadAccessAllowed(Thread, boolean) allow} access from multiple
* threads (default behavior) then the language instance is guaranteed to be used from one
* thread at a time only. In this case also cached ASTs will not be used from multiple
* threads at the same time. If the language allows access from multiple threads then also
* ASTs may be used from multiple threads at the same time.
* <li>{@link TruffleLanguage#initializeMultipleContexts()} will be invoked to notify the
* language that multiple contexts will be used with one language instance.
* <li>{@link TruffleLanguage Language} instance fields must only be used for data that can
* be shared across multiple contexts.
* </ul>
*
* @since 19.0
*/
REUSE,
Use one TruffleLanguage
instance for many language context instances.
Using this policy has the following implications:
Parse caching
is scoped per language
instance. With multiple language instances per context, context instances must not be directly stored in instance fields of AST nodes and the ContextReference
must be used instead. - All methods of the
language
instance and parsed ASTs may be called from multiple threads at the same time independent of whether multiple thread access is allowed
for the language. TruffleLanguage.initializeMultipleContexts()
will be invoked to notify the language that multiple contexts will be used with one language instance. Language
instance fields must only be used for data that can be shared across multiple contexts and mutable data held by the language instance must be synchronized to support concurrent access.
Since: 19.0
/**
* Use one {@link TruffleLanguage} instance for many language context instances.
* <p>
* Using this policy has the following implications:
* <ul>
* <li>{@link TruffleLanguage#parse(ParsingRequest) Parse caching} is scoped per
* {@link TruffleLanguage language} instance. With multiple language instances per context,
* context instances must <i>not</i> be directly stored in instance fields of AST nodes and
* the {@link ContextReference} must be used instead.
* <li>All methods of the {@link TruffleLanguage language} instance and parsed ASTs may be
* called from multiple threads at the same time independent of whether multiple thread
* access is {@link TruffleLanguage#isThreadAccessAllowed(Thread, boolean) allowed} for the
* language.
* <li>{@link TruffleLanguage#initializeMultipleContexts()} will be invoked to notify the
* language that multiple contexts will be used with one language instance.
* <li>{@link TruffleLanguage Language} instance fields must only be used for data that can
* be shared across multiple contexts and mutable data held by the language instance must be
* synchronized to support concurrent access.
* </ul>
*
* @since 19.0
*/
SHARED;
}
}
class TruffleLanguageSnippets {
class Context {
String[] args;
Env env;
CallTarget mul;
InputStream in;
OutputStream out;
OutputStream err;
String languageVersion;
Context(String[] args) {
this.args = args;
this.env = null;
this.languageVersion = null;
}
Context(Env env) {
this.env = env;
this.args = null;
this.languageVersion = null;
}
Context(Env env, String languageVersion) {
this.env = env;
this.args = null;
this.languageVersion = languageVersion;
}
Context fork() {
return null;
}
final Assumption singleThreaded = Truffle.getRuntime().createAssumption();
final List<Thread> startedThreads = new ArrayList<>();
}
// @formatter:off
abstract
class MyLanguage extends TruffleLanguage<Context> {
@Override
protected Context createContext(Env env) {
String[] args = env.getApplicationArguments();
return new Context(args);
}
}
abstract
// BEGIN: TruffleLanguageSnippets.PostInitLanguage#createContext
class PostInitLanguage extends TruffleLanguage<Context> {
@Override
protected Context createContext(Env env) {
// "quickly" create the context
return new Context(env);
}
@Override
protected void initializeContext(Context context) throws IOException {
// called "later" to finish the initialization
// for example call into another language
Source source = Source.newBuilder("js",
"function(x, y) x * y",
"mul.js").build();
context.mul = context.env.parsePublic(source);
}
}
// END: TruffleLanguageSnippets.PostInitLanguage#createContext
abstract static
// BEGIN: TruffleLanguageSnippets.CompatibleLanguage#areOptionsCompatible
class CompatibleLanguage extends TruffleLanguage<Env> {
@Option(help = "", category = OptionCategory.USER)
static final OptionKey<String> ScriptVersion
= new OptionKey<>("ECMA2017");
@Override
protected boolean areOptionsCompatible(OptionValues firstOptions,
OptionValues newOptions) {
return firstOptions.get(ScriptVersion).
equals(newOptions.get(ScriptVersion));
}
@Override
protected OptionDescriptors getOptionDescriptors() {
return new CompatibleLanguageOptionDescriptors();
}
}
// END: TruffleLanguageSnippets.CompatibleLanguage#areOptionsCompatible
static class CompatibleLanguageOptionDescriptors implements OptionDescriptors{
public OptionDescriptor get(String optionName) {
return null;
}
public Iterator<OptionDescriptor> iterator() {
return null;
}
}
abstract
class PreInitializedLanguage extends TruffleLanguage<Context> {
private final OptionKey<String> version = new OptionKey<>("2.0");
// BEGIN: TruffleLanguageSnippets.PreInitializedLanguage#patchContext
@Override
protected boolean patchContext(Context context, Env newEnv) {
if (!optionsAllowPreInitializedContext(context, newEnv)) {
// Incompatible options - cannot use pre-initialized context
return false;
}
context.env = newEnv;
context.args = newEnv.getApplicationArguments();
context.in = newEnv.in();
context.out = newEnv.out();
context.err = newEnv.err();
return true;
}
private boolean optionsAllowPreInitializedContext(Context context, Env newEnv) {
// Verify that values of important options in the new Env do not differ
// from values in the pre-initialized context
final String newVersionValue = newEnv.getOptions().get(version);
return Objects.equals(context.languageVersion, newVersionValue);
}
// END: TruffleLanguageSnippets.PreInitializedLanguage#patchContext
}
// BEGIN: TruffleLanguageSnippets#parseWithParams
public void parseWithParams(Env env) {
Source multiply = Source.newBuilder("js",
"a * b",
"mul.js").build();
CallTarget method = env.parsePublic(multiply, "a", "b");
Number fortyTwo = (Number) method.call(6, 7);
assert 42 == fortyTwo.intValue();
Number ten = (Number) method.call(2, 5);
assert 10 == ten.intValue();
}
// END: TruffleLanguageSnippets#parseWithParams
abstract
// BEGIN: TruffleLanguageSnippets.MultiThreadedLanguage#initializeThread
class MultiThreadedLanguage extends TruffleLanguage<Context> {
@Override
protected Context createContext(Env env) {
return new Context(env);
}
@Override
protected boolean isThreadAccessAllowed(Thread thread,
boolean singleThreaded) {
// allow access from any thread instead of just one
return true;
}
@Override
protected void initializeMultiThreading(Context context) {
// perform actions when the context is switched to multi-threading
context.singleThreaded.invalidate();
}
@Override
protected void initializeThread(Context context, Thread thread) {
// perform initialization actions for threads
}
@Override
protected void disposeThread(Context context, Thread thread) {
// perform disposal actions for threads
}
}
// END: TruffleLanguageSnippets.MultiThreadedLanguage#initializeThread
abstract
// BEGIN: TruffleLanguageSnippets.AsyncThreadLanguage#finalizeContext
class AsyncThreadLanguage extends TruffleLanguage<Context> {
@Override
protected Context createContext(Env env) {
return new Context(env);
}
@Override
protected boolean isThreadAccessAllowed(Thread thread,
boolean singleThreaded) {
// allow access from any thread instead of just one
return true;
}
@Override
protected void initializeContext(Context context) throws Exception {
// create and start a Thread for the asynchronous task
// remeber the Thread reference to stop and join it in
// the finalizeContext
Thread t = context.env.createThread(new Runnable() {
@Override
public void run() {
// asynchronous task
}
});
context.startedThreads.add(t);
t.start();
}
@Override
protected void finalizeContext(Context context) {
// stop and join all the created Threads
boolean interrupted = false;
for (int i = 0; i < context.startedThreads.size();) {
Thread threadToJoin = context.startedThreads.get(i);
try {
if (threadToJoin != Thread.currentThread()) {
threadToJoin.interrupt();
threadToJoin.join();
}
i++;
} catch (InterruptedException ie) {
interrupted = true;
}
}
if (interrupted) {
Thread.currentThread().interrupt();
}
}
}
// END: TruffleLanguageSnippets.AsyncThreadLanguage#finalizeContext
}