Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
* Copyright (c) 2014, 2022, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* The Universal Permissive License (UPL), Version 1.0
*
* Subject to the condition set forth below, permission is hereby granted to any
* person obtaining a copy of this software, associated documentation and/or
* data (collectively the "Software"), free of charge and under any and all
* copyright rights in the Software, and any and all patent rights owned or
* freely licensable by each licensor hereunder covering either (i) the
* unmodified Software as contributed to or provided by such licensor, or (ii)
* the Larger Works (as defined below), to deal in both
*
* (a) the Software, and
*
* (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if
* one is included with the Software each a "Larger Work" to which the Software
* is contributed by such licensors),
*
* without restriction, including without limitation the rights to copy, create
* derivative works of, display, perform, and distribute the Software and make,
* use, sell, offer for sale, import, export, have made, and have sold the
* Software and the Larger Work(s), and to sublicense the foregoing rights on
* either these or other terms.
*
* This license is subject to the following condition:
*
* The above copyright notice and either this complete permission notice or at a
* minimum a reference to the UPL must be included in all copies or substantial
* portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package org.pkl.thirdparty.truffle.api;
import static org.pkl.thirdparty.truffle.api.LanguageAccessor.ENGINE;
import static java.util.concurrent.TimeUnit.SECONDS;
import java.io.Closeable;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.ref.WeakReference;
import java.net.URI;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;
import java.nio.file.attribute.FileAttribute;
import java.time.ZoneId;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.ServiceLoader;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.function.BiFunction;
import java.util.function.Consumer;
import java.util.function.Predicate;
import java.util.logging.Level;
import org.pkl.thirdparty.graalvm.home.Version;
import org.pkl.thirdparty.graalvm.options.OptionCategory;
import org.pkl.thirdparty.graalvm.options.OptionDescriptor;
import org.pkl.thirdparty.graalvm.options.OptionDescriptors;
import org.pkl.thirdparty.graalvm.options.OptionKey;
import org.pkl.thirdparty.graalvm.options.OptionValues;
import org.pkl.thirdparty.graalvm.polyglot.Context;
import org.pkl.thirdparty.graalvm.polyglot.Context.Builder;
import org.pkl.thirdparty.graalvm.polyglot.Engine;
import org.pkl.thirdparty.graalvm.polyglot.EnvironmentAccess;
import org.pkl.thirdparty.graalvm.polyglot.Language;
import org.pkl.thirdparty.graalvm.polyglot.PolyglotException;
import org.pkl.thirdparty.graalvm.polyglot.SandboxPolicy;
import org.pkl.thirdparty.graalvm.polyglot.Value;
import org.pkl.thirdparty.graalvm.polyglot.io.FileSystem;
import org.pkl.thirdparty.graalvm.polyglot.io.IOAccess;
import org.pkl.thirdparty.truffle.api.CompilerDirectives.CompilationFinal;
import org.pkl.thirdparty.truffle.api.CompilerDirectives.TruffleBoundary;
import org.pkl.thirdparty.truffle.api.TruffleFile.FileSystemContext;
import org.pkl.thirdparty.truffle.api.TruffleFile.FileTypeDetector;
import org.pkl.thirdparty.truffle.api.TruffleLanguage.Env;
import org.pkl.thirdparty.truffle.api.TruffleSafepoint.Interrupter;
import org.pkl.thirdparty.truffle.api.TruffleSafepoint.Interruptible;
import org.pkl.thirdparty.truffle.api.frame.Frame;
import org.pkl.thirdparty.truffle.api.frame.MaterializedFrame;
import org.pkl.thirdparty.truffle.api.frame.VirtualFrame;
import org.pkl.thirdparty.truffle.api.impl.ReadOnlyArrayList;
import org.pkl.thirdparty.truffle.api.io.TruffleProcessBuilder;
import org.pkl.thirdparty.truffle.api.nodes.ExecutableNode;
import org.pkl.thirdparty.truffle.api.nodes.LanguageInfo;
import org.pkl.thirdparty.truffle.api.nodes.Node;
import org.pkl.thirdparty.truffle.api.nodes.RootNode;
import org.pkl.thirdparty.truffle.api.source.Source;
/**
* A Truffle language implementation contains all the services a language should provide to make it
* composable with other languages. Implementation classes must be annotated with
* {@link Registration} in order to be discoverable by the {@linkplain org.pkl.thirdparty.graalvm.polyglot Polyglot
* API}.
*
* {@link 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
* {@link 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
* {@linkplain org.pkl.thirdparty.graalvm.polyglot.Language descriptor} for each. The descriptor holds the
* language's registered metadata, but its execution environment is not initialized until the
* language is needed for code execution. That execution environment remains initialized for the
* lifetime of the engine and is isolated from the environment in any other engine instance.
*
* Language global state can be shared between multiple context instances by saving them in a custom
* field of the {@link TruffleLanguage} subclass. Languages may control sharing between multiple
* contexts using its {@link Registration#contextPolicy() context policy}. By default the context
* policy is {@link ContextPolicy#EXCLUSIVE exclusive}: each context has its own separate
* TruffleLanguage instance.
*
* If the context policy is more permissive then the implementation needs to manually ensure data
* isolation between the contexts. This means that state associated with a context must not be
* stored in a TruffleLanguage subclass. ASTs and assumptions can be shared across multiple contexts
* if modifying them does not affect language semantics. Languages are strongly discouraged from
* using static mutable state in their languages. Instead {@link TruffleLanguage} instances should
* be used instead to store global state and their sharing should be configured using
* {@link Registration#contextPolicy() context policy}.
*
* Whenever an engine is disposed then each initialized language context will be
* {@link #disposeContext(Object) disposed}.
*
*
*
Context Policy and Sharing
*
* The number of {@link TruffleLanguage} instances per polyglot {@link org.pkl.thirdparty.graalvm.polyglot.Context
* context} is configured by the {@link Registration#contextPolicy() context policy}. By default an
* {@link ContextPolicy#EXCLUSIVE exclusive} {@link TruffleLanguage language} instance is created
* for every {@link org.pkl.thirdparty.graalvm.polyglot.Context polyglot context} or
* {@link TruffleLanguage.Env#newInnerContextBuilder(String...) inner context}. With policy
* {@link ContextPolicy#REUSE reuse}, language instances will be reused after a language context was
* {@link TruffleLanguage#disposeContext(Object) disposed}. With policy {@link ContextPolicy#SHARED
* shared}, a language will also be reused if active contexts are not yet disposed. Language
* instances will only be shared or reused if they are
* {@link TruffleLanguage#areOptionsCompatible(OptionValues, OptionValues) compatible}. Language
* implementations are encouraged to support the most permissive context policy possible. Please see
* the individual {@link ContextPolicy policies} for details on the implications on the language
* implementation.
*
* 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 : {@linkplain org.pkl.thirdparty.graalvm.polyglot.Engine Engine}
* - N : {@linkplain org.pkl.thirdparty.graalvm.polyglot.Context Context}
* - L : Language Context
* - P * L : {@link TruffleLanguage TruffleLanguage}
* - I : {@linkplain org.pkl.thirdparty.graalvm.polyglot.Instrument Instrument}
* - 1 : {@link org.pkl.thirdparty.truffle.api.instrumentation.TruffleInstrument TruffleInstrument}
*
*
* For more information on sharing between multiple contexts please see {@link ContextPolicy}.
*
*
Parse Caching
*
* The result of the {@link #parse(ParsingRequest) parsing request} is cached per language instance,
* {@link ParsingRequest#getSource() source}, {@link ParsingRequest#getArgumentNames() argument
* names} and environment {@link Env#getOptions() options}. The scope of the caching is influenced
* by the {@link Registration#contextPolicy() context policy}. Caching may be
* {@link Source#isCached() disabled} for certain sources. It is enabled for new sources by default.
*
*
Language Configuration
*
* On {@link #createContext(Env) context creation} each language context is provided with
* information about the environment {@link Env environment }. Language can optionally declare
* {@link org.pkl.thirdparty.graalvm.polyglot.Context.Builder#option(String, String) configurable} options in
* {@link #getOptionDescriptors()}.
*
*
Polyglot Bindings
*
* Language implementations communicate with one another (and with instrumentation-based tools such
* as debuggers) by reading/writing named values into the {@link Env#getPolyglotBindings() polyglot
* bindings}. This bindings object is used to implement guest language export/import statements used
* for language interoperation.
*
* A language implementation can also {@linkplain Env#importSymbol(String) import} or
* {@linkplain Env#exportSymbol(String, Object) export} a global symbol by name. The scope may be
* accessed from multiple threads at the same time. Existing keys are overwritten.
*
*
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
* {@link org.pkl.thirdparty.graalvm.polyglot.Context}, which should be designed in a generic way.
* Language-specific entry points, for instance to emulate the command-line interface of an existing
* implementation, should be handled externally.
*
*
Multi-threading
*
* There are two kinds of threads that access contexts of Truffle guest languages:
*
*
Internal threads are {@link Env#createThread(Runnable) created} and managed by a language for
* a context. All internally created threads need to be stopped when the context is
* {@link #disposeContext(Object) disposed}.
*
External threads are created and managed by the host application / language launcher. The
* host application is allowed to use language contexts from changing threads, sequentially or at
* the same time if the language {@link #isThreadAccessAllowed(Thread, boolean) allows} it.
*
*
* By default every {@link #createContext(Env) context} only allows access from one thread at the
* same time. Therefore if the context is tried to be accessed from multiple threads at the same
* time the access will fail. Languages that want to allow multi-threaded access to a context may
* override {@link #isThreadAccessAllowed(Thread, boolean)} and return true also for
* multi-threaded accesses. Initialization actions for multi-threaded access can be performed by
* overriding {@link #initializeMultiThreading(Object)}. Threads are
* {@link #initializeThread(Object, Thread) initialized} and {@link #disposeContext(Object)
* disposed} before and after use with a context. Languages may {@link Env#createThread(Runnable)
* create} new threads if the environment {@link Env#isCreateThreadAllowed() allows} it.
*
* @param internal state of the language associated with every thread that is executing program
* {@link #parse(org.pkl.thirdparty.truffle.api.TruffleLanguage.ParsingRequest) parsed} by the
* language
* @see org.pkl.thirdparty.graalvm.polyglot.Context for embedding of Truffle languages in Java host applications.
* @since 0.8 or earlier
*/
@SuppressWarnings({"javadoc"})
public abstract class TruffleLanguage {
// get and isFinal are frequent operations -> cache the engine access call
@CompilationFinal LanguageInfo languageInfo;
@CompilationFinal Object polyglotLanguageInstance;
List> contextThreadLocals;
List> contextLocals;
/**
* Constructor to be called by subclasses. Language should not create any {@link RootNode}s in
* its constructor. The RootNodes created in the language constructor are not associated with a
* Context and they don't respect Context's engine options. The needed RootNodes can be created
* in the {@link #createContext(Env)}.
*
* @since 0.8 or earlier
*/
protected TruffleLanguage() {
}
/**
* The annotation to use to register your language to the {@link org.pkl.thirdparty.graalvm.polyglot Polyglot
* API}. By annotating your implementation of {@link TruffleLanguage} by this annotation the
* language can be discovered on the class path.
*
* @since 0.8 or earlier
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Registration {
/**
* Unique id of your language. This id will be exposed to users via the getter. It is used
* as group identifier for options of the language.
*
* @return identifier of your language
* @since 0.8 or earlier
*/
String id() default "";
/**
* Unique name of your language. This name will be exposed to users via the
* {@link org.pkl.thirdparty.graalvm.polyglot.Language#getName()} getter.
*
* @return identifier of your language
* @since 0.8 or earlier
*/
String name() default "";
/**
* Unique name of your language implementation.
*
* @return the implementation name of your language
* @since 0.8 or earlier
*/
String implementationName() default "";
/**
* Unique string identifying the language version. This name will be exposed to users via
* the {@link org.pkl.thirdparty.graalvm.polyglot.Language#getVersion()} getter. It inherits from
* {@link org.pkl.thirdparty.graalvm.polyglot.Engine#getVersion()} by default.
*
* @return version of your language
* @since 0.8 or earlier
*/
String version() default "inherit";
/**
* Returns the default MIME type of this language. The default MIME type allows embedders
* and other language or instruments to find out how content is interpreted if no MIME type
* was specified. The default MIME type must be specified in the list of supported
* {@link #characterMimeTypes() character} or {@link #byteMimeTypes() byte} based MIME
* types.
*
* The default MIME type is mandatory if more than one supported MIME type was specified. If
* no default MIME type and no supported MIME types were specified then all sources for this
* language will be interpreted as {@link Source#hasCharacters() character} based sources.
*
* @see LanguageInfo#getDefaultMimeType()
* @see Language#getDefaultMimeType()
* @see #characterMimeTypes()
* @see #byteMimeTypes()
* @since 19.0
*/
String defaultMimeType() default "";
/**
* List of MIME types supported by this language which sources should be interpreted as
* {@link Source#hasCharacters() character} based sources. Languages may use MIME types to
* differentiate supported source kinds. If a MIME type is declared as supported then the
* language needs to be able to {@link TruffleLanguage#parse(ParsingRequest) parse} sources
* of this kind. If only one supported MIME type was specified by a language then it will be
* used as {@link #defaultMimeType() default} MIME type. If no supported character and byte
* based MIME types are specified then all sources will be interpreted as
* {@link Source#hasCharacters() character} based.
*
* @return array of MIME types assigned to your language files
* @see #defaultMimeType()
* @see #byteMimeTypes()
* @since 19.0
*/
String[] characterMimeTypes() default {};
/**
* List of MIME types supported by this language which sources should be interpreted as
* {@link Source#hasBytes() byte} based sources. Languages may use MIME types to
* differentiate supported source kinds. If a MIME type is declared as supported then the
* language needs to be able to {@link TruffleLanguage#parse(ParsingRequest) parse} sources
* of this kind. If only one supported MIME type was specified by a language then it will be
* used as {@link #defaultMimeType() default} MIME type. If no supported character and byte
* based MIME types are specified then all sources will be interpreted as
* {@link Source#hasCharacters() character} based.
*
* @return array of MIME types assigned to your language files
* @see #defaultMimeType()
* @see #characterMimeTypes()
* @since 19.0
*/
String[] byteMimeTypes() default {};
/**
* Specifies if the language is suitable for interactive evaluation of {@link Source
* sources}. {@link #interactive() Interactive} languages should be displayed in interactive
* environments and presented to the user. The default value of this attribute is
* true assuming majority of the languages is interactive. Change the value to
* false to opt-out and turn your language into non-interactive one.
*
* @return true if the language should be presented to end-user in an
* interactive environment
* @since 0.22
*/
boolean interactive() default true;
/**
* Returns true if this language is intended for internal use only. Internal
* languages cannot be used in the host environment directly, they can only be used from
* other languages or from instruments.
*
* @since 0.27
*/
boolean internal() default false;
/**
* Specifies a list of languages that this language depends on. Languages are referenced
* using their {@link #id()}. This has the following effects:
*
*
This language always has access to dependent languages if this language is
* accessible. Languages may not be accessible if language access is
* {@link org.pkl.thirdparty.graalvm.polyglot.Context#create(String...) restricted}.
*
This language is finalized before dependent language contexts are
* {@link TruffleLanguage#finalizeContext(Object) finalized}.
*
This language is disposed before dependent language contexts are
* {@link TruffleLanguage#disposeContext(Object) disposed}.
*
*
* {@link #internal() Non-internal} languages implicitly depend on all internal languages.
* Therefore by default non-internal languages are disposed and finalized before internal
* languages.
*
* Dependent languages should be parsed with {@link Env#parseInternal(Source, String...)} as
* the embedder might choose to disable access to it for
* {@link Env#parsePublic(Source, String...)}.
*
* Dependent languages references are optional. If a dependent language is not installed and
* the language needs to fail in such a case then the language should fail on
* {@link TruffleLanguage#initializeContext(Object) context initialization}. Cycles in
* dependencies will cause an {@link IllegalStateException} when one of the cyclic languages
* is {@link org.pkl.thirdparty.graalvm.polyglot.Context#initialize(String) initialized}.
*
* @since 0.30
*/
String[] dependentLanguages() default {
};
/**
* Defines the supported policy for reusing {@link TruffleLanguage languages} per context.
* I.e. the policy specifies the degree of sharing that is allowed between multiple language
* contexts. The default policy is {@link ContextPolicy#EXCLUSIVE exclusive}. Every language
* is encouraged to try to support a context policy that is as permissive as possible, where
* {@link ContextPolicy#EXCLUSIVE exclusive} is the least and {@link ContextPolicy#SHARED
* shared} is the most permissive policy. {@link TruffleLanguage#parse(ParsingRequest) Parse
* caching} is scoped per {@link TruffleLanguage language} instance, therefore the context
* policy influences its behavior.
*
* The context policy applies to contexts that were created using the
* {@link org.pkl.thirdparty.graalvm.polyglot.Context polyglot API} as well as for {@link TruffleContext
* inner contexts}. The context policy does not apply to nodes that were created using the
* Truffle interop protocol. Therefore, interop message nodes always need to be prepared to
* be used with policy {@link ContextPolicy#SHARED}.
*
* @see TruffleLanguage#parse(ParsingRequest)
* @since 19.0
*/
ContextPolicy contextPolicy() default ContextPolicy.EXCLUSIVE;
/**
* Declarative list of classes this language is known to provide. The language is supposed
* to override its {@link #createContext(org.pkl.thirdparty.truffle.api.TruffleLanguage.Env)
* createContext} method and instantiate and {@link Env#registerService(java.lang.Object)
* register} all here in defined services.
*
* Languages automatically get created but not yet initialized when their registered
* {@link Env#lookup(org.pkl.thirdparty.truffle.api.nodes.LanguageInfo, java.lang.Class) service is
* requested}.
*
* @since 19.0
* @return list of service types that this language can provide
*/
Class>[] services() default {};
/**
* Declarative list of {@link TruffleFile.FileTypeDetector} classes provided by this
* language.
*
* The language has to support all MIME types recognized by the registered
* {@link TruffleFile.FileTypeDetector file type detectors}.
*
* @return list of file type detectors
* @since 19.0
*/
Class extends TruffleFile.FileTypeDetector>[] fileTypeDetectors() default {};
/**
* Returns {@code true} if the language uses {@code TruffleString}s with encodings not
* present in the following list.
*
*
{@code UTF-8}
*
{@code UTF-16}
*
{@code UTF-32}
*
{@code ISO-8859-1}
*
{@code US-ASCII}
*
{@code BYTES}
*
*
* @since 22.1
*/
boolean needsAllEncodings() default false;
/**
* A link to a website with more information about the language. Will be shown in the help
* text of GraalVM launchers.
*
* The link can contain the following substitutions:
*
*
{@code ${graalvm-version}}
*
the current GraalVM version. Optionally, a format string can be provided for the
* version using {@code ${graalvm-version:format}}. See {@link Version#format}.
*
{@code ${graalvm-website-version}}
*
the current GraalVM version in a format suitable for links to the GraalVM reference
* manual. The exact format may change without notice.
*
*
* @since 22.1.0
* @return URL for language website.
*/
String website() default "";
/**
* Specifies the most strict sandbox policy in which the language can be used. The language
* can be used in a context with the specified sandbox policy or a weaker one. For example,
* if a language specifies {@code ISOLATED} policy, it can be used in a context configured
* with sandbox policy {@code TRUSTED}, {@code CONSTRAINED} or {@code ISOLATED}. But it
* cannot be used in a context configured with the {@code UNTRUSTED} sandbox policy.
*
* @see SandboxPolicy
* @since 23.0
*/
SandboxPolicy sandbox() default SandboxPolicy.TRUSTED;
}
/**
* Used to register a {@link TruffleLanguage} using a {@link ServiceLoader}. This interface is
* not intended to be implemented directly by a language developer, rather the implementation is
* generated by the Truffle DSL. The generated implementation has to inherit the
* {@link Registration} and {@code ProvidedTags} annotations from the {@link TruffleLanguage}.
*
* @since 19.3.0
*/
public interface Provider {
/**
* Returns the name of a class implementing the {@link TruffleLanguage}.
*
* @since 19.3.0
*/
String getLanguageClassName();
/**
* Creates a new instance of a {@link TruffleLanguage}.
*
* @since 19.3.0
*/
TruffleLanguage> create();
/**
* Creates file type detectors used by the {@link TruffleLanguage}.
*
* @since 19.3.0
*/
List createFileTypeDetectors();
/**
* Returns the class names of provided services.
*
* @since 19.3.0
*/
Collection getServicesClassNames();
}
/**
* Returns true if the combination of two sets of options allow to
* {@link ContextPolicy#SHARED share} or {@link ContextPolicy#REUSE 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 {@link ContextPolicy#EXCLUSIVE exclusive}
* (default behavior) then {@link #areOptionsCompatible(OptionValues, OptionValues)} will never
* be invoked as {@link TruffleLanguage} instances will not be shared for multiple contexts. For
* the other context policies {@link ContextPolicy#REUSE reuse} and {@link ContextPolicy#SHARED
* shared} this method can be used to further restrict the reuse of language instances.
* Compatibility influences {@link #parse(ParsingRequest) parse caching} because it uses the
* {@link TruffleLanguage language} instance as a key.
*
* Example usage of areOptionsCompatible if sharing of the language instances and parse caching
* should be restricted by the script version option:
*
* {@link TruffleLanguageSnippets.CompatibleLanguage#areOptionsCompatible}
*
* @param firstOptions the options used to create the first context, never null
* @param newOptions the options that will be used for the new context, never null
* @see ContextPolicy
* @see #parse(ParsingRequest)
* @since 19.0
*/
protected boolean areOptionsCompatible(OptionValues firstOptions, OptionValues newOptions) {
return true;
}
/**
* Creates internal representation of the executing context suitable for given environment. Each
* time the {@link TruffleLanguage language} is used by a new
* {@link org.pkl.thirdparty.graalvm.polyglot.Context}, the system calls this method to let the
* {@link TruffleLanguage 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 {@link ContextReference context
* references}. An {@link 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
* {@link Env#parsePublic(org.pkl.thirdparty.truffle.api.source.Source, java.lang.String...) calls into
* other languages} and assuming your language is already initialized and others can see it
* would be wrong - until you return from this method, the initialization isn't over. The same
* is true for instrumentation, the instruments cannot receive any meta data about code executed
* during context creation. Should there be a need to perform complex initialization, do it by
* overriding the {@link #initializeContext(java.lang.Object)} method.
*
* Additional services provided by the language must be
* {@link Env#registerService(java.lang.Object) registered} by this method otherwise
* {@link IllegalStateException} is thrown.
*
* May return {@code null} if the language does not need any per-{@linkplain Context context}
* state. Otherwise it should return a new object instance every time it is called.
*
* @param env the environment the language is supposed to operate in
* @return internal data of the language in given environment or {@code null}
* @since 0.8 or earlier
*/
protected abstract C createContext(Env env);
/**
* Perform any complex initialization. The
* {@link #createContext(org.pkl.thirdparty.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:
*
* {@link TruffleLanguageSnippets.PostInitLanguage#createContext}
*
* @param context the context created by
* {@link #createContext(org.pkl.thirdparty.truffle.api.TruffleLanguage.Env)}
* @throws java.lang.Exception if something goes wrong
* @since 0.17
*/
protected void initializeContext(C context) throws Exception {
}
/**
* Performs language context finalization actions that are necessary before language contexts
* are {@link #disposeContext(Object) disposed}. However, in case the underlying polyglot
* context is being cancelled or hard-exited, {@link #disposeContext(Object)} is called even if
* {@link #finalizeContext(Object)} throws an
* {@link org.pkl.thirdparty.truffle.api.exception.AbstractTruffleException} or a {@link ThreadDeath}
* cancel or exit exception.
*
* For the hard exit a language is supposed to run its finalization actions that require running
* guest code in {@link #exitContext(Object, ExitMode, int)}, but please note that after
* {@link #exitContext(Object, ExitMode, int)} runs for a language, the language can still be
* invoked from {@link #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
* {@link TruffleSafepoint safepoint}. If there is guest code that always needs to run even if
* cancelled, e.g. to prevent resource leakage, use
* {@link 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 {@link Registration#dependentLanguages() 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 {@link Env#createThread(Runnable) created} by the language must be stopped and
* joined during finalizeContext. The languages are responsible for fulfilling that contract,
* otherwise, an {@link AssertionError} is thrown. It's not safe to use the
* {@link ExecutorService#awaitTermination(long, java.util.concurrent.TimeUnit)} to detect
* Thread termination as the polyglot thread may be cancelled before executing the executor
* worker.
*
* During finalizeContext, all unclosed inner contexts
* {@link Env#newInnerContextBuilder(String...) created} by the language must be left on all
* threads where the contexts are still active. No active inner context is allowed after
* {@link #finalizeContext(Object)} returns, otherwise it is an internal error.
*
* Non-active inner contexts {@link Env#newInnerContextBuilder(String...) created} by the
* language that are still unclosed after {@link #finalizeContext(Object)} returns are
* automatically closed by Truffle.
*
* Typical implementation looks like:
*
* {@link TruffleLanguageSnippets.AsyncThreadLanguage#finalizeContext}
*
* @see Registration#dependentLanguages() for specifying language dependencies.
* @param context the context created by
* {@link #createContext(org.pkl.thirdparty.truffle.api.TruffleLanguage.Env)}
* @since 0.30
*/
protected void finalizeContext(C context) {
}
/**
* Performs language exit event actions that are necessary before language contexts are
* {@link #finalizeContext(Object) finalized}. However, in case the underlying polyglot context
* is being cancelled, {@link #exitContext(Object, ExitMode, int) exit notifications} are not
* executed. Also, for {@link ExitMode#HARD hard exit}, {@link #finalizeContext(Object)} is
* called even if {@link #exitContext(Object, ExitMode, int)} throws an
* {@link org.pkl.thirdparty.truffle.api.exception.AbstractTruffleException} or a {@link ThreadDeath}
* cancel or exit exception. All initialized language contexts must remain usable after exit
* notifications. In case a {@link org.pkl.thirdparty.truffle.api.exception.AbstractTruffleException} or
* the {@link ThreadDeath} exit exception is thrown during an {@link ExitMode#HARD hard exit
* notification}, it is just logged and otherwise ignored and the notification process continues
* with the next language in order. In case the {@link 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
* {@link Registration#dependentLanguages() 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 {@link ExitMode#HARD hard exit} notification, a language is supposed to run its
* finalization actions that require running guest code instead of running them in
* {@link #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 {@link TruffleContext#closeExited(Node, int)} is called during a
* {@link ExitMode#NATURAL natural exit} notification, natural exit notifications for remaining
* language contexts are not executed and the {@link ExitMode#HARD hard exit} process starts by
* executing {@link ExitMode#HARD hard exit} notifications. In case
* {@link TruffleContext#closeExited(Node, int)} is called during a {@link ExitMode#HARD hard
* exit} notification, it just throws the special {@link ThreadDeath} exit exception, which is
* then just logged as described above.
*
* In case the underlying polyglot context is cancelled by e.g.
* {@link TruffleContext#closeCancelled(Node, String)} during exit notifications, guest code
* executed during exit notification is regularly cancelled, i.e., throws the
* {@link ThreadDeath} cancel exception, and the notification process does not continue as
* described above.
*
* In the case of {@link ExitMode#HARD 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.
*
* @param context language context.
* @param exitMode mode of exit.
* @param exitCode exit code that was specified for exit.
* @see Context
* Exit
*
* @since 22.0
*/
protected void exitContext(C context, ExitMode exitMode, int exitCode) {
}
/**
* Initializes this language instance for use with multiple contexts. Whether a language
* instance supports being used for multiple contexts depends on its
* {@link Registration#contextPolicy() context policy}.
*
* 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 {@link Builder#engine(Engine) explicit engine} or
* using an option. Before any language is used for sharing
* {@link #initializeMultipleContexts()} is invoked. It is guaranteed that sharing between
* multiple contexts is {@link #initializeMultipleContexts() initialized} before any language
* context is {@link #createContext(Env) 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 {@link 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.
*
* @see ContextPolicy More information on sharing language instances for multiple contexts.
* @see #areOptionsCompatible(OptionValues, OptionValues) Specify option configurations that
* make sharing incompatible.
* @see ContextPolicy
* @since 19.0
*/
protected void initializeMultipleContexts() {
}
/**
* Disposes the context created by
* {@link #createContext(org.pkl.thirdparty.truffle.api.TruffleLanguage.Env)}. A dispose cleans up all
* resources associated with a context. The context may become unusable after it was disposed.
* It is not allowed to run guest language code while disposing a context. Finalization code
* should be run in {@link #finalizeContext(Object)} instead. Finalization will be performed
* prior to context {@link #disposeContext(Object) disposal}. However, in case the underlying
* polyglot context is being cancelled, {@link #disposeContext(Object)} is called even if
* {@link #finalizeContext(Object)} throws
* {@link org.pkl.thirdparty.truffle.api.exception.AbstractTruffleException} or {@link ThreadDeath}
* exception..
*
* The disposal order can be influenced by specifying {@link Registration#dependentLanguages()
* language dependencies}. By default internal languages are disposed last, otherwise the
* default order is unspecified but deterministic. During disposal no other language must be
* accessed using the {@link Env language environment}.
*
* @param context the context created by
* {@link #createContext(org.pkl.thirdparty.truffle.api.TruffleLanguage.Env)}
* @see #finalizeContext(Object) to run finalization code for a context.
* @see #disposeThread(Object, Thread) to perform disposal actions when a thread is no longer
* used.
*
* @since 0.8 or earlier
*/
protected void disposeContext(C context) {
}
/**
* Parses the {@link ParsingRequest#getSource() provided source} and generates its appropriate
* AST representation. The parsing should execute no user code, it should only create the
* {@link Node} tree to represent the source. If the {@link ParsingRequest#getSource() provided
* source} does not correspond naturally to a {@link CallTarget call target}, the returned call
* target should create and if necessary initialize the corresponding language entity and return
* it.
*
* The result of the parsing request is cached per language instance,
* {@link ParsingRequest#getSource() source} and {@link ParsingRequest#getArgumentNames()
* argument names}. It is safe to assume that current {@link TruffleLanguage language} instance
* and {@link ParsingRequest#getArgumentNames() argument names} will remain unchanged for a
* parsed {@link CallTarget}. The scope of the caching is influenced by the
* {@link Registration#contextPolicy() context policy} and option
* {@link TruffleLanguage#areOptionsCompatible(OptionValues, OptionValues) compatibility}.
* Caching may be {@link Source#isCached() disabled} for sources. It is enabled for new sources
* by default.
*
* The {@code argumentNames} may contain symbolic names for actual parameters of the call to the
* returned value. The result should be a call target with method
* {@link CallTarget#call(java.lang.Object...)} that accepts as many arguments as were provided
* via the {@link ParsingRequest#getArgumentNames()} method.
*
* Implement {@link #parse(org.pkl.thirdparty.truffle.api.TruffleLanguage.InlineParsingRequest)} to
* parse source in a specific context location.
*
* @see TruffleLanguage.Registration#contextPolicy()
* @param request request for parsing
* @return a call target to invoke which also keeps in memory the {@link Node} tree representing
* just parsed code
* @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
* {@link org.pkl.thirdparty.graalvm.polyglot.Context}
* @since 0.22
*/
protected CallTarget parse(ParsingRequest request) throws Exception {
throw new UnsupportedOperationException(
String.format("Override parse method of %s, it will be made abstract in future version of Truffle API!", getClass().getName()));
}
/**
* Parses the {@link InlineParsingRequest#getSource() provided source snippet} at the
* {@link InlineParsingRequest#getLocation() provided location} and generates its appropriate
* AST representation. The parsing should execute no user code, it should only create the
* {@link Node} tree to represent the source.
*
* The parsing should be performed in a context (specified by
* {@link InlineParsingRequest#getLocation()}). The result should be an AST fragment with method
* {@link ExecutableNode#execute(org.pkl.thirdparty.truffle.api.frame.VirtualFrame)} that accepts frames
* valid at the {@link InlineParsingRequest#getLocation() provided location}.
*
* When not implemented, null is returned by default.
*
* @param request request for parsing
* @return a fragment to invoke which also keeps in memory the {@link Node} tree representing
* just parsed {@link InlineParsingRequest#getSource() code}, or null when
* inline parsing of code snippets is not implemented
* @throws Exception exception can be thrown when parsing goes wrong.
* @since 0.31
*/
protected ExecutableNode parse(InlineParsingRequest request) throws Exception {
return null;
}
/**
* Returns a set of option descriptors that are supported by this language. Option values are
* accessible using the {@link Env#getOptions() environment} when the context is
* {@link #createContext(Env) created}. To construct option descriptors from a list then
* {@link OptionDescriptors#create(List)} can be used. Languages must always return the same
* option descriptors independent of the language instance or side-effects.
*
* @see Option For an example of declaring the option descriptor using an annotation.
* @since 0.27
*/
protected OptionDescriptors getOptionDescriptors() {
return OptionDescriptors.EMPTY;
}
/**
* Notifies the language with pre-initialized context about {@link Env} change. See
* {@link org.pkl.thirdparty.graalvm.polyglot.Context} for information how to enable the Context
* pre-initialization.
*
* During the pre-initialization (in the native compilation time) the
* {@link #createContext(org.pkl.thirdparty.truffle.api.TruffleLanguage.Env)} and
* {@link #initializeContext(java.lang.Object)} methods are called. In the image execution time,
* the {@link #patchContext(java.lang.Object, org.pkl.thirdparty.truffle.api.TruffleLanguage.Env)} is
* called on all languages whose contexts were created during the pre-initialization a
* consequence of {@link org.pkl.thirdparty.graalvm.polyglot.Context#create(java.lang.String...)} invocation.
* The contexts are patched in a topological order starting from dependent languages. If the
* {@link #patchContext(java.lang.Object, org.pkl.thirdparty.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:
*
* {@link TruffleLanguageSnippets.PreInitializedLanguage#patchContext}
*
* @param context the context created by
* {@link #createContext(org.pkl.thirdparty.truffle.api.TruffleLanguage.Env)} during
* pre-initialization
* @param newEnv the new environment replacing the environment used in pre-initialization phase
* @return true in case of successful environment update. When the context cannot be updated to
* a new environment return false to create a new context. By default it returns
* {@code false} to prevent an usage of pre-initialized context by a language which is
* not aware of context pre-initialization.
* @since 0.31
*/
protected boolean patchContext(C context, Env newEnv) {
return false;
}
/**
* Request for parsing. Contains information of what to parse and in which context.
*
* @since 0.22
*/
public static final class ParsingRequest {
private final Source source;
private final String[] argumentNames;
private boolean disposed;
ParsingRequest(Source source, String... argumentNames) {
Objects.requireNonNull(source);
this.source = source;
this.argumentNames = argumentNames;
}
/**
* The source code to parse.
*
* @return the source code, never null
* @since 0.22
*/
public Source getSource() {
if (disposed) {
throw new IllegalStateException();
}
return source;
}
/**
* Argument names. The result of
* {@link #parse(org.pkl.thirdparty.truffle.api.TruffleLanguage.ParsingRequest) parsing} is an
* instance of {@link CallTarget} that {@link CallTarget#call(java.lang.Object...) can be
* invoked} without or with some parameters. If the invocation requires some arguments, and
* the {@link #getSource()} references them, it is essential to name them. Example that uses
* the argument names:
*
* {@link TruffleLanguageSnippets#parseWithParams}
*
* @return symbolic names for parameters of {@link CallTarget#call(java.lang.Object...)}
* @since 0.22
*/
public List getArgumentNames() {
if (disposed) {
throw new IllegalStateException();
}
return argumentNames == null ? Collections. emptyList() : ReadOnlyArrayList.asList(argumentNames, 0, argumentNames.length);
}
void dispose() {
disposed = true;
}
CallTarget parse(TruffleLanguage> truffleLanguage) throws Exception {
return truffleLanguage.parse(this);
}
}
/**
* Request for inline parsing. Contains information of what to parse and in which context.
*
* @since 0.31
*/
public static final class InlineParsingRequest {
private final Node node;
private final MaterializedFrame frame;
private final Source source;
private boolean disposed;
InlineParsingRequest(Source source, Node node, MaterializedFrame frame) {
Objects.requireNonNull(source);
this.node = node;
this.frame = frame;
this.source = source;
}
/**
* The source code to parse.
*
* @return the source code, never null
* @since 0.31
*/
public Source getSource() {
if (disposed) {
throw new IllegalStateException();
}
return source;
}
/**
* Specifies the code location for parsing. The location is specified as an instance of a
* {@link Node} in the AST. The node can be
* {@link org.pkl.thirdparty.truffle.api.instrumentation.EventContext#getInstrumentedNode()}, for
* example.
*
* @return a {@link Node} defining AST context for the parsing, it's never null
* @since 0.31
*/
public Node getLocation() {
if (disposed) {
throw new IllegalStateException();
}
return node;
}
/**
* Specifies the execution context for parsing. If the parsing request is used for
* evaluation during halted execution, for example as in
* {@link org.pkl.thirdparty.truffle.api.debug.DebugStackFrame#eval(String)} method, this method
* provides access to current {@link MaterializedFrame frame} with local variables, etc.
*
* @return a {@link MaterializedFrame} exposing the current execution state or
* null if there is none
* @since 0.31
*/
public MaterializedFrame getFrame() {
if (disposed) {
throw new IllegalStateException();
}
return frame;
}
void dispose() {
disposed = true;
}
ExecutableNode parse(TruffleLanguage> truffleLanguage) throws Exception {
return truffleLanguage.parse(this);
}
}
/**
* 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
* {@link Thread#currentThread() current thread} may differ from the passed thread. If this
* method throws an {@link org.pkl.thirdparty.truffle.api.exception.AbstractTruffleException} the
* exception interop messages may be executed without a context being entered.
*
* Example multi-threaded language implementation:
* {@link TruffleLanguageSnippets.MultiThreadedLanguage#initializeThread}
*
* @param thread the thread that accesses the context for the first time.
* @param singleThreaded true if the access is considered single-threaded,
* false if more than one thread is active at the same time.
* @since 0.28
*/
protected boolean isThreadAccessAllowed(Thread thread, boolean singleThreaded) {
return singleThreaded;
}
/**
* Invoked before the context is accessed from multiple threads at the same time. This allows
* languages to perform actions that are required to support multi-threading. It will never be
* invoked if {@link #isThreadAccessAllowed(Thread, boolean)} is implemented to deny access from
* multiple threads at the same time. All initialized languages must allow multi-threading for
* this method to be invoked. If this method throws an
* {@link org.pkl.thirdparty.truffle.api.exception.AbstractTruffleException} the exception interop
* messages may be executed without a context being entered.
*
* Example multi-threaded language implementation:
* {@link TruffleLanguageSnippets.MultiThreadedLanguage#initializeThread}
*
* @param context the context that should be prepared for multi-threading.
* @since 0.28
*/
protected void initializeMultiThreading(C context) {
}
/**
* Invoked before a context is accessed from a new thread. This allows the language to perform
* initialization actions for each thread before guest language code is executed. Also for
* languages that deny access from multiple threads at the same time, multiple threads may be
* initialized if they are used sequentially. This method will be invoked before the context is
* {@link #initializeContext(Object) initialized} for the thread the context will be initialized
* with. If the thread is stored in the context it must be referenced using
* {@link WeakReference} to avoid leaking thread objects.
*
* The {@link Thread#currentThread() current thread} may differ from the initialized thread.
*
* If this method throws an {@link org.pkl.thirdparty.truffle.api.exception.AbstractTruffleException}
* the exception interop messages may be executed without a context being entered.
*
* Example multi-threaded language implementation:
* {@link TruffleLanguageSnippets.MultiThreadedLanguage#initializeThread}
*
* @param context the context that is entered
* @param thread the thread that accesses the context for the first time.
*
* @since 0.28
*/
protected void initializeThread(C context, Thread thread) {
}
/**
* Invoked the last time code will be executed for this thread and context. This allows the
* language to perform cleanup actions for each thread and context. Threads might be disposed
* before after or while a context is disposed. The {@link Thread#currentThread() current
* thread} may differ from the disposed thread. Disposal of threads is only guaranteed for
* threads that were created by guest languages, so called {@link Env#createThread(Runnable)
* polyglot threads}. Other threads, created by the embedder, may be collected by the garbage
* collector before they can be disposed and may therefore not be disposed.
*
* @see #initializeThread(Object, Thread) For usage details.
* @since 0.28
*/
@SuppressWarnings("unused")
protected void disposeThread(C context, Thread thread) {
}
/**
* Get a top scope of the language, if any. The returned object must be an
* {@link org.pkl.thirdparty.truffle.api.interop.InteropLibrary#isScope(Object) interop scope object}
* and may have {@link org.pkl.thirdparty.truffle.api.interop.InteropLibrary#hasScopeParent(Object)
* parent scopes}. The scope object exposes all top scopes variables as flattened
* {@link org.pkl.thirdparty.truffle.api.interop.InteropLibrary#getMembers(Object) members}. Top scopes
* are independent of a {@link Frame}. See
* {@link org.pkl.thirdparty.truffle.api.interop.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
*
*
Top scopes are accessible to instruments with
* {@link org.pkl.thirdparty.truffle.api.instrumentation.TruffleInstrument.Env#getScope(LanguageInfo)}.
* They are used by debuggers to access the top-most scopes of the language.
*
Top scopes available in the {@link org.pkl.thirdparty.graalvm.polyglot polyglot API} as context
* {@link Context#getBindings(String) bindings} object. Access to members of the bindings object
* is applied to the returned scope object via interop.
*
*
*
* @param context the context to find the language top scope in
* @return the scope object or null if the language does not support such concept
* @since 20.3
*/
protected Object getScope(C context) {
return null;
}
/**
* 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
* {@link org.pkl.thirdparty.graalvm.polyglot.Context#eval(org.pkl.thirdparty.graalvm.polyglot.Source)} - when evaluating an
* {@link Source#isInteractive() interactive source} the result of the evaluation is tested for
* {@link #isVisible(java.lang.Object, java.lang.Object) visibility} and if the value is found
* visible, it gets converted to string and printed to
* {@link org.pkl.thirdparty.graalvm.polyglot.Context.Builder#out(OutputStream) 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 {@link Env#out()}, {@link Env#err()} and {@link Env#in()} streams of the
* environment.
*
* When evaluation is called with an {@link Source#isInteractive() interactive source} of a
* language that controls its interactive behavior, it is the responsibility of the language
* itself to print the result to use the {@link Env#out()}, {@link Env#err()} and
* {@link Env#in()} streams of the environment.
*
* @param context the execution context for doing the conversion
* @param value the value to check. Either primitive type or
* {@link org.pkl.thirdparty.truffle.api.interop.TruffleObject}
* @return true if the language implements an interactive response to evaluation of
* interactive sources.
* @since 0.22
*/
protected boolean isVisible(C context, Object value) {
return true;
}
/**
* Wraps the value to provide language-specific information for primitive and foreign values.
* Foreign values should be enhanced to look like the most generic object type of the language.
* The wrapper needs to introduce any "virtual" methods and properties that are commonly used in
* language constructs and in algorithms that are written to work on this generic object type.
* The wrapper may add or remove existing interop traits, but it is not allowed to change the
* {@link org.pkl.thirdparty.truffle.api.interop.InteropLibrary interop type}. For example, it is not
* allowed to change the type from number to string. If the behavior of an existing trait is
* modified then all writes on the mapper need to be forwarded to the underlying object, apart
* from the virtual members. Writes to the virtual members should be persisted in the wrapper if
* this is the behavior of the object type that is being mapped to.
*
* Every language view wrapper must return the current language as their associated
* {@link org.pkl.thirdparty.truffle.api.interop.InteropLibrary#getLanguage(Object) language}. An
* {@link 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
* {@link org.pkl.thirdparty.truffle.api.interop.InteropLibrary#toDisplayString(Object) display string}
* for primitive and foreign values.
*
Return a language specific
* {@link org.pkl.thirdparty.truffle.api.interop.InteropLibrary#getMetaObject(Object) 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".
*
*
*
* @param context the current context.
* @param value the value
* @since 20.1
*/
protected Object getLanguageView(C context, Object value) {
return null;
}
CallTarget parse(Source source, String... argumentNames) {
ParsingRequest request = new ParsingRequest(source, argumentNames);
CallTarget target;
try {
target = request.parse(this);
} catch (RuntimeException ex) {
throw ex;
} catch (Exception ex) {
throw new RuntimeException(ex);
} finally {
request.dispose();
}
return target;
}
ExecutableNode parseInline(Source source, Node context, MaterializedFrame frame) {
assert context != null;
InlineParsingRequest request = new InlineParsingRequest(source, context, frame);
ExecutableNode snippet;
try {
snippet = request.parse(this);
} catch (RuntimeException ex) {
throw ex;
} catch (Exception ex) {
throw new RuntimeException(ex);
} finally {
request.dispose();
}
return snippet;
}
/**
* @since 0.27
* @deprecated in 21.3, use static final context references instead. See
* {@link ContextReference} for the new intended usage.
*/
@Deprecated(since = "21.3")
protected static > T getCurrentLanguage(Class languageClass) {
try {
return LanguageAccessor.engineAccess().getCurrentLanguage(languageClass);
} catch (Throwable t) {
CompilerDirectives.transferToInterpreter();
throw Env.engineToLanguageException(t);
}
}
/**
* @since 0.27
* @deprecated in 21.3, use static final context references instead. See
* {@link LanguageReference} for the new intended usage.
*/
@Deprecated(since = "21.3")
protected static > C getCurrentContext(Class languageClass) {
try {
return ENGINE.getCurrentContext(languageClass);
} catch (Throwable t) {
CompilerDirectives.transferToInterpreter();
throw Env.engineToLanguageException(t);
}
}
/**
* Creates a new context local reference for this Truffle language. Context locals for languages
* allow to store additional top-level values for each context besides the language context. The
* advantage of context locals compared to storing the value in a field of the language context
* is that reading a context local requires one indirection less. It is recommended to use
* context locals for languages only if the read is critical for performance.
*
* Context local references must be created during the invocation in the {@link TruffleLanguage}
* constructor. Calling this method at a later point in time will throw an
* {@link IllegalStateException}. For each registered {@link TruffleLanguage} subclass it is
* required to always produce the same number of context local references. The values produced
* by the factory must not be 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 {@link 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;
* }
*
* }
* }
*
*
* @since 20.3
*/
protected final ContextLocal createContextLocal(ContextLocalFactory factory) {
ContextLocal local = ENGINE.createLanguageContextLocal(factory);
if (contextLocals == null) {
contextLocals = new ArrayList<>();
}
try {
contextLocals.add(local);
} catch (UnsupportedOperationException e) {
throw new IllegalStateException("The set of context locals is frozen. Context locals can only be created during construction of the TruffleLanguage subclass.");
}
return local;
}
/**
* Creates a new context thread local reference for this Truffle language. Context thread locals
* for languages allow storing additional top-level values for each context and thread. The
* factory may be invoked on any thread other than the thread of the context thread local value.
*
* Context thread local references must be created during the invocation in the
* {@link TruffleLanguage} constructor. Calling this method at a later point in time will throw
* an {@link IllegalStateException}. For each registered {@link TruffleLanguage} subclass it is
* required to always produce the same number of context thread local references. The values
* 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 {@link 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);
* }
*
* }
* }
*
*
* @since 20.3
*/
protected final ContextThreadLocal createContextThreadLocal(ContextThreadLocalFactory factory) {
ContextThreadLocal local = ENGINE.createLanguageContextThreadLocal(factory);
if (contextThreadLocals == null) {
contextThreadLocals = new ArrayList<>();
}
try {
contextThreadLocals.add(local);
} catch (UnsupportedOperationException e) {
throw new IllegalStateException("The set of context thread locals is frozen. Context thread locals can only be created during construction of the TruffleLanguage subclass.");
}
return local;
}
/**
* Returns the home location for this language. This corresponds to the directory in which the
* Jar file is located, if run from a Jar file. For an AOT compiled binary, this corresponds to
* the location of the language files in the default GraalVM distribution layout. executable or
* shared library.
*
* @since 19.0
*/
protected final String getLanguageHome() {
try {
return ENGINE.getLanguageHome(languageInfo);
} catch (Throwable t) {
throw Env.engineToLanguageException(t);
}
}
/**
* Get the depth of asynchronous stack. When zero, the language should not sacrifice performance
* to be able to provide asynchronous stack. When the depth is non-zero, the language should
* provide asynchronous stack up to that depth. The language may provide more asynchronous
* frames than this depth if it's of no performance penalty, or if requested by other (e.g.
* language-specific) options. The returned depth may change at any time.
*
* Override {@link RootNode#findAsynchronousFrames(Frame)} to provide the asynchronous stack
* frames.
*
* @see RootNode#findAsynchronousFrames(Frame)
* @since 20.1.0
*/
protected final int getAsynchronousStackDepth() {
assert polyglotLanguageInstance != null : "getAsynchronousStackDepth not supported for host language";
return LanguageAccessor.engineAccess().getAsynchronousStackDepth(polyglotLanguageInstance);
}
/**
* Context local factory for Truffle languages. Creates a new value per context.
*
* @since 20.3
*/
@FunctionalInterface
protected interface ContextLocalFactory {
/**
* Returns a new value for a context local of a language. The returned value must not be
* null and must return a stable and exact type per registered language. A
* thread local must always return the same {@link Object#getClass() class}, even for
* multiple instances of the same {@link TruffleLanguage}. If this method throws an
* {@link org.pkl.thirdparty.truffle.api.exception.AbstractTruffleException} the exception interop
* messages may be executed without a context being entered.
*
* @see TruffleLanguage#createContextLocal(ContextLocalFactory)
* @since 20.3
*/
T create(C context);
}
/**
* Context thread local factory for Truffle languages. Creates a new value per context and
* thread.
*
* @since 20.3
*/
@FunctionalInterface
protected interface ContextThreadLocalFactory {
/**
* Returns a new value for a context thread local for a language context and thread. The
* returned value must not be null and must return a stable and exact type per
* TruffleLanguage subclass. A thread local must always return the same
* {@link Object#getClass() class}, even for multiple instances of the same
* {@link TruffleLanguage}. If this method throws an
* {@link org.pkl.thirdparty.truffle.api.exception.AbstractTruffleException} the exception interop
* messages may be executed without a context being entered.
*
* @see TruffleLanguage#createContextThreadLocal(ContextThreadLocalFactory)
* @since 20.3
*/
T create(C context, Thread thread);
}
/**
* Represents execution environment of the {@link TruffleLanguage}. Each active
* {@link TruffleLanguage} receives instance of the environment before any code is executed upon
* it. The environment has knowledge of all active languages and can exchange symbols between
* them.
*
* @since 0.8 or earlier
*/
public static final class Env {
static final Object UNSET_CONTEXT = new Object();
final Object polyglotLanguageContext; // PolylgotLanguageContext
final TruffleLanguage