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.
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.
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.
|
protected static class |
TruffleLanguage.ContextLocalProvider<C>
Provider for creating context local and context thread local references.
|
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.Registration
The annotation to use to register your language to the
Polyglot
API . |
Modifier and Type | Field and Description |
---|---|
protected TruffleLanguage.ContextLocalProvider<C> |
locals
Provider for creating context local and context thread local references.
|
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 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 final TruffleLanguage.ContextLocalProvider<C> locals
protected TruffleLanguage()
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 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"); @Override
protected boolean areOptionsCompatible(OptionValues
firstOptions,OptionValues
newOptions) { return firstOptions.get(ScriptVersion). equals(newOptions.get(ScriptVersion)); } @Override
protectedOptionDescriptors
getOptionDescriptors() { return new CompatibleLanguageOptionDescriptors(); } }
firstOptions
- the options used to create the first context, never null
newOptions
- the options that will be used for the new context, never null
TruffleLanguage.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 innull
protected 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
> { @Override
protectedContext
createContext(TruffleLanguage.Env
env) { // "quickly" create the context return newContext
(env); } @Override
protected void initializeContext(Context
context) throwsIOException
{ // called "later" to finish the initialization // for example call into another languageSource
source =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
> { @Override
protectedContext
createContext(TruffleLanguage.Env
env) { return newContext
(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) throwsException
{ // create and start a Thread for the asynchronous task // remeber the Thread reference to stop and join it in // the finalizeContextThread
t = context.env.newTruffleThreadBuilder(newRunnable
() { @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(); } } }
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 code
Exception
- exception can be thrown when parsing goes wrong. Here-in thrown exception
is propagated to the user who called one of eval
methods of
Context
TruffleLanguage.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:
@Override
protected boolean patchContext(Context
context,TruffleLanguage.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,TruffleLanguage.Env
newEnv) { // Verify that values of important options in the new Env do not differ // from values in the pre-initialized context finalString
newVersionValue = 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
> { @Override
protectedContext
createContext(TruffleLanguage.Env
env) { return newContext
(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 } }
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
> { @Override
protectedContext
createContext(TruffleLanguage.Env
env) { return newContext
(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 } }
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
> { @Override
protectedContext
createContext(TruffleLanguage.Env
env) { return newContext
(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 } }
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
TruffleObject
true
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 String getLanguageHome()
protected final int getAsynchronousStackDepth()
Override RootNode.findAsynchronousFrames(Frame)
to provide the asynchronous stack
frames.
RootNode.findAsynchronousFrames(Frame)