C - internal state of the language associated with every thread that is executing program
parsed by the
languagepublic abstract class TruffleLanguage<C> extends Object
TruffleLanguage.Registration in order to be discoverable by the Polyglot
API.
TruffleLanguage subclasses must provide a public default constructor.
TruffleLanguage.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.
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 :For more information on sharing between multiple contexts please seeTruffleLanguage- I : Instrument - 1 :TruffleInstrument
TruffleLanguage.ContextPolicy.
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.
context creation each language context is provided with
information about the environment environment . Language can optionally declare
configurable options in
TruffleLanguage.getOptionDescriptors().
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.
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.
created and managed by a language for
a context. All internally created threads need to be stopped when the context is
disposed.
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 TruffleLanguage.isThreadAccessAllowed(Thread, boolean) and return true also for
multi-threaded accesses. Initialization actions for multi-threaded access can be performed by
overriding TruffleLanguage.initializeMultiThreading(Object). Threads are
initialized and disposed before and after use with a context. Languages may create new threads if the environment allows it.
for embedding of Truffle languages in Java host applications.| Modifier and Type | Class and Description |
|---|---|
protected static interface |
TruffleLanguage.ContextLocalFactory<C,T>
Context local factory for Truffle languages.
|
static class |
TruffleLanguage.ContextPolicy
Defines the supported policy for reusing
languages per context. |
static class |
TruffleLanguage.ContextReference<C>
Represents a reference to the current context.
|
protected static interface |
TruffleLanguage.ContextThreadLocalFactory<C,T>
Context thread local factory for Truffle languages.
|
static class |
TruffleLanguage.Env
Represents execution environment of the
TruffleLanguage. |
static class |
TruffleLanguage.ExitMode
Mode of exit operation.
|
static class |
TruffleLanguage.InlineParsingRequest
Request for inline parsing.
|
static class |
TruffleLanguage.LanguageReference<L extends TruffleLanguage>
Represents a reference to the current language instance.
|
static class |
TruffleLanguage.ParsingRequest
Request for parsing.
|
static interface |
TruffleLanguage.Provider
Used to register a
TruffleLanguage using a ServiceLoader. |
static interface |
TruffleLanguage.Registration
The annotation to use to register your language to the
Polyglot
API. |
| Modifier | Constructor and Description |
|---|---|
protected |
TruffleLanguage()
Constructor to be called by subclasses.
|
| Modifier and Type | Method and Description |
|---|---|
protected boolean |
areOptionsCompatible(OptionValues firstOptions,
OptionValues newOptions)
|
protected abstract C |
createContext(TruffleLanguage.Env env)
Creates internal representation of the executing context suitable for given environment.
|
protected <T> ContextLocal<T> |
createContextLocal(TruffleLanguage.ContextLocalFactory<C,T> factory)
Creates a new context local reference for this Truffle language.
|
protected <T> ContextThreadLocal<T> |
createContextThreadLocal(TruffleLanguage.ContextThreadLocalFactory<C,T> factory)
Creates a new context thread local reference for this Truffle language.
|
protected void |
disposeContext(C context)
Disposes the context created by
TruffleLanguage.createContext(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 are
finalized. |
protected void |
finalizeContext(C context)
Performs language context finalization actions that are necessary before language contexts
are
disposed. |
protected int |
getAsynchronousStackDepth()
Get the depth of asynchronous stack.
|
protected String |
getLanguageHome()
Returns the home location for this language.
|
protected Object |
getLanguageView(C context,
Object value)
Wraps the value to provide language-specific information for primitive and foreign values.
|
protected OptionDescriptors |
getOptionDescriptors()
Returns a set of option descriptors that are supported by this language.
|
protected Object |
getScope(C context)
Get a top scope of the language, if any.
|
protected void |
initializeContext(C context)
Perform any complex initialization.
|
protected void |
initializeMultipleContexts()
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)
Returns
true if code of this language is allowed to be executed on this thread. |
protected boolean |
isVisible(C context,
Object value)
Decides whether the result of evaluating an interactive source should be printed to stdout.
|
protected ExecutableNode |
parse(TruffleLanguage.InlineParsingRequest request)
Parses the
provided source snippet at the
provided location and generates its appropriate
AST representation. |
protected CallTarget |
parse(TruffleLanguage.ParsingRequest request)
Parses the
provided source and generates its appropriate
AST representation. |
protected boolean |
patchContext(C context,
TruffleLanguage.Env newEnv)
Notifies the language with pre-initialized context about
TruffleLanguage.Env change. |
protected TruffleLanguage()
RootNodes 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 TruffleLanguage.createContext(Env).protected boolean areOptionsCompatible(OptionValues firstOptions, OptionValues newOptions)
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 default implementation returns true.
If the context policy of a language is set to exclusive
(default behavior) then TruffleLanguage.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:
class CompatibleLanguage extendsTruffleLanguage<TruffleLanguage.Env> { @Option(help = "", category =OptionCategory.USER) static finalOptionKey<String> ScriptVersion = newOptionKey<>("ECMA2017"); @Overrideprotected boolean areOptionsCompatible(OptionValuesfirstOptions,OptionValuesnewOptions) { return firstOptions.get(ScriptVersion). equals(newOptions.get(ScriptVersion)); } @OverrideprotectedOptionDescriptorsgetOptionDescriptors() { return new CompatibleLanguageOptionDescriptors(); } }
firstOptions - the options used to create the first context, never nullnewOptions - the options that will be used for the new context, never nullTruffleLanguage.ContextPolicy,
TruffleLanguage.parse(ParsingRequest)protected abstract C createContext(TruffleLanguage.Env env)
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 context
references. 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 TruffleLanguage.initializeContext(java.lang.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.
env - the environment the language is supposed to operate innullprotected void initializeContext(C context) throws Exception
TruffleLanguage.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 later to finish any post initialization
actions. Example:
class PostInitLanguage extendsTruffleLanguage<Context> { @OverrideprotectedContextcreateContext(TruffleLanguage.Envenv) { // "quickly" create the context return newContext(env); } @Overrideprotected void initializeContext(Contextcontext) throwsIOException{ // called "later" to finish the initialization // for example call into another languageSourcesource =Source.newBuilder("js", "function(x, y) x * y", "mul.js").build(); context.mul = context.env.parsePublic(source); } }
context - the context created by
TruffleLanguage.createContext(com.oracle.truffle.api.TruffleLanguage.Env)Exception - if something goes wrongprotected void finalizeContext(C context)
disposed. However, in case the underlying polyglot
context is being cancelled or hard-exited, TruffleLanguage.disposeContext(Object) is called even if
TruffleLanguage.finalizeContext(Object) throws an
AbstractTruffleException or a ThreadDeath
cancel or exit exception.
For the hard exit a language is supposed to run its finalization actions that require running
guest code in TruffleLanguage.exitContext(Object, ExitMode, int), but please note that after
TruffleLanguage.exitContext(Object, ExitMode, int) runs for a language, the language can still be
invoked from TruffleLanguage.exitContext(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, use
TruffleSafepoint.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, an AssertionError is thrown. It's not safe to use the
ExecutorService.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 after TruffleLanguage.finalizeContext(Object) returns, otherwise it is an
internal error.
Non-active inner contexts created by the language that are
still unclosed after TruffleLanguage.finalizeContext(Object) returns are automatically closed by
Truffle.
Typical implementation looks like:
class AsyncThreadLanguage extendsTruffleLanguage<Context> { @OverrideprotectedContextcreateContext(TruffleLanguage.Envenv) { return newContext(env); } @Overrideprotected boolean isThreadAccessAllowed(Threadthread, boolean singleThreaded) { // allow access from any thread instead of just one return true; } @Overrideprotected void initializeContext(Contextcontext) throwsException{ // create and start a Thread for the asynchronous task // remeber the Thread reference to stop and join it in // the finalizeContextThreadt = context.env.createThread(newRunnable() { @Overridepublic void run() { // asynchronous task } }); context.startedThreads.add(t); t.start(); } @Overrideprotected void finalizeContext(Contextcontext) { // stop and join all the created Threads boolean interrupted = false; for (int i = 0; i < context.startedThreads.size();) {ThreadthreadToJoin = context.startedThreads.get(i); try { if (threadToJoin !=Thread.currentThread()) { threadToJoin.interrupt(); threadToJoin.join(); } i++; } catch (InterruptedExceptionie) { interrupted = true; } } if (interrupted) {Thread.currentThread().interrupt(); } } }
context - the context created by
TruffleLanguage.createContext(com.oracle.truffle.api.TruffleLanguage.Env)for specifying language dependencies.protected void exitContext(C context, TruffleLanguage.ExitMode exitMode, int exitCode)
finalized. However, in case the underlying polyglot context
is being cancelled, exit notifications are not
executed. Also, for hard exit, TruffleLanguage.finalizeContext(Object) is
called even if TruffleLanguage.exitContext(Object, ExitMode, int) throws an
AbstractTruffleException or a ThreadDeath
cancel or exit exception. All initialized language contexts must remain usable after exit
notifications. In case a AbstractTruffleException or
the ThreadDeath exit exception is thrown during an hard exit
notification, it is just logged and otherwise ignored and the notification process continues
with the next language in order. In case the ThreadDeath 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 specifying
language 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 in
TruffleLanguage.finalizeContext(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 a
natural exit notification, natural exit notifications for remaining
language contexts are not executed and the hard exit process starts by
executing hard exit notifications. In case
TruffleContext.closeExited(Node, int) is called during a hard
exit notification, it just throws the special ThreadDeath 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 the
ThreadDeath 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.
context - language context.exitMode - mode of exit.exitCode - exit code that was specified for exit.protected void initializeMultipleContexts()
context 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 sharing
TruffleLanguage.initializeMultipleContexts() is invoked. It is guaranteed that sharing between
multiple contexts is initialized before any language
context is created.
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:
protected void disposeContext(C context)
TruffleLanguage.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 TruffleLanguage.finalizeContext(Object) instead. Finalization will be performed
prior to context disposal. However, in case the underlying
polyglot context is being cancelled, TruffleLanguage.disposeContext(Object) is called even if
TruffleLanguage.finalizeContext(Object) throws
AbstractTruffleException or ThreadDeath
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 the language environment.
context - the context created by
TruffleLanguage.createContext(com.oracle.truffle.api.TruffleLanguage.Env)to run finalization code for a context.,
to perform disposal actions when a thread is no longer
used.protected CallTarget parse(TruffleLanguage.ParsingRequest request) throws Exception
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(java.lang.Object...) that accepts as many arguments as were provided
via the TruffleLanguage.ParsingRequest.getArgumentNames() method.
Implement TruffleLanguage.parse(com.oracle.truffle.api.TruffleLanguage.InlineParsingRequest) to
parse source in a specific context location.
request - request for parsingNode tree representing
just parsed codeException - exception can be thrown when parsing goes wrong. Here-in thrown exception
is propagated to the user who called one of eval methods of
ContextTruffleLanguage.Registration.contextPolicy()protected ExecutableNode parse(TruffleLanguage.InlineParsingRequest request) throws Exception
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
TruffleLanguage.InlineParsingRequest.getLocation()). The result should be an AST fragment with method
ExecutableNode.execute(com.oracle.truffle.api.frame.VirtualFrame) that accepts frames
valid at the provided location.
When not implemented, null is returned by default.
protected OptionDescriptors getOptionDescriptors()
environment when the context is
created. To construct option descriptors from a list then
OptionDescriptors.create(List) can be used. Languages must always return the same
option descriptors independent of the language instance or side-effects.For an example of declaring the option descriptor using an annotation.protected boolean patchContext(C context, TruffleLanguage.Env newEnv)
TruffleLanguage.Env change. See
Context for information how to enable the Context
pre-initialization.
During the pre-initialization (in the native compilation time) the
TruffleLanguage.createContext(com.oracle.truffle.api.TruffleLanguage.Env) and
TruffleLanguage.initializeContext(java.lang.Object) methods are called. In the image execution time,
the TruffleLanguage.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 Context.create(java.lang.String...) invocation.
The contexts are patched in a topological order starting from dependent languages. If the
TruffleLanguage.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.
Typical implementation looks like:
@Overrideprotected boolean patchContext(Contextcontext,TruffleLanguage.EnvnewEnv) { 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(Contextcontext,TruffleLanguage.EnvnewEnv) { // Verify that values of important options in the new Env do not differ // from values in the pre-initialized context finalStringnewVersionValue = newEnv.getOptions().get(version); returnObjects.equals(context.languageVersion, newVersionValue); }
context - the context created by
TruffleLanguage.createContext(com.oracle.truffle.api.TruffleLanguage.Env) during
pre-initializationnewEnv - the new environment replacing the environment used in pre-initialization phasefalse to prevent an usage of pre-initialized context by a language which is
not aware of context pre-initialization.protected boolean isThreadAccessAllowed(Thread thread, boolean singleThreaded)
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:
class MultiThreadedLanguage extendsTruffleLanguage<Context> { @OverrideprotectedContextcreateContext(TruffleLanguage.Envenv) { return newContext(env); } @Overrideprotected boolean isThreadAccessAllowed(Threadthread, boolean singleThreaded) { // allow access from any thread instead of just one return true; } @Overrideprotected void initializeMultiThreading(Contextcontext) { // perform actions when the context is switched to multi-threading context.singleThreaded.invalidate(); } @Overrideprotected void initializeThread(Contextcontext,Threadthread) { // perform initialization actions for threads } @Overrideprotected void disposeThread(Contextcontext,Threadthread) { // perform disposal actions for threads } }
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.protected void initializeMultiThreading(C context)
TruffleLanguage.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:
class MultiThreadedLanguage extendsTruffleLanguage<Context> { @OverrideprotectedContextcreateContext(TruffleLanguage.Envenv) { return newContext(env); } @Overrideprotected boolean isThreadAccessAllowed(Threadthread, boolean singleThreaded) { // allow access from any thread instead of just one return true; } @Overrideprotected void initializeMultiThreading(Contextcontext) { // perform actions when the context is switched to multi-threading context.singleThreaded.invalidate(); } @Overrideprotected void initializeThread(Contextcontext,Threadthread) { // perform initialization actions for threads } @Overrideprotected void disposeThread(Contextcontext,Threadthread) { // perform disposal actions for threads } }
context - the context that should be prepared for multi-threading.protected void initializeThread(C context, Thread thread)
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:
class MultiThreadedLanguage extendsTruffleLanguage<Context> { @OverrideprotectedContextcreateContext(TruffleLanguage.Envenv) { return newContext(env); } @Overrideprotected boolean isThreadAccessAllowed(Threadthread, boolean singleThreaded) { // allow access from any thread instead of just one return true; } @Overrideprotected void initializeMultiThreading(Contextcontext) { // perform actions when the context is switched to multi-threading context.singleThreaded.invalidate(); } @Overrideprotected void initializeThread(Contextcontext,Threadthread) { // perform initialization actions for threads } @Overrideprotected void disposeThread(Contextcontext,Threadthread) { // perform disposal actions for threads } }
context - the context that is enteredthread - the thread that accesses the context for the first time.protected void disposeThread(C context, Thread thread)
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.For usage details.protected Object getScope(C context)
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
InteropLibrary.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.
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.
TruffleInstrument.Env.getScope(LanguageInfo).
They are used by debuggers to access the top-most scopes of the language.
polyglot API as context
bindings object. Access to members of the bindings object
is applied to the returned scope object via interop.
context - the context to find the language top scope innull if the language does not support such conceptprotected boolean isVisible(C context, Object value)
true claiming all values are visible.
This method affects behavior of
Context.eval(org.graalvm.polyglot.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 TruffleLanguage.Env.out(), TruffleLanguage.Env.err() and TruffleLanguage.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 TruffleLanguage.Env.out(), TruffleLanguage.Env.err() and
TruffleLanguage.Env.in() streams of the environment.
context - the execution context for doing the conversionvalue - the value to check. Either primitive type or
TruffleObjecttrue if the language implements an interactive response to evaluation of
interactive sources.protected Object getLanguageView(C context, Object value)
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:
display string
for primitive and foreign values.
metaobject for
primitive or foreign 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.
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();
}
}
}
context - the current context.value - the valueprotected final <T> ContextLocal<T> createContextLocal(TruffleLanguage.ContextLocalFactory<C,T> factory)
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 new RootNode(this) { @Override public Object execute(VirtualFrame frame) { // fast read ExampleLocal local = contextLocal.get(); // access local return ""; } }.getCallTarget(); } static final class ExampleLocal { final Env env; ExampleLocal(Env env) { this.env = env; } } }
protected final <T> ContextThreadLocal<T> createContextThreadLocal(TruffleLanguage.ContextThreadLocalFactory<C,T> factory)
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
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.
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 new RootNode(this) { @Override public Object execute(VirtualFrame frame) { // fast read ExampleLocal local = threadLocal.get(); // access local return ""; } }.getCallTarget(); } static final class ExampleLocal { final Env env; final WeakReference thread; ExampleLocal(Env env, Thread thread) { this.env = env; this.thread = new WeakReference<>(thread); } } }
protected final String getLanguageHome()
protected final int getAsynchronousStackDepth()
Override RootNode.findAsynchronousFrames(Frame) to provide the asynchronous stack
frames.
RootNode.findAsynchronousFrames(Frame)