Class TruffleLanguage<C>
- Type Parameters:
C
- internal state of the language associated with every thread that is executing programparsed
by the language
TruffleLanguage.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 theTruffleLanguage.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 and Sharing
The number ofTruffleLanguage
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 :For more information on sharing between multiple contexts please seeTruffleLanguage
- I : Instrument - 1 :TruffleInstrument
TruffleLanguage.ContextPolicy
.
Parse Caching
The result of theparsing 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
Oncontext 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 thepolyglot
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 theContext
, 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 isdisposed
. - 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.
In addition to the two kinds of threads described above, there are
system threads
designed to process language
internal tasks in the background. They do not require the creation permit
, but they must not enter any language context.
- Since:
- 0.8 or earlier
- See Also:
-
Nested Class Summary
Modifier and TypeClassDescriptionprotected static interface
Context local factory for Truffle languages.protected static final class
Provider for creating context local and context thread local references.static enum
Defines the supported policy for reusinglanguages
per context.static class
Represents a reference to the current context.protected static interface
Context thread local factory for Truffle languages.static final class
Represents execution environment of theTruffleLanguage
.static enum
Mode of exit operation.static final class
Request for inline parsing.static class
Represents a reference to the current language instance.static final class
Request for parsing.static interface
Deprecated.static @interface
The annotation to use to register your language to thePolyglot API
. -
Field Summary
Modifier and TypeFieldDescriptionprotected final TruffleLanguage.ContextLocalProvider
<C> Provider for creating context local and context thread local references. -
Constructor Summary
ModifierConstructorDescriptionprotected
Constructor to be called by subclasses. -
Method Summary
Modifier and TypeMethodDescriptionprotected boolean
areOptionsCompatible
(OptionValues firstOptions, OptionValues newOptions) protected abstract C
Creates internal representation of the executing context suitable for given environment.protected final <T> ContextLocal
<T> createContextLocal
(TruffleLanguage.ContextLocalFactory<C, T> factory) Deprecated.protected final <T> ContextThreadLocal
<T> Deprecated.protected void
disposeContext
(C context) Disposes the context created bycreateContext(com.oracle.truffle.api.TruffleLanguage.Env)
.protected void
disposeThread
(C context, Thread thread) Invoked the last time code will be executed for this thread and context.protected void
exitContext
(C context, TruffleLanguage.ExitMode exitMode, int exitCode) Performs language exit event actions that are necessary before language contexts arefinalized
.protected void
finalizeContext
(C context) Performs language context finalization actions that are necessary before language contexts aredisposed
.protected void
finalizeThread
(C context, Thread thread) The behavior of this notification is different forpolyglot threads
and embedder threads.protected final int
Get the depth of asynchronous stack.protected static <C,
T extends TruffleLanguage<C>>
CgetCurrentContext
(Class<T> languageClass) Deprecated.in 21.3, use static final context references instead.protected static <T extends TruffleLanguage<?>>
TgetCurrentLanguage
(Class<T> languageClass) Deprecated.in 21.3, use static final context references instead.protected final String
Returns the home location for this language ornull
if the language home is not set.protected Object
getLanguageView
(C context, Object value) Wraps the value to provide language-specific information for primitive and foreign values.protected OptionDescriptors
Returns a set of option descriptors that are supported by this language.protected Object
Get a top scope of the language, if any.protected void
initializeContext
(C context) Perform any complex initialization.protected void
Initializes this language instance for use with multiple contexts.protected void
initializeMultiThreading
(C context) Invoked before the context is accessed from multiple threads at the same time.protected void
initializeThread
(C context, Thread thread) Invoked before a context is accessed from a new thread.protected boolean
isThreadAccessAllowed
(Thread thread, boolean singleThreaded) Returnstrue
if code of this language is allowed to be executed on this thread.protected boolean
Decides whether the result of evaluating an interactive source should be printed to stdout.protected ExecutableNode
Parses theprovided source snippet
at theprovided location
and generates its appropriate AST representation.protected CallTarget
parse
(TruffleLanguage.ParsingRequest request) Parses theprovided source
and generates its appropriate AST representation.protected boolean
patchContext
(C context, TruffleLanguage.Env newEnv) Notifies the language with pre-initialized context aboutTruffleLanguage.Env
change.
-
Field Details
-
locals
Provider for creating context local and context thread local references.- Since:
- 23.1
- See Also:
-
-
Constructor Details
-
TruffleLanguage
protected TruffleLanguage()Constructor to be called by subclasses. Language should not create anyRootNode
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 thecreateContext(Env)
.- Since:
- 0.8 or earlier
-
-
Method Details
-
areOptionsCompatible
Returnstrue
if the combination of two sets of options allow toshare
orreuse
the same language instance, elsefalse
. If options are incompatible then a new language instance will be created for a new context. The default implementation returnstrue
.If the context policy of a language is set to
exclusive
(default behavior) thenareOptionsCompatible(OptionValues, OptionValues)
will never be invoked asTruffleLanguage
instances will not be shared for multiple contexts. For the other context policiesreuse
andshared
this method can be used to further restrict the reuse of language instances. Compatibility influencesparse caching
because it uses thelanguage
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:
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(); } }
- Parameters:
firstOptions
- the options used to create the first context, nevernull
newOptions
- the options that will be used for the new context, nevernull
- Since:
- 19.0
- See Also:
-
createContext
Creates internal representation of the executing context suitable for given environment. Each time thelanguage
is used by a newContext
, the system calls this method to let thelanguage
prepare for execution. The returned execution context is completely language specific; it is however expected it will contain reference to here-in providedenv
and adjust itself according to parameters provided by theenv
object.The context created by this method is accessible using
context references
. AnIllegalStateException
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 theinitializeContext(java.lang.Object)
method.Additional services provided by the language must be
registered
by this method otherwiseIllegalStateException
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.- Parameters:
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
-
initializeContext
Perform any complex initialization. ThecreateContext(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 later to finish any post initialization actions. Example: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); } }
- Parameters:
context
- the context created bycreateContext(com.oracle.truffle.api.TruffleLanguage.Env)
- Throws:
Exception
- if something goes wrong- Since:
- 0.17
-
finalizeContext
Performs language context finalization actions that are necessary before language contexts aredisposed
. However, in case the underlying polyglot context is being cancelled or hard-exited,disposeContext(Object)
is called even iffinalizeContext(Object)
throws anAbstractTruffleException
or aThreadDeath
cancel or exit exception.For the hard exit a language is supposed to run its finalization actions that require running guest code in
exitContext(Object, ExitMode, int)
, but please note that afterexitContext(Object, ExitMode, int)
runs for a language, the language can still be invoked fromexitContext(Object, ExitMode, int)
for a different language. Therefore, for instance, finalization for standard streams should both flush and set them to unbuffered mode at the end of exitContext, so that running guest code is not required to dispose the streams after that point.Context finalization is invoked even if a context was cancelled. In such a case, if guest code would run as part of the finalization, it would be cancelled at the next polled
safepoint
. If there is guest code that always needs to run even if cancelled, e.g. to prevent resource leakage, useTruffleSafepoint.setAllowActions(boolean)
to temporarily disable safepoints while executing that code.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 the 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 the language must be stopped and joined during finalizeContext. The languages are responsible for fulfilling that contract, otherwise, anAssertionError
is thrown. It's not safe to use theExecutorService.awaitTermination(long, java.util.concurrent.TimeUnit)
to detect Thread termination as the polyglot thread may be cancelled before executing the executor worker.During finalizeContext, all unclosed inner contexts
created
by the language must be left on all threads where the contexts are still active. No active inner context is allowed afterfinalizeContext(Object)
returns, otherwise it is an internal error.Non-active inner contexts
created
by the language that are still unclosed afterfinalizeContext(Object)
returns are automatically closed by Truffle.Typical implementation looks like:
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.newTruffleThreadBuilder(new Runnable() { @Override public void run() { // asynchronous task } }).build(); 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(); } } }
- Parameters:
context
- the context created bycreateContext(com.oracle.truffle.api.TruffleLanguage.Env)
- Since:
- 0.30
- See Also:
-
exitContext
Performs language exit event actions that are necessary before language contexts arefinalized
. However, in case the underlying polyglot context is being cancelled,exit notifications
are not executed. Also, forhard exit
,finalizeContext(Object)
is called even ifexitContext(Object, ExitMode, int)
throws anAbstractTruffleException
or aThreadDeath
cancel or exit exception. All initialized language contexts must remain usable after exit notifications. In case aAbstractTruffleException
or theThreadDeath
exit exception is thrown during anhard exit notification
, it is just logged and otherwise ignored and the notification process continues with the next language in order. In case theThreadDeath
cancel exception is thrown, it means the context is being cancelled in which case the exit notification process immediately stops. The exit notification order can be influenced by specifyinglanguage dependencies
- The exit notification for language A that depends on language B is executed before the exit notification for language B. By default, notifications for internal languages are executed last, otherwise, the default order is unspecified but deterministic.During
hard exit
notification, a language is supposed to run its finalization actions that require running guest code instead of running them infinalizeContext(Object)
.While the exit notification code is run, all languages remain fully functional. Also, other language contexts may become initialized. In such a case, the notification order may be non-deterministic and/or not respect the order specified by language dependencies.
In case
TruffleContext.closeExited(Node, int)
is called during anatural exit
notification, natural exit notifications for remaining language contexts are not executed and thehard exit
process starts by executinghard exit
notifications. In caseTruffleContext.closeExited(Node, int)
is called during ahard exit
notification, it just throws the specialThreadDeath
exit exception, which is then just logged as described above.In case the underlying polyglot context is cancelled by e.g.
TruffleContext.closeCancelled(Node, String)
during exit notifications, guest code executed during exit notification is regularly cancelled, i.e., throws theThreadDeath
cancel exception, and the notification process does not continue as described above.In the case of
hard exit
, if the current context has inner contexts that are still active, the execution for them will be stopped as well after all language exit notifications are executed for the outer context, but the exit notifications for the inner contexts are not automatically executed. The language needs to take appropriate action to make sure inner contexts are exited properly.- Parameters:
context
- language context.exitMode
- mode of exit.exitCode
- exit code that was specified for exit.- Since:
- 22.0
- See Also:
-
initializeMultipleContexts
protected void initializeMultipleContexts()Initializes this language instance for use with multiple contexts. Whether a language instance supports being used for multiple contexts depends on itscontext policy
.For any sharing of a language instance for multiple language contexts to take place a context must be created with sharing enabled. By default sharing is disabled for polyglot contexts. Sharing can be enabled by specifying an
explicit engine
or using an option. Before any language is used for sharinginitializeMultipleContexts()
is invoked. It is guaranteed that sharing between multiple contexts isinitialized
before any language context iscreated
.A language may use this method to configure itself to use context independent speculations only. Since Truffle nodes are never shared between multiple language instances it is sufficient to keep track of whether sharing is enabled using a non-volatile boolean field instead of an assumption. They field may also be annotated with
CompilerDirectives.CompilationFinal
as it is guaranteed that this method is called prior to any compilation. The following criteria should be satisfied when supporting context independent code:- All speculation on runtime value identity must be disabled with multiple contexts initialized, as they will lead to a guaranteed deoptimization when used with a second context.
- Function inline caches should be modified and implemented as a two-level inline cache. The first level speculates on the function instance's identity and the second level on the underlying CallTarget instance. The first level cache must be disabled if multiple contexts are initialized, as this would unnecessarily cause deoptimization.
- The DynamicObject root Shape instance should be stored in the language instance instead of the language context. Otherwise, any inline cache on shapes will not stabilize and ultimately end up in the generic state.
- All Node implementations must not store context-dependent data structures or context-dependent runtime values.
- All assumption instances should be stored in the language instance instead of the context. With multiple contexts initialized, the context instance read using context references may no longer be a constant. In this case any assumption read from the context would not be folded and they would cause significant runtime performance overhead. Assumptions from the language can always be folded by the compiler in both single and multiple context mode.
- Since:
- 19.0
- See Also:
-
disposeContext
Disposes the context created bycreateContext(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 infinalizeContext(Object)
instead. Finalization will be performed prior to contextdisposal
. However, in case the underlying polyglot context is being cancelled,disposeContext(Object)
is called even iffinalizeContext(Object)
throwsAbstractTruffleException
orThreadDeath
exception..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 thelanguage environment
.- Parameters:
context
- the context created bycreateContext(com.oracle.truffle.api.TruffleLanguage.Env)
- Since:
- 0.8 or earlier
- See Also:
-
parse
Parses theprovided source
and generates its appropriate AST representation. The parsing should execute no user code, it should only create theNode
tree to represent the source. If theprovided source
does not correspond naturally to acall 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
andargument names
. It is safe to assume that currentlanguage
instance andargument names
will remain unchanged for a parsedCallTarget
. The scope of the caching is influenced by thecontext policy
and optioncompatibility
. Caching may bedisabled
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 methodCallTarget.call(java.lang.Object...)
that accepts as many arguments as were provided via theTruffleLanguage.ParsingRequest.getArgumentNames()
method.Implement
parse(com.oracle.truffle.api.TruffleLanguage.InlineParsingRequest)
to parse source in a specific context location.- Parameters:
request
- request for parsing- Returns:
- a call target to invoke which also keeps in memory the
Node
tree representing just parsedcode
- Throws:
Exception
- exception can be thrown when parsing goes wrong. Here-in thrown exception is propagated to the user who called one ofeval
methods ofContext
- Since:
- 0.22
- See Also:
-
parse
Parses theprovided source snippet
at theprovided location
and generates its appropriate AST representation. The parsing should execute no user code, it should only create theNode
tree to represent the source.The parsing should be performed in a context (specified by
TruffleLanguage.InlineParsingRequest.getLocation()
). The result should be an AST fragment with methodExecutableNode.execute(com.oracle.truffle.api.frame.VirtualFrame)
that accepts frames valid at theprovided location
.When not implemented,
null
is returned by default. -
getOptionDescriptors
Returns a set of option descriptors that are supported by this language. Option values are accessible using theenvironment
when the context iscreated
. To construct option descriptors from a list thenOptionDescriptors.create(List)
can be used. Languages must always return the same option descriptors independent of the language instance or side-effects.- Since:
- 0.27
- See Also:
-
patchContext
Notifies the language with pre-initialized context aboutTruffleLanguage.Env
change. SeeContext
for information how to enable the Context pre-initialization.During the pre-initialization (in the native compilation time) the
createContext(com.oracle.truffle.api.TruffleLanguage.Env)
andinitializeContext(java.lang.Object)
methods are called. In the image execution time, thepatchContext(java.lang.Object, com.oracle.truffle.api.TruffleLanguage.Env)
is called on all languages whose contexts were created during the pre-initialization a consequence ofContext.create(java.lang.String...)
invocation. The contexts are patched in a topological order starting from dependent languages. If thepatchContext(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.Typical implementation looks like:
@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); }
- Parameters:
context
- the context created bycreateContext(com.oracle.truffle.api.TruffleLanguage.Env)
during pre-initializationnewEnv
- 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
-
isThreadAccessAllowed
Returnstrue
if code of this language is allowed to be executed on this thread. The method returnsfalse
to deny execution on this thread. The default implementation denies access to more than one thread at the same time. Thecurrent thread
may differ from the passed thread. If this method throws anAbstractTruffleException
the exception interop messages may be executed without a context being entered.Example multi-threaded language implementation:
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 } }
- Parameters:
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
-
initializeMultiThreading
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 ifisThreadAccessAllowed(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 anAbstractTruffleException
the exception interop messages may be executed without a context being entered.Example multi-threaded language implementation:
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 } }
- Parameters:
context
- the context that should be prepared for multi-threading.- Since:
- 0.28
-
initializeThread
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 isinitialized
for the thread the context will be initialized with. If the thread is stored in the context it must be referenced usingWeakReference
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:
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 } }
- Parameters:
context
- the context that is enteredthread
- the thread that accesses the context for the first time.- Since:
- 0.28
-
finalizeThread
The behavior of this notification is different forpolyglot threads
and embedder threads.For
polyglot threads
thefinalizeThread
notification is invoked just before the context is left for the last time in the thread, and it is still safe to run guest code unless the context is cancelled or hard-exited. This allows the language to perform finalization actions for each thread and context. Polyglot threads are finalized before or while the context is finalized and it always holds thatthread == Thread.currentThread()
.Embedder threads are finalized after the context is finalized, but before it is disposed.
thread == Thread.currentThread()
holds only for the embedder thread that performed the context finalization. Finalization of other embedder threads is invoked in the context finalization thread as well, and sothread != Thread.currentThread()
. It is still safe to run guest code infinalizeThread
for an embedder thread unless the context is cancelled or hard-exited, but it is not allowed to initialize new language contexts or create polyglot threads. A language context initialization or creation of a polyglot thread infinalizeThread
for an embedder thread results inIllegalStateException
. Please note that embedder threads may be collected by the garbage collector before they can be finalized and may therefore not be finalized.Thread finalization is invoked before
thread disposal
.- Since:
- 23.1
- See Also:
-
disposeThread
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. Thecurrent thread
may differ from the disposed thread. Disposal of threads is only guaranteed for threads that were created by guest languages, so calledpolyglot 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.- Since:
- 0.28
- See Also:
-
getScope
Get a top scope of the language, if any. The returned object must be aninterop scope object
and may haveparent scopes
. The scope object exposes all top scopes variables as flattenedmembers
. Top scopes are independent of aFrame
. SeeInteropLibrary.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 likeMath
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
TruffleInstrument.Env.getScope(LanguageInfo)
. They are used by debuggers to access the top-most scopes of the language. - Top scopes available in the
polyglot API
as contextbindings
object. Access to members of the bindings object is applied to the returned scope object via interop. - Languages may expose other language scopes using a polyglot bindings builtin. E.g with
TruffleLanguage.Env.getScopePublic(LanguageInfo)
.
- Parameters:
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
- Top scopes are accessible to instruments with
-
isVisible
Decides whether the result of evaluating an interactive source should be printed to stdout. By default this methods returnstrue
claiming all values are visible.This method affects behavior of
Context.eval(org.graalvm.polyglot.Source)
- when evaluating aninteractive source
the result of the evaluation is tested forvisibility
and if the value is found visible, it gets converted to string and printed tostandard 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 theTruffleLanguage.Env.out()
,TruffleLanguage.Env.err()
andTruffleLanguage.Env.in()
streams of the environment. When evaluation is called with aninteractive source
of a language that controls its interactive behavior, it is the responsibility of the language itself to print the result to use theTruffleLanguage.Env.out()
,TruffleLanguage.Env.err()
andTruffleLanguage.Env.in()
streams of the environment.- Parameters:
context
- the execution context for doing the conversionvalue
- the value to check. Either primitive type orTruffleObject
- Returns:
true
if the language implements an interactive response to evaluation of interactive sources.- Since:
- 0.22
-
getLanguageView
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 theinterop 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
. AnAssertionError
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
. Ifnull
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.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(); } } }
- Parameters:
context
- the current context.value
- the value- Since:
- 20.1
- Provide a language specific
-
getCurrentLanguage
@Deprecated(since="21.3") protected static <T extends TruffleLanguage<?>> T getCurrentLanguage(Class<T> languageClass) Deprecated.in 21.3, use static final context references instead. SeeTruffleLanguage.ContextReference
for the new intended usage.- Since:
- 0.27
-
getCurrentContext
@Deprecated(since="21.3") protected static <C,T extends TruffleLanguage<C>> C getCurrentContext(Class<T> languageClass) Deprecated.in 21.3, use static final context references instead. SeeTruffleLanguage.LanguageReference
for the new intended usage.- Since:
- 0.27
-
createContextLocal
@Deprecated protected final <T> ContextLocal<T> createContextLocal(TruffleLanguage.ContextLocalFactory<C, T> factory) Deprecated.Creates a new context local reference for this Truffle language. Starting with JDK 21, using this method leads to a this-escape warning. UseTruffleLanguage.ContextLocalProvider.createContextLocal(TruffleLanguage.ContextLocalFactory)
instead.- Since:
- 20.3
-
createContextThreadLocal
@Deprecated protected final <T> ContextThreadLocal<T> createContextThreadLocal(TruffleLanguage.ContextThreadLocalFactory<C, T> factory) Deprecated.Creates a new context thread local reference for this Truffle language. Starting with JDK 21, using this method leads to a this-escape warning. UseTruffleLanguage.ContextLocalProvider.createContextThreadLocal(TruffleLanguage.ContextThreadLocalFactory)
instead.- Since:
- 20.3
-
getLanguageHome
Returns the home location for this language ornull
if the language home is not set. Languages consumed from the Maven repository typically don't have a language home. For legacy graalvm or standalone builds the language home 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.- Since:
- 19.0
-
getAsynchronousStackDepth
protected final int getAsynchronousStackDepth()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.- Since:
- 20.1.0
- See Also:
-
TruffleLanguageProvider
.