Class TruffleLanguage<C>

java.lang.Object
com.oracle.truffle.api.TruffleLanguage<C>
Type Parameters:
C - internal state of the language associated with every thread that is executing program parsed by the language

public abstract class TruffleLanguage<C> extends Object
A Truffle language implementation contains all the services a language should provide to make it composable with other languages. Implementation classes must be annotated with 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 the 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.

Context Policy and Sharing

The number of TruffleLanguage instances per polyglot context is configured by the context policy. By default an exclusive language instance is created for every polyglot context or inner context. With policy reuse, language instances will be reused after a language context was disposed. With policy shared, a language will also be reused if active contexts are not yet disposed. Language instances will only be shared or reused if they are compatible. Language implementations are encouraged to support the most permissive context policy possible. Please see the individual policies for details on the implications on the language implementation.

The following illustration shows the cardinalities of the individual components:

  N: unbounded
  P: N for exclusive, 1 for shared context policy
  L: number of installed languages
  I: number of installed instruments

  - 1 : Host VM Processs
   - N : Engine
     - N : Context
       - L : Language Context
     - P * L : TruffleLanguage
     - I : Instrument
       - 1 : TruffleInstrument
 
For more information on sharing between multiple contexts please see TruffleLanguage.ContextPolicy.

Parse Caching

The result of the parsing request is cached per language instance, source, argument names and environment options. The scope of the caching is influenced by the context policy. Caching may be disabled for certain sources. It is enabled for new sources by default.

Language Configuration

On context creation each language context is provided with information about the environment environment . Language can optionally declare configurable options in getOptionDescriptors().

Polyglot Bindings

Language implementations communicate with one another (and with instrumentation-based tools such as debuggers) by reading/writing named values into the polyglot bindings. This bindings object is used to implement guest language export/import statements used for language interoperation.

A language implementation can also import or export a global symbol by name. The scope may be accessed from multiple threads at the same time. Existing keys are overwritten.

Configuration vs. Initialization

To ensure that a Truffle language can be used in a language-agnostic way, the implementation should be designed to decouple its configuration and initialization from language specifics as much as possible. One aspect of this is the initialization and start of execution via the Context, which should be designed in a generic way. Language-specific entry points, for instance to emulate the command-line interface of an existing implementation, should be handled externally.

Multi-threading

There are two kinds of threads that access contexts of Truffle guest languages:
  • Internal threads are created and managed by a language for a context. All internally created threads need to be stopped when the context is disposed.
  • External threads are created and managed by the host application / language launcher. The host application is allowed to use language contexts from changing threads, sequentially or at the same time if the language allows it.

By default every context only allows access from one thread at the same time. Therefore if the context is tried to be accessed from multiple threads at the same time the access will fail. Languages that want to allow multi-threaded access to a context may override isThreadAccessAllowed(Thread, boolean) and return true also for multi-threaded accesses. Initialization actions for multi-threaded access can be performed by overriding initializeMultiThreading(Object). Threads are initialized and disposed before and after use with a context. Languages may create new threads if the environment allows it.

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:
  • Field Details

  • Constructor Details

    • TruffleLanguage

      protected TruffleLanguage()
      Constructor to be called by subclasses. Language should not create any 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 createContext(Env).
      Since:
      0.8 or earlier
  • Method Details

    • areOptionsCompatible

      protected boolean areOptionsCompatible(OptionValues firstOptions, OptionValues newOptions)
      Returns true if the combination of two sets of options allow to share or reuse the same language instance, else false. If options are incompatible then a new language instance will be created for a new context. The default implementation returns true.

      If the context policy of a language is set to exclusive (default behavior) then areOptionsCompatible(OptionValues, OptionValues) will never be invoked as TruffleLanguage instances will not be shared for multiple contexts. For the other context policies reuse and shared this method can be used to further restrict the reuse of language instances. Compatibility influences parse caching because it uses the language instance as a key.

      Example usage of areOptionsCompatible if sharing of the language instances and parse caching should be restricted by the script version option:

      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, never null
      newOptions - the options that will be used for the new context, never null
      Since:
      19.0
      See Also:
    • createContext

      protected abstract C createContext(TruffleLanguage.Env env)
      Creates internal representation of the executing context suitable for given environment. Each time the language is used by a new Context, the system calls this method to let the language prepare for execution. The returned execution context is completely language specific; it is however expected it will contain reference to here-in provided env and adjust itself according to parameters provided by the env object.

      The context created by this method is accessible using 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 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.

      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

      protected void initializeContext(C context) throws Exception
      Perform any complex initialization. The 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 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 by createContext(com.oracle.truffle.api.TruffleLanguage.Env)
      Throws:
      Exception - if something goes wrong
      Since:
      0.17
    • finalizeContext

      protected void finalizeContext(C context)
      Performs language context finalization actions that are necessary before language contexts are disposed. However, in case the underlying polyglot context is being cancelled or hard-exited, disposeContext(Object) is called even if 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 exitContext(Object, ExitMode, int), but please note that after exitContext(Object, ExitMode, int) runs for a language, the language can still be invoked from 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 finalizeContext(Object) returns, otherwise it is an internal error.

      Non-active inner contexts created by the language that are still unclosed after finalizeContext(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 by createContext(com.oracle.truffle.api.TruffleLanguage.Env)
      Since:
      0.30
      See Also:
    • exitContext

      protected void exitContext(C context, TruffleLanguage.ExitMode exitMode, int exitCode)
      Performs language exit event actions that are necessary before language contexts are finalized. However, in case the underlying polyglot context is being cancelled, exit notifications are not executed. Also, for hard exit, finalizeContext(Object) is called even if 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 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.

      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 its 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 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:

      • 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

      protected void disposeContext(C context)
      Disposes the context created by 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 finalizeContext(Object) instead. Finalization will be performed prior to context disposal. However, in case the underlying polyglot context is being cancelled, disposeContext(Object) is called even if 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.

      Parameters:
      context - the context created by createContext(com.oracle.truffle.api.TruffleLanguage.Env)
      Since:
      0.8 or earlier
      See Also:
    • parse

      protected CallTarget parse(TruffleLanguage.ParsingRequest request) throws Exception
      Parses the provided source and generates its appropriate AST representation. The parsing should execute no user code, it should only create the Node tree to represent the source. If the provided source does not correspond naturally to a call target, the returned call target should create and if necessary initialize the corresponding language entity and return it.

      The result of the parsing request is cached per language instance, source and argument names. It is safe to assume that current language instance and argument names will remain unchanged for a parsed CallTarget. The scope of the caching is influenced by the context policy and option compatibility. Caching may be disabled for sources. It is enabled for new sources by default.

      The argumentNames may contain symbolic names for actual parameters of the call to the returned value. The result should be a call target with method CallTarget.call(java.lang.Object...) that accepts as many arguments as were provided via the TruffleLanguage.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 parsed code
      Throws:
      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
      Since:
      0.22
      See Also:
    • parse

      Parses the provided source snippet at the provided location and generates its appropriate AST representation. The parsing should execute no user code, it should only create the Node tree to represent the source.

      The parsing should be performed in a context (specified by 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.

      Parameters:
      request - request for parsing
      Returns:
      a fragment to invoke which also keeps in memory the Node tree representing just parsed code, or null when inline parsing of code snippets is not implemented
      Throws:
      Exception - exception can be thrown when parsing goes wrong.
      Since:
      0.31
    • getOptionDescriptors

      protected OptionDescriptors getOptionDescriptors()
      Returns a set of option descriptors that are supported by this language. Option values are accessible using the environment when the context is created. To construct option descriptors from a list then OptionDescriptors.create(List) 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

      protected boolean patchContext(C context, TruffleLanguage.Env newEnv)
      Notifies the language with pre-initialized context about TruffleLanguage.Env change. See Context 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) and initializeContext(java.lang.Object) methods are called. In the image execution time, the 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 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, 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 by createContext(com.oracle.truffle.api.TruffleLanguage.Env) during pre-initialization
      newEnv - the new environment replacing the environment used in pre-initialization phase
      Returns:
      true in case of successful environment update. When the context cannot be updated to a new environment return false to create a new context. By default it returns false to prevent an usage of pre-initialized context by a language which is not aware of context pre-initialization.
      Since:
      0.31
    • isThreadAccessAllowed

      protected boolean isThreadAccessAllowed(Thread thread, boolean singleThreaded)
      Returns true if code of this language is allowed to be executed on this thread. The method returns false to deny execution on this thread. The default implementation denies access to more than one thread at the same time. The current thread may differ from the passed thread. If this method throws an AbstractTruffleException the exception interop messages may be executed without a context being entered.

      Example multi-threaded language implementation:

      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

      protected void initializeMultiThreading(C context)
      Invoked before the context is accessed from multiple threads at the same time. This allows languages to perform actions that are required to support multi-threading. It will never be invoked if isThreadAccessAllowed(Thread, boolean) is implemented to deny access from multiple threads at the same time. All initialized languages must allow multi-threading for this method to be invoked. If this method throws an AbstractTruffleException the exception interop messages may be executed without a context being entered.

      Example multi-threaded language implementation:

      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

      protected void initializeThread(C context, Thread thread)
      Invoked before a context is accessed from a new thread. This allows the language to perform initialization actions for each thread before guest language code is executed. Also for languages that deny access from multiple threads at the same time, multiple threads may be initialized if they are used sequentially. This method will be invoked before the context is initialized for the thread the context will be initialized with. If the thread is stored in the context it must be referenced using WeakReference to avoid leaking thread objects.

      The current thread may differ from the initialized thread.

      If this method throws an AbstractTruffleException the exception interop messages may be executed without a context being entered.

      Example multi-threaded language implementation:

      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 entered
      thread - the thread that accesses the context for the first time.
      Since:
      0.28
    • finalizeThread

      protected void finalizeThread(C context, Thread thread)
      The behavior of this notification is different for polyglot threads and embedder threads.

      For polyglot threads the finalizeThread 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 that thread == 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 so thread != Thread.currentThread(). It is still safe to run guest code in finalizeThread 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 in finalizeThread for an embedder thread results in IllegalStateException. 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

      protected void disposeThread(C context, Thread thread)
      Invoked the last time code will be executed for this thread and context. This allows the language to perform cleanup actions for each thread and context. Threads might be disposed before after or while a context is disposed. The current thread may differ from the disposed thread. Disposal of threads is only guaranteed for threads that were created by guest languages, so called polyglot threads. Other threads, created by the embedder, may be collected by the garbage collector before they can be disposed and may therefore not be disposed.
      Since:
      0.28
      See Also:
    • getScope

      protected Object getScope(C context)
      Get a top scope of the language, if any. The returned object must be an interop scope object and may have parent scopes. The scope object exposes all top scopes variables as flattened members. Top scopes are independent of a Frame. See 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.

      Interpretation

      In most languages, just evaluating an expression like Math is equivalent of a lookup with the identifier 'Math' in the top-most scopes of the language. Looking up the identifier 'Math' should have equivalent semantics as reading with the key 'Math' from the variables object of one of the top-most scopes of the language. In addition languages may optionally allow modification and insertion with the variables object of the returned top-scopes.

      Languages may want to specify multiple parent top-scopes. It is recommended to stay as close as possible to the set of top-scopes that as is described in the guest language specification, if available. For example, in JavaScript, there is a 'global environment' and a 'global object' scope. While the global environment scope contains class declarations and is not insertable, the global object scope is used to insert new global variable values and is therefore insertable.

      Use Cases

      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
    • isVisible

      protected boolean isVisible(C context, Object value)
      Decides whether the result of evaluating an interactive source should be printed to stdout. By default this methods returns true claiming all values are visible.

      This method affects behavior of Context.eval(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.

      Parameters:
      context - the execution context for doing the conversion
      value - the value to check. Either primitive type or TruffleObject
      Returns:
      true if the language implements an interactive response to evaluation of interactive sources.
      Since:
      0.22
    • getLanguageView

      protected Object getLanguageView(C context, Object value)
      Wraps the value to provide language-specific information for primitive and foreign values. Foreign values should be enhanced to look like the most generic object type of the language. The wrapper needs to introduce any "virtual" methods and properties that are commonly used in language constructs and in algorithms that are written to work on this generic object type. The wrapper may add or remove existing interop traits, but it is not allowed to change the interop type. For example, it is not allowed to change the type from number to string. If the behavior of an existing trait is modified then all writes on the mapper need to be forwarded to the underlying object, apart from the virtual members. Writes to the virtual members should be persisted in the wrapper if this is the behavior of the object type that is being mapped to.

      Every language view wrapper must return the current language as their associated language. An AssertionError is thrown when a language view is requested if this contract is violated.

      Example modifications language view wrappers may perform:

      • Provide a language specific display string for primitive and foreign values.
      • Return a language specific metaobject for primitive or foreign values.
      • Add virtual members to the object for the view. For example, any JavaScript object is expected to have an implicit __proto__ member. Foreign objects, even if they do not have such a member, are interpreted as if they have.
      • There are languages where all scalar values are also vectors. In such a case the array element trait may be added using the language wrapper to such values.

      The default implementation returns null. If null is returned then the default language view will be used. The default language view wraps the value and returns the current language as their associated language. With the default view wrapper all interop library messages will be forwarded to the delegate value.

      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
    • 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. See TruffleLanguage.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. See TruffleLanguage.LanguageReference for the new intended usage.
      Since:
      0.27
    • createContextLocal

      @Deprecated protected final <T> ContextLocal<T> createContextLocal(TruffleLanguage.ContextLocalFactory<C,T> factory)
      Creates a new context local reference for this Truffle language. Starting with JDK 21, using this method leads to a this-escape warning. Use TruffleLanguage.ContextLocalProvider.createContextLocal(TruffleLanguage.ContextLocalFactory) instead.
      Since:
      20.3
    • createContextThreadLocal

      @Deprecated protected final <T> ContextThreadLocal<T> createContextThreadLocal(TruffleLanguage.ContextThreadLocalFactory<C,T> factory)
      Creates a new context thread local reference for this Truffle language. Starting with JDK 21, using this method leads to a this-escape warning. Use TruffleLanguage.ContextLocalProvider.createContextThreadLocal(TruffleLanguage.ContextThreadLocalFactory) instead.
      Since:
      20.3
    • getLanguageHome

      protected final String getLanguageHome()
      Returns the home location for this language or null 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: