/*
 * Copyright (c) 2016, 2020, 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 com.oracle.truffle.api.instrumentation;

import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;

import com.oracle.truffle.api.TruffleContext;
import com.oracle.truffle.api.TruffleLanguage;
import com.oracle.truffle.api.nodes.Node;
import com.oracle.truffle.api.nodes.RootNode;
import com.oracle.truffle.api.source.Source;
import com.oracle.truffle.api.source.SourceSection;

Provides capabilities to attach listeners for execution, load, output and allocation events. The instrumenter remains usable as long as the engine is not closed. The instrumenter methods are safe to be used from arbitrary other threads.
Since:0.12
/** * Provides capabilities to attach listeners for execution, load, output and allocation events. The * instrumenter remains usable as long as the engine is not closed. The instrumenter methods are * safe to be used from arbitrary other threads. * * @since 0.12 */
public abstract class Instrumenter { Instrumenter() { }
Starts execution event notification for a given event filter and listener. The execution events are delivered to the ExecutionEventListener.

Returns a binding which allows to dispose the attached execution event binding. Disposing the binding removes all probes and wrappers from the AST that were created for this instrument. The removal of probes and wrappers is performed lazily on the next execution of the AST.

By default no input value events are delivered to the listener.

Params:
  • eventFilter – filters the events that are reported to the given listener
  • listener – that listens to execution events.
See Also:
Since:0.33
/** * Starts execution event notification for a given {@link SourceSectionFilter event filter} and * {@link ExecutionEventListener listener}. The execution events are delivered to the * {@link ExecutionEventListener}. * <p> * Returns a {@link EventBinding binding} which allows to dispose the attached execution event * binding. Disposing the binding removes all probes and wrappers from the AST that were created * for this instrument. The removal of probes and wrappers is performed lazily on the next * execution of the AST. * <p> * By default no * {@link ExecutionEventNode#onInputValue(com.oracle.truffle.api.frame.VirtualFrame, EventContext, int, Object) * input value events} are delivered to the listener. * * @param eventFilter filters the events that are reported to the given * {@link ExecutionEventListener listener} * @param listener that listens to execution events. * @see ExecutionEventListener * @since 0.33 */
public final <T extends ExecutionEventListener> EventBinding<T> attachExecutionEventListener(SourceSectionFilter eventFilter, T listener) { return attachExecutionEventListener(eventFilter, null, listener); }
Starts execution event notification for a given event filter and factory. Events are delivered to the ExecutionEventNode instances created by the factory.

Returns a binding which allows to dispose the attached execution event binding. Disposing the binding removes all probes and wrappers from the AST that were created for this instrument. The removal of probes and wrappers is performed lazily on the next execution of the AST.

By default no input value events are delivered to the created execution event nodes. To deliver inputs events use attachExecutionEventFactory(SourceSectionFilter, SourceSectionFilter, ExecutionEventNodeFactory) instead.

Params:
See Also:
Since:0.33
/** * Starts execution event notification for a given {@link SourceSectionFilter event filter} and * {@link ExecutionEventNodeFactory factory}. Events are delivered to the * {@link ExecutionEventNode} instances created by the factory. * <p> * Returns a {@link EventBinding binding} which allows to dispose the attached execution event * binding. Disposing the binding removes all probes and wrappers from the AST that were created * for this instrument. The removal of probes and wrappers is performed lazily on the next * execution of the AST. * <p> * By default no * {@link ExecutionEventNode#onInputValue(com.oracle.truffle.api.frame.VirtualFrame, EventContext, int, Object) * input value events} are delivered to the created execution event nodes. To deliver inputs * events use * {@link #attachExecutionEventFactory(SourceSectionFilter, SourceSectionFilter, ExecutionEventNodeFactory)} * instead. * * @param eventFilter filters the events that are reported to the {@link ExecutionEventNode * execution event nodes} created by the factory. * @param factory the factory that creates {@link ExecutionEventNode execution event nodes}. * @see ExecutionEventNodeFactory * @see #attachExecutionEventFactory(SourceSectionFilter, SourceSectionFilter, * ExecutionEventNodeFactory) * @since 0.33 */
public final <T extends ExecutionEventNodeFactory> EventBinding<T> attachExecutionEventFactory(SourceSectionFilter eventFilter, T factory) { return attachExecutionEventFactory(eventFilter, null, factory); }
Starts execution event notification for a given event filter and listener. The execution events are delivered to the ExecutionEventListener.

Returns a binding which allows to dispose the attached execution event binding. Disposing the binding removes all probes and wrappers from the AST that were created for this instrument. The removal of probes and wrappers is performed lazily on the next execution of the AST.

The input filter argument filters which input events are delivered to the created execution event nodes.

Params:
  • eventFilter – filters the events that are reported to the given listener
  • inputFilter – filters input events, null for no input values
  • listener – that listens to execution events.
See Also:
Since:0.33
Deprecated:inputFilters do not work for execution event listeners Use attachExecutionEventFactory(SourceSectionFilter, SourceSectionFilter, ExecutionEventNodeFactory) or use attachExecutionEventListener(SourceSectionFilter, ExecutionEventListener) instead.
/** * Starts execution event notification for a given {@link SourceSectionFilter event filter} and * {@link ExecutionEventListener listener}. The execution events are delivered to the * {@link ExecutionEventListener}. * <p> * Returns a {@link EventBinding binding} which allows to dispose the attached execution event * binding. Disposing the binding removes all probes and wrappers from the AST that were created * for this instrument. The removal of probes and wrappers is performed lazily on the next * execution of the AST. * <p> * The input filter argument filters which * {@link ExecutionEventListener#onInputValue(EventContext, com.oracle.truffle.api.frame.VirtualFrame, EventContext, int, Object) * input events} are delivered to the created execution event nodes. * * @param eventFilter filters the events that are reported to the given * {@link ExecutionEventListener listener} * @param inputFilter filters input events, <code>null</code> for no input values * @param listener that listens to execution events. * @see ExecutionEventListener * @see ExecutionEventListener#onInputValue(EventContext, * com.oracle.truffle.api.frame.VirtualFrame, EventContext, int, Object) * @since 0.33 * @deprecated inputFilters do not work for execution event listeners Use * {@link #attachExecutionEventFactory(SourceSectionFilter, SourceSectionFilter, ExecutionEventNodeFactory)} * or use * {@link #attachExecutionEventListener(SourceSectionFilter, ExecutionEventListener)} * instead. */
@Deprecated public abstract <T extends ExecutionEventListener> EventBinding<T> attachExecutionEventListener(SourceSectionFilter eventFilter, SourceSectionFilter inputFilter, T listener);
Starts execution event notification for a given event filter and factory. Events are delivered to the ExecutionEventNode instances created by the factory.

Returns a binding which allows to dispose the attached execution event binding. Disposing the binding removes all probes and wrappers from the AST that were created for this instrument. The removal of probes and wrappers is performed lazily on the next execution of the AST.

The input filter argument filters which input events are delivered to the created execution event nodes.

Params:
  • eventFilter – filters the events that are reported to the execution event nodes created by the factory.
  • inputFilter – filters input events, null for no input values
  • factory – the factory that creates execution event nodes.
See Also:
Since:0.33
/** * Starts execution event notification for a given {@link SourceSectionFilter event filter} and * {@link ExecutionEventNodeFactory factory}. Events are delivered to the * {@link ExecutionEventNode} instances created by the factory. * <p> * Returns a {@link EventBinding binding} which allows to dispose the attached execution event * binding. Disposing the binding removes all probes and wrappers from the AST that were created * for this instrument. The removal of probes and wrappers is performed lazily on the next * execution of the AST. * <p> * The input filter argument filters which * {@link ExecutionEventNode#onInputValue(com.oracle.truffle.api.frame.VirtualFrame, EventContext, int, Object) * input events} are delivered to the created execution event nodes. * * @param eventFilter filters the events that are reported to the {@link ExecutionEventNode * execution event nodes} created by the factory. * @param inputFilter filters input events, <code>null</code> for no input values * @param factory the factory that creates {@link ExecutionEventNode execution event nodes}. * @see ExecutionEventNodeFactory * @see ExecutionEventNode#onInputValue(com.oracle.truffle.api.frame.VirtualFrame, EventContext, * int, Object) * @since 0.33 */
public abstract <T extends ExecutionEventNodeFactory> EventBinding<T> attachExecutionEventFactory(SourceSectionFilter eventFilter, SourceSectionFilter inputFilter, T factory);
Starts notifications for each newly loaded Source and returns a binding that can be used to terminate notifications. Only subsequent loads will be notified unless includeExistingSources is true, in which case a notification for each previous load will be delivered before this method returns.

Note: the provided SourceSectionFilter must only contain filters on sources or mime types.

Params:
  • filter – a filter on which sources trigger events. Only source filters are allowed.
  • listener – a listener that gets notified if a source was loaded
  • includeExistingSources – whether or not this listener should be notified for sources which were already loaded at the time when this listener was attached.
See Also:
Returns:a handle for stopping the notification stream
Since:0.15
Deprecated:Use attachLoadSourceListener(SourceFilter, LoadSourceListener, boolean)
/** * Starts notifications for each newly loaded {@link Source} and returns a * {@linkplain EventBinding binding} that can be used to terminate notifications. Only * subsequent loads will be notified unless {@code includeExistingSources} is true, in which * case a notification for each previous load will be delivered before this method returns. * <p> * <strong>Note:</strong> the provided {@link SourceSectionFilter} must only contain filters on * {@link SourceSectionFilter.Builder#sourceIs(Source...) sources} or * {@link SourceSectionFilter.Builder#mimeTypeIs(String...) mime types}. * * @param filter a filter on which sources trigger events. Only source filters are allowed. * @param listener a listener that gets notified if a source was loaded * @param includeExistingSources whether or not this listener should be notified for sources * which were already loaded at the time when this listener was attached. * @return a handle for stopping the notification stream * * @see LoadSourceListener#onLoad(LoadSourceEvent) * * @since 0.15 * @deprecated Use {@link #attachLoadSourceListener(SourceFilter, LoadSourceListener, boolean)} */
@Deprecated public abstract <T extends LoadSourceListener> EventBinding<T> attachLoadSourceListener(SourceSectionFilter filter, T listener, boolean includeExistingSources);
Starts notifications for each newly loaded Source and returns a binding that can be used to terminate notifications. Only subsequent loads will be notified unless includeExistingSources is true, in which case a notification for each previous load will be delivered before this method returns.
Params:
  • filter – a filter on which sources events are triggered.
  • listener – a listener that gets notified if a source was loaded
  • includeExistingSources – whether or not this listener should be notified for sources which were already loaded at the time when this listener was attached.
See Also:
Returns:a handle for stopping the notification stream
Since:0.33
/** * Starts notifications for each newly loaded {@link Source} and returns a * {@linkplain EventBinding binding} that can be used to terminate notifications. Only * subsequent loads will be notified unless {@code includeExistingSources} is true, in which * case a notification for each previous load will be delivered before this method returns. * * @param filter a filter on which sources events are triggered. * @param listener a listener that gets notified if a source was loaded * @param includeExistingSources whether or not this listener should be notified for sources * which were already loaded at the time when this listener was attached. * @return a handle for stopping the notification stream * * @see LoadSourceListener#onLoad(LoadSourceEvent) * * @since 0.33 */
public abstract <T extends LoadSourceListener> EventBinding<T> attachLoadSourceListener(SourceFilter filter, T listener, boolean includeExistingSources);
Starts notifications for each newly executed Source and returns a binding that can be used to terminate notifications. Only subsequent executions will be notified unless includeExecutedSources is true, in which case a notification for each previously executed source will be delivered before this method returns. A source is reported as executed if any of it's RootNodes start to be executed.
Params:
  • filter – a filter on which source events are triggered.
  • listener – a listener that gets notified if a source was loaded
  • includeExecutedSources – whether or not this listener should be notified for sources which were already executed at the time when this listener was attached.
See Also:
Returns:a handle for stopping the notification stream
Since:0.33
/** * Starts notifications for each newly executed {@link Source} and returns a * {@linkplain EventBinding binding} that can be used to terminate notifications. Only * subsequent executions will be notified unless {@code includeExecutedSources} is true, in * which case a notification for each previously executed source will be delivered before this * method returns. A source is reported as executed if any of it's {@link RootNode}s start to be * executed. * * @param filter a filter on which source events are triggered. * @param listener a listener that gets notified if a source was loaded * @param includeExecutedSources whether or not this listener should be notified for sources * which were already executed at the time when this listener was attached. * @return a handle for stopping the notification stream * * @see ExecuteSourceListener#onExecute(ExecuteSourceEvent) * * @since 0.33 */
public abstract <T extends ExecuteSourceListener> EventBinding<T> attachExecuteSourceListener(SourceFilter filter, T listener, boolean includeExecutedSources);
Starts notifications for each SourceSection in every newly loaded Source and returns a binding that can be used to terminate notifications. Only subsequent loads will be notified unless includeExistingSourceSections is true, in which case a notification for each previous load will be delivered before this method returns.
Params:
  • filter – a filter on which sources sections trigger events
  • listener – a listener that gets notified if a source section was loaded
  • includeExistingSourceSections – whether or not this listener should be notified for sources which were already loaded at the time when this listener was attached.
See Also:
Returns:a handle for stopping the notification stream
Since:0.15
/** * Starts notifications for each {@link SourceSection} in every newly loaded {@link Source} and * returns a {@linkplain EventBinding binding} that can be used to terminate notifications. Only * subsequent loads will be notified unless {@code includeExistingSourceSections} is true, in * which case a notification for each previous load will be delivered before this method * returns. * * @param filter a filter on which sources sections trigger events * @param listener a listener that gets notified if a source section was loaded * @param includeExistingSourceSections whether or not this listener should be notified for * sources which were already loaded at the time when this listener was attached. * @return a handle for stopping the notification stream * * @see LoadSourceSectionListener#onLoad(LoadSourceSectionEvent) * * @since 0.15 */
public abstract <T extends LoadSourceSectionListener> EventBinding<T> attachLoadSourceSectionListener(SourceSectionFilter filter, T listener, boolean includeExistingSourceSections);
Notifies the listener for each SourceSection in every loaded Source that corresponds to the filter. Only loaded sections are notified, synchronously.
Params:
  • filter – a filter on which source sections trigger events
  • listener – a listener that gets notified with loaded source sections
See Also:
Since:19.0
/** * Notifies the listener for each {@link SourceSection} in every loaded {@link Source} that * corresponds to the filter. Only loaded sections are notified, synchronously. * * @param filter a filter on which source sections trigger events * @param listener a listener that gets notified with loaded source sections * * @see LoadSourceSectionListener#onLoad(LoadSourceSectionEvent) * * @since 19.0 */
public abstract void visitLoadedSourceSections(SourceSectionFilter filter, LoadSourceSectionListener listener);
Attach an output stream as a consumer of the standard output. The consumer output stream receives all output that goes to Env.out() since this call, including output emitted by the Engine this instrumenter is being executed in, output from instruments (including this one), etc. Be sure to dispose the binding when it's not used any more.
Since:0.25
/** * Attach an output stream as a consumer of the {@link TruffleInstrument.Env#out() standard * output}. The consumer output stream receives all output that goes to * {@link TruffleInstrument.Env#out()} since this call, including output emitted by the * {@link org.graalvm.polyglot.Engine} this instrumenter is being executed in, output from * instruments (including this one), etc. Be sure to {@link EventBinding#dispose() dispose} the * binding when it's not used any more. * * @since 0.25 */
public abstract <T extends OutputStream> EventBinding<T> attachOutConsumer(T stream);
Attach an output stream as a consumer of the error output . The consumer output stream receives all error output that goes to Env.err() since this call, including error output emitted by the Engine this instrumenter is being executed in, error output from instruments (including this one), etc. Be sure to dispose the binding when it's not used any more.
Since:0.25
/** * Attach an output stream as a consumer of the {@link TruffleInstrument.Env#err() error output} * . The consumer output stream receives all error output that goes to * {@link TruffleInstrument.Env#err()} since this call, including error output emitted by the * {@link org.graalvm.polyglot.Engine} this instrumenter is being executed in, error output from * instruments (including this one), etc. Be sure to {@link EventBinding#dispose() dispose} the * binding when it's not used any more. * * @since 0.25 */
public abstract <T extends OutputStream> EventBinding<T> attachErrConsumer(T stream);
Attach a listener to be notified about allocations of guest language values. Be sure to dispose the binding when it's not used any more.
Since:0.27
/** * Attach a {@link AllocationListener listener} to be notified about allocations of guest * language values. Be sure to {@link EventBinding#dispose() dispose} the binding when it's not * used any more. * * @since 0.27 */
public abstract <T extends AllocationListener> EventBinding<T> attachAllocationListener(AllocationEventFilter filter, T listener);
Attach a listener to be notified about changes in contexts in guest language application. This is supported in Env.getInstrumenter() only.
Params:
  • listener – a listener to receive the context events
  • includeActiveContexts – whether or not this listener should be notified for present active contexts
Returns:a handle for unregistering the listener
Since:0.30
/** * Attach a {@link ContextsListener listener} to be notified about changes in contexts in guest * language application. This is supported in {@link TruffleInstrument.Env#getInstrumenter()} * only. * * @param listener a listener to receive the context events * @param includeActiveContexts whether or not this listener should be notified for present * active contexts * @return a handle for unregistering the listener * @since 0.30 */
public abstract <T extends ContextsListener> EventBinding<T> attachContextsListener(T listener, boolean includeActiveContexts);
Attach a listener to be notified about changes in threads in guest language application. This is supported in Env.getInstrumenter() only.
Params:
  • listener – a listener to receive the context events
  • includeInitializedThreads – whether or not this listener should be notified for present initialized threads
Returns:a handle for unregistering the listener
Since:0.30
/** * Attach a {@link ThreadsListener listener} to be notified about changes in threads in guest * language application. This is supported in {@link TruffleInstrument.Env#getInstrumenter()} * only. * * @param listener a listener to receive the context events * @param includeInitializedThreads whether or not this listener should be notified for present * initialized threads * @return a handle for unregistering the listener * @since 0.30 */
public abstract <T extends ThreadsListener> EventBinding<T> attachThreadsListener(T listener, boolean includeInitializedThreads);
Attach a listener to be notified about when a thread gets entered or left in guest language applications.

The event notification starts after the listener registration is completed. This means that currently activated threads won't get a notification. It is also possible that ThreadsActivationListener.onLeaveThread(TruffleContext) is called without ever invoking ThreadsActivationListener.onEnterThread(TruffleContext).

Returns:a handle for unregistering the listener.
Since:20.3
/** * Attach a {@link ThreadsActivationListener listener} to be notified about when a thread gets * entered or left in guest language applications. * <p> * The event notification starts after the listener registration is completed. This means that * currently activated threads won't get a notification. It is also possible that * {@link ThreadsActivationListener#onLeaveThread(TruffleContext)} is called without ever * invoking {@link ThreadsActivationListener#onEnterThread(TruffleContext)}. * * @return a handle for unregistering the listener. * @since 20.3 */
public abstract EventBinding<? extends ThreadsActivationListener> attachThreadsActivationListener(ThreadsActivationListener listener);
Returns a filtered list of loaded SourceSection instances.
Params:
  • filter – criterion for inclusion
Returns:unmodifiable list of instances that pass the filter
Since:0.18
/** * Returns a filtered list of loaded {@link SourceSection} instances. * * @param filter criterion for inclusion * @return unmodifiable list of instances that pass the filter * * @since 0.18 */
public final List<SourceSection> querySourceSections(SourceSectionFilter filter) { final List<SourceSection> sourceSectionList = new ArrayList<>(); visitLoadedSourceSections(filter, new LoadSourceSectionListener() { @Override public void onLoad(LoadSourceSectionEvent event) { sourceSectionList.add(event.getSourceSection()); } }); return Collections.unmodifiableList(sourceSectionList); }
Returns an unmodifiable Set of tag classes which where associated with this node. If the instrumenter is used as a TruffleLanguage then only nodes can be queried for tags that are associated with the current language otherwise an IllegalArgumentException is thrown. The given node must not be null. If the given node is not instrumentable, the given node is not yet adopted by a RootNode or the given tag was not provided by the language then always an empty Set is returned.
Params:
  • node – the node to query
Returns:an unmodifiable Set of tag classes which where associated with this node.
Since:0.12
/** * Returns an unmodifiable {@link Set} of tag classes which where associated with this node. If * the instrumenter is used as a {@link TruffleLanguage} then only nodes can be queried for tags * that are associated with the current language otherwise an {@link IllegalArgumentException} * is thrown. The given node must not be <code>null</code>. If the given node is not * instrumentable, the given node is not yet adopted by a {@link RootNode} or the given tag was * not {@link ProvidedTags provided} by the language then always an empty {@link Set} is * returned. * * @param node the node to query * @return an unmodifiable {@link Set} of tag classes which where associated with this node. * @since 0.12 */
public abstract Set<Class<?>> queryTags(Node node);
Returns the execution event node that was inserted at the node's location given an event binding, if any. This is useful to identify and find information from nodes that were created for a specific instrumentation.
Params:
  • node – an instrumentable node specifying the location
  • binding – the binding to lookup the execution nodes of
Returns:the ExecutionEventNode, or null.
Since:19.0
/** * Returns the execution event node that was inserted at the node's location given an event * binding, if any. This is useful to identify and find information from nodes that were created * for a specific instrumentation. * * @param node an instrumentable node specifying the location * @param binding the binding to lookup the execution nodes of * @return the {@link ExecutionEventNode}, or <code>null</code>. * @since 19.0 */
public abstract ExecutionEventNode lookupExecutionEventNode(Node node, EventBinding<?> binding); }