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) 2016, 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.instrumentation;
import static org.pkl.thirdparty.truffle.api.instrumentation.InstrumentAccessor.ENGINE;
import static java.util.concurrent.TimeUnit.SECONDS;
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.net.URI;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Collection;
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.concurrent.atomic.AtomicBoolean;
import java.util.function.Consumer;
import org.pkl.thirdparty.graalvm.home.Version;
import org.pkl.thirdparty.graalvm.options.OptionDescriptor;
import org.pkl.thirdparty.graalvm.options.OptionDescriptors;
import org.pkl.thirdparty.graalvm.options.OptionValues;
import org.pkl.thirdparty.graalvm.polyglot.Engine;
import org.pkl.thirdparty.graalvm.polyglot.SandboxPolicy;
import org.pkl.thirdparty.graalvm.polyglot.io.MessageEndpoint;
import org.pkl.thirdparty.graalvm.polyglot.io.MessageTransport;
import org.pkl.thirdparty.graalvm.polyglot.proxy.Proxy;
import org.pkl.thirdparty.truffle.api.CallTarget;
import org.pkl.thirdparty.truffle.api.CompilerDirectives;
import org.pkl.thirdparty.truffle.api.CompilerDirectives.TruffleBoundary;
import org.pkl.thirdparty.truffle.api.ContextLocal;
import org.pkl.thirdparty.truffle.api.ContextThreadLocal;
import org.pkl.thirdparty.truffle.api.InstrumentInfo;
import org.pkl.thirdparty.truffle.api.Option;
import org.pkl.thirdparty.truffle.api.ThreadLocalAction;
import org.pkl.thirdparty.truffle.api.TruffleContext;
import org.pkl.thirdparty.truffle.api.TruffleFile;
import org.pkl.thirdparty.truffle.api.TruffleLanguage;
import org.pkl.thirdparty.truffle.api.TruffleLogger;
import org.pkl.thirdparty.truffle.api.TruffleRuntime;
import org.pkl.thirdparty.truffle.api.TruffleSafepoint;
import org.pkl.thirdparty.truffle.api.TruffleSafepoint.Interrupter;
import org.pkl.thirdparty.truffle.api.TruffleSafepoint.Interruptible;
import org.pkl.thirdparty.truffle.api.TruffleStackTrace;
import org.pkl.thirdparty.truffle.api.frame.Frame;
import org.pkl.thirdparty.truffle.api.frame.FrameDescriptor;
import org.pkl.thirdparty.truffle.api.frame.MaterializedFrame;
import org.pkl.thirdparty.truffle.api.frame.VirtualFrame;
import org.pkl.thirdparty.truffle.api.instrumentation.InstrumentationHandler.InstrumentClientInstrumenter;
import org.pkl.thirdparty.truffle.api.interop.InteropLibrary;
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;
/**
* The service provider interface (SPI) for Truffle instruments: clients of Truffle instrumentation
* that may observe and inject behavior into interpreters written using the Truffle framework.
*
* Instrument implementation classes must use the {@link Registration} annotation to provide
* required metadata and to enable automatic discovery of the implementation.
*
* An instrument is {@link #onCreate(Env) created } if at least one instrument
* {@link TruffleInstrument.Env#getOptions() option} was specified or if a
* {@link TruffleInstrument.Env#registerService(Object) service} was looked up. The
* {@link Instrumenter} available in the provided {@linkplain Env environment} allows the instrument
* instance to bind listeners for {@linkplain ExecutionEventListener execution} and
* {@linkplain LoadSourceListener source} events, as well as {@linkplain ExecutionEventNodeFactory
* node factories} for code injection at guest language code locations.
*
* An instrument is disposed when the associated polyglot {@linkplain Engine engine} is disposed.
* All active bindings created by a disposed instrument become disposed automatically. The
* {@link Instrumenter} instance available in the provided {@linkplain Env environment} may not be
* used after disposal.
*
*
Example for a simple expression coverage instrument:
* {@codesnippet org.pkl.thirdparty.truffle.api.instrumentation.test.examples.CoverageExample}
*
* @since 0.12
*/
public abstract class TruffleInstrument {
/**
* Constructor for subclasses.
*
* @since 0.12
*/
protected TruffleInstrument() {
}
List> contextThreadLocals;
List> contextLocals;
/**
* Invoked once on each newly allocated {@link TruffleInstrument} instance.
*
* The method may {@link Env#registerService(java.lang.Object) register} additional
* {@link Registration#services() services} - e.g. objects to be exposed via
* {@link org.pkl.thirdparty.graalvm.polyglot.Instrument#lookup lookup query}. For example to expose a debugger
* one could define an abstract debugger controller:
*
*
* {@codesnippet DebuggerController}
*
* and declare it as a {@link Registration#services() service} associated with the instrument,
* implement it, instantiate and {@link Env#registerService(java.lang.Object) register} in own's
* instrument {@link #onCreate(org.pkl.thirdparty.truffle.api.instrumentation.TruffleInstrument.Env)
* onCreate} method:
*
* {@codesnippet DebuggerExample}
*
* If this method throws an {@link org.pkl.thirdparty.truffle.api.exception.AbstractTruffleException}
* the exception interop messages are executed without a context being entered.
*
* @param env environment information for the instrument
*
* @see Env#getInstrumenter()
* @since 0.12
*/
protected abstract void onCreate(Env env);
/**
* Invoked once on an {@linkplain TruffleInstrument instance} just before all instruments and
* languages are going to be disposed, possibly because the underlying
* {@linkplain org.pkl.thirdparty.graalvm.polyglot.Engine engine} is going to be closed. This method is called
* before {@link #onDispose(Env)} and the instrument must remain usable after finalization. The
* instrument can prepare for disposal while still having other instruments not disposed yet. In
* the event of VM shutdown, {@link #onDispose(Env)} for active instruments on unclosed
* {@link org.pkl.thirdparty.graalvm.polyglot.Engine engines} is not called, and so in case the instrument is
* supposed to do some specific action before its disposal, e.g. print some kind of summary, it
* should be done in this method.
*
* @param env environment information for the instrument
* @since 19.0
*/
protected void onFinalize(Env env) {
// default implementation does nothing
}
/**
* Invoked once on an {@linkplain TruffleInstrument instance} when it becomes disabled, possibly
* because the underlying {@linkplain org.pkl.thirdparty.graalvm.polyglot.Engine engine} has been closed. A
* disposed instance is no longer usable. If the instrument is re-enabled, the engine will
* create a new instance. In the event of VM shutdown, this method is not called for active
* instruments on unclosed {@link org.pkl.thirdparty.graalvm.polyglot.Engine engines}. The unclosed engines are
* not closed automatically on VM shutdown, they just die with the VM.
*
* @param env environment information for the instrument
* @since 0.12
*/
protected void onDispose(Env env) {
// default implementation does nothing
}
/**
* Returns a set of option descriptors that are supported by this instrument. Option values are
* accessible using the {@link Env#getOptions() environment} when the instrument is
* {@link #onCreate(Env) created}. By default no options are available for an instrument.
* Options returned by this method must specify the {@link Registration#id() instrument id} as
* {@link OptionDescriptor#getName() name} prefix for each option. For example if the id of the
* instrument is "debugger" then a valid option name would be "debugger.Enabled". The instrument
* will automatically be {@link #onCreate(Env) created} if one of the specified options was
* provided by the engine. To construct option descriptors from a list then
* {@link OptionDescriptors#create(List)} can be used.
*
* By default option descriptors may only be specified per engine or bound engine, but option
* values may also be specified per context. In this case the context specific options can be
* specified with {@link #getContextOptionDescriptors()} and the values can be accessed with
* {@link Env#getOptions(TruffleContext)}.
*
* @see Option For an example of declaring the option descriptor using an annotation.
* @since 0.27
*/
protected OptionDescriptors getOptionDescriptors() {
return OptionDescriptors.EMPTY;
}
/**
* Returns a set of option descriptors for instrument options that can be specified per context.
* This can be specified in addition to options specified on the engine level, instruments may
* specify options for each context. Option descriptors specified per context must not overlap
* with option descriptors specified per instrument instance.
*
* Example usage:
*
*
*
* @Option.Group(MyInstrument.ID)
* final class MyContext {
*
* @Option(category = OptionCategory.EXPERT, help = "Description...")
* static final OptionKey MyContextOption = new OptionKey<>(Boolean.FALSE);
* }
*
* @Registration(...)
* class MyInstrument extends TruffleInstrument {
*
* static final OptionDescriptors CONTEXT_OPTIONS = new MyContextOptionDescriptors();
*
* //...
*
* protected OptionDescriptors getContextOptionDescriptors() {
* return CONTEXT_OPTIONS;
* }
* }
*
*
* @see Env#getOptions(TruffleContext) to lookup the option values for a context.
* @since 20.3
*/
protected OptionDescriptors getContextOptionDescriptors() {
return OptionDescriptors.EMPTY;
}
/**
* Creates a new context local reference for this instrument. Context locals for instruments
* allow to store additional top-level values for each context similar to language contexts.
* This enables instruments to use context local values just as languages using their language
* context. Context local factories are guaranteed to be invoked after the instrument is
* {@link #onCreate(Env) created}.
*
* Context local references must be created during the invocation in the
* {@link TruffleInstrument} constructor. Calling this method at a later point in time will
* throw an {@link IllegalStateException}. For each registered {@link TruffleInstrument}
* 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 instrument 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:
*
*
* @TruffleInstrument.Registration(id = "example", name = "Example Instrument")
* public static class ExampleInstrument extends TruffleInstrument {
*
* final ContextLocal local = createContextLocal(ExampleLocal::new);
*
* @Override
* protected void onCreate(Env env) {
* ExecutionEventListener listener = new ExecutionEventListener() {
* public void onEnter(EventContext context, VirtualFrame frame) {
* ExampleLocal value = local.get();
* // use context local value;
* }
*
* public void onReturnValue(EventContext context, VirtualFrame frame, Object result) {
* }
*
* public void onReturnExceptional(EventContext context, VirtualFrame frame, Throwable exception) {
* }
* };
*
* env.getInstrumenter().attachExecutionEventListener(
* SourceSectionFilter.ANY,
* listener);
* }
*
* static class ExampleLocal {
*
* final TruffleContext context;
*
* ExampleLocal(TruffleContext context) {
* this.context = context;
* }
*
* }
*
* }
*
*
* @since 20.3
*/
protected final ContextLocal createContextLocal(ContextLocalFactory factory) {
ContextLocal local = ENGINE.createInstrumentContextLocal(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 TruffleInstrument subclass.");
}
return local;
}
/**
* Creates a new context thread local reference for this Truffle language. Context thread locals
* for languages allow to store 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 factories are guaranteed to be invoked after the instrument is
* {@link #onCreate(Env) created}.
*
* 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
* produces 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:
*
*
* @TruffleInstrument.Registration(id = "example", name = "Example Instrument")
* public static class ExampleInstrument extends TruffleInstrument {
*
* final ContextThreadLocal local = createContextThreadLocal(ExampleLocal::new);
*
* @Override
* protected void onCreate(Env env) {
* ExecutionEventListener listener = new ExecutionEventListener() {
* public void onEnter(EventContext context, VirtualFrame frame) {
* ExampleLocal value = local.get();
* // use thread local value;
* assert value.thread.get() == Thread.currentThread();
* }
*
* public void onReturnValue(EventContext context, VirtualFrame frame, Object result) {
* }
*
* public void onReturnExceptional(EventContext context, VirtualFrame frame, Throwable exception) {
* }
* };
*
* env.getInstrumenter().attachExecutionEventListener(
* SourceSectionFilter.ANY,
* listener);
* }
*
* static class ExampleLocal {
*
* final TruffleContext context;
* final WeakReference thread;
*
* ExampleLocal(TruffleContext context, Thread thread) {
* this.context = context;
* this.thread = new WeakReference<>(thread);
* }
* }
*
* }
*
*
* @since 20.3
*/
protected final ContextThreadLocal createContextThreadLocal(ContextThreadLocalFactory factory) {
ContextThreadLocal local = ENGINE.createInstrumentContextThreadLocal(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 TruffleInstrument subclass.");
}
return local;
}
/**
* Context local factory for Truffle instruments. Creates a new value per context.
*
* @since 20.3
*/
@FunctionalInterface
protected interface ContextLocalFactory {
/**
* Returns a new value for a context local of an instrument. The returned value must not be
* null and must return a stable and exact type per registered instrument. A
* thread local must always return the same {@link Object#getClass() class}, even for
* multiple instances of the same {@link TruffleInstrument}. 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 TruffleInstrument#createContextLocal(ContextLocalFactory)
* @since 20.3
*/
T create(TruffleContext context);
}
/**
* Context local factory for Truffle instruments. 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 context and thread. The returned
* value must not be null and must return a stable and exact type per
* registered instrument. A thread local must always return the same
* {@link Object#getClass() class}, even for multiple instances of the same
* {@link TruffleInstrument}. 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 TruffleInstrument#createContextThreadLocal(ContextThreadLocalFactory)
* @since 20.3
*/
T create(TruffleContext context, Thread thread);
}
/**
* Access to instrumentation services as well as input, output, and error streams.
*
* @since 0.12
*/
@SuppressWarnings("static-method")
public static final class Env {
private final Object polyglotInstrument;
private final InputStream in;
private final OutputStream err;
private final OutputStream out;
private final MessageTransport messageTransport;
OptionValues options;
InstrumentClientInstrumenter instrumenter;
private List