org.pkl.thirdparty.truffle.api.instrumentation.Instrumenter Maven / Gradle / Ivy
Show all versions of pkl-config-java-all Show documentation
/*
* 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 java.io.OutputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import org.pkl.thirdparty.truffle.api.TruffleContext;
import org.pkl.thirdparty.truffle.api.TruffleLanguage;
import org.pkl.thirdparty.truffle.api.nodes.Node;
import org.pkl.thirdparty.truffle.api.nodes.RootNode;
import org.pkl.thirdparty.truffle.api.source.Source;
import org.pkl.thirdparty.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
*/
public abstract class Instrumenter {
Instrumenter() {
}
/**
* Starts execution event notification for a given {@link SourceSectionFilter event filter} and
* {@link ExecutionEventListener listener}. The execution events are delivered to the
* {@link ExecutionEventListener}.
*
* 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.
*
* By default no
* {@link ExecutionEventNode#onInputValue(org.pkl.thirdparty.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 EventBinding attachExecutionEventListener(SourceSectionFilter eventFilter, T listener) {
return attachExecutionEventListener(eventFilter, null, listener);
}
/**
* 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.
*
* 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.
*
* By default no
* {@link ExecutionEventNode#onInputValue(org.pkl.thirdparty.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 EventBinding attachExecutionEventFactory(SourceSectionFilter eventFilter, T factory) {
return attachExecutionEventFactory(eventFilter, null, factory);
}
/**
* Starts execution event notification for a given {@link SourceSectionFilter event filter} and
* {@link ExecutionEventListener listener}. The execution events are delivered to the
* {@link ExecutionEventListener}.
*
* 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.
*
* The input filter argument filters which
* {@link ExecutionEventListener#onInputValue(EventContext, org.pkl.thirdparty.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, null
for no input values
* @param listener that listens to execution events.
* @see ExecutionEventListener
* @see ExecutionEventListener#onInputValue(EventContext,
* org.pkl.thirdparty.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(since = "20.0")
public abstract EventBinding attachExecutionEventListener(SourceSectionFilter eventFilter, SourceSectionFilter inputFilter, T listener);
/**
* 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.
*
* 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.
*
* The input filter argument filters which
* {@link ExecutionEventNode#onInputValue(org.pkl.thirdparty.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, null
for no input values
* @param factory the factory that creates {@link ExecutionEventNode execution event nodes}.
* @see ExecutionEventNodeFactory
* @see ExecutionEventNode#onInputValue(org.pkl.thirdparty.truffle.api.frame.VirtualFrame, EventContext,
* int, Object)
* @since 0.33
*/
public abstract EventBinding attachExecutionEventFactory(SourceSectionFilter eventFilter, SourceSectionFilter inputFilter, T factory);
/**
* Starts execution event notification for the nearest {@link SourceSection} as specified by the
* {@link NearestSectionFilter}. Events are delivered to the {@link ExecutionEventNode}
* instances created by the {@link ExecutionEventNodeFactory factory}.
*
* 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.
*
* The final nearest node is selected from the sections filtered by the
* {@link SourceSectionFilter baseFilter} by applying
* {@link InstrumentableNode#findNearestNodeAt(int, int, Set)}.
*
*
* @param nearestFilter a filter describing the nearest section
* @param baseFilter a filter selecting sections we find the nearest from
* @param factory the factory that creates {@link ExecutionEventNode execution event nodes}.
* @return a handle to dispose the execution event binding.
*
* @see ExecutionEventNodeFactory
* @since 23.0
*/
public abstract EventBinding attachExecutionEventFactory(NearestSectionFilter nearestFilter, SourceSectionFilter baseFilter, T factory);
/**
* 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.
*
* Note: 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(since = "19.0")
public abstract EventBinding attachLoadSourceListener(SourceSectionFilter filter, T listener, boolean includeExistingSources);
/**
* 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 EventBinding attachLoadSourceListener(SourceFilter filter, T listener, boolean includeExistingSources);
/**
* 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. Every source is reported at most once.
*
* @param filter a filter on which source events are triggered.
* @param listener a listener that gets notified if a source was executed
* @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 EventBinding attachExecuteSourceListener(SourceFilter filter, T listener, boolean includeExecutedSources);
/**
* 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. Every source is reported at most once.
*
* @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 EventBinding attachLoadSourceSectionListener(SourceSectionFilter filter, T listener, boolean includeExistingSourceSections);
/**
* Starts notifications for the nearest {@link SourceSection} as specified by the
* {@link NearestSectionFilter} and returns a {@linkplain EventBinding binding} that can be used
* to terminate notifications. The final nearest node is selected from the sections filtered by
* the {@link SourceSectionFilter baseFilter} by applying
* {@link InstrumentableNode#findNearestNodeAt(int, int, Set)}. Only subsequent loads will be
* notified unless {@code includeExistingSourceSections} is true, in which case a notification
* for each previously loaded source section will be delivered before this method returns.
*
*
* @param nearestFilter a filter describing the nearest section
* @param baseFilter a filter selecting sections we find the nearest from
* @param listener a listener that gets notified if a source section was loaded
* @param includeExistingSourceSections whether or not this listener should be notified for
* source sections 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 23.0
*/
public abstract EventBinding attachLoadSourceSectionListener(NearestSectionFilter nearestFilter, SourceSectionFilter baseFilter, T listener,
boolean includeExistingSourceSections);
/**
* Create a {@linkplain EventBinding binding} to get notifications for each newly loaded
* {@link Source}. The binding needs to be {@link EventBinding#attach() attached} to receive
* notifications. Only subsequent loads will be notified after {@link EventBinding#attach()
* attach}, unless {@code includeExistingSources} is true, in which case a notification for each
* previously loaded source will be delivered before attach method returns.
*
* The difference from
* {@link #attachLoadSourceListener(SourceFilter, LoadSourceListener, boolean)} is in having the
* binding object before notifications are produced when existing sources are requested.
*
* @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 binding handle to {@link EventBinding#attach() attach} and
* {@link EventBinding#dispose() stop} the notification stream
*
* @see LoadSourceListener#onLoad(LoadSourceEvent)
* @since 21.1
*/
public abstract EventBinding createLoadSourceBinding(SourceFilter filter, T listener, boolean includeExistingSources);
/**
* Create a {@linkplain EventBinding binding} to get notifications for each newly executed
* {@link Source}. The binding needs to be {@link EventBinding#attach() attached} to receive
* notifications. Only subsequent executions will be notified after {@link EventBinding#attach()
* attach}, unless {@code includeExecutedSources} is true, in which case a notification for each
* previously executed source will be delivered before attach method returns. Every source is
* reported at most once.
*
* The difference from
* {@link #attachExecuteSourceListener(SourceFilter, ExecuteSourceListener, boolean)} is in
* having the binding object before notifications are produced when executed sources are
* requested.
*
* @param filter a filter on which sources events are triggered.
* @param listener a listener that gets notified if a source was executed
* @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 binding handle to {@link EventBinding#attach() attach} and
* {@link EventBinding#dispose() stop} the notification stream
*
* @see ExecuteSourceListener#onExecute(ExecuteSourceEvent)
* @since 21.1
*/
public abstract EventBinding createExecuteSourceBinding(SourceFilter filter, T listener, boolean includeExecutedSources);
/**
* Create a {@linkplain EventBinding binding} to get notifications for each newly loaded
* {@link SourceSection} in every newly loaded {@link Source}. The binding needs to be
* {@link EventBinding#attach() attached} to receive notifications. Only subsequent loads will
* be notified after {@link EventBinding#attach() attach}, unless
* {@code includeExistingSourceSections} is true, in which case a notification for each
* previously loaded source section will be delivered before attach method returns. Every source
* is reported at most once.
*
* The difference from
* {@link #attachLoadSourceSectionListener(SourceSectionFilter, LoadSourceSectionListener, boolean)}
* is in having the binding object before notifications are produced when existing source
* sections are requested.
*
* @param filter a filter on which sources events are triggered.
* @param listener a listener that gets notified if a source section was loaded
* @param includeExistingSourceSections whether or not this listener should be notified for
* source sections which were already loaded at the time when this listener was
* attached.
* @return a binding handle to {@link EventBinding#attach() attach} and
* {@link EventBinding#dispose() stop} the notification stream
*
* @see LoadSourceSectionListener#onLoad(LoadSourceSectionEvent)
* @since 21.1
*/
public abstract EventBinding createLoadSourceSectionBinding(SourceSectionFilter filter, T listener, boolean includeExistingSourceSections);
/**
* Create a {@linkplain EventBinding binding} to get notification for the nearest source section
* to the given position as specified by the {@link NearestSectionFilter}. The final nearest
* node is selected from the sections filtered by the {@link SourceSectionFilter baseFilter} by
* applying {@link InstrumentableNode#findNearestNodeAt(int, int, Set)}. The binding needs to be
* {@link EventBinding#attach() attached} to receive notifications. Only subsequent loads will
* be notified after {@link EventBinding#attach() attach}, unless
* {@code includeExistingSourceSections} is true, in which case a notification for each
* previously loaded source section will be delivered before attach method returns.
*
* The difference from
* {@link #attachLoadSourceSectionListener(NearestSectionFilter, SourceSectionFilter, LoadSourceSectionListener, boolean)}
* is in having the binding object before notifications are produced when existing source
* sections are requested.
*
* @param nearestFilter a filter describing the nearest section
* @param baseFilter a filter selecting sections we find the nearest from
* @param listener a listener that gets notified if a source section was loaded
* @param includeExistingSourceSections whether or not this listener should be notified for
* source sections which were already loaded at the time when this listener was
* attached.
* @return a binding handle to {@link EventBinding#attach() attach} and
* {@link EventBinding#dispose() stop} the notification stream
*
* @see LoadSourceSectionListener#onLoad(LoadSourceSectionEvent)
* @since 23.0
*/
public abstract EventBinding createLoadSourceSectionBinding(NearestSectionFilter nearestFilter, SourceSectionFilter baseFilter, T listener,
boolean includeExistingSourceSections);
/**
* 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 {@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.pkl.thirdparty.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 EventBinding attachOutConsumer(T stream);
/**
* 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.pkl.thirdparty.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 EventBinding attachErrConsumer(T stream);
/**
* 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 EventBinding attachAllocationListener(AllocationEventFilter filter, T listener);
/**
* 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 EventBinding attachContextsListener(T listener, boolean includeActiveContexts);
/**
* 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 EventBinding attachThreadsListener(T listener, boolean includeInitializedThreads);
/**
* Attach a {@link ThreadsActivationListener 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
* {@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 {@link SourceSection} instances.
*
* @param filter criterion for inclusion
* @return unmodifiable list of instances that pass the filter
*
* @since 0.18
*/
public final List querySourceSections(SourceSectionFilter filter) {
final List sourceSectionList = new ArrayList<>();
visitLoadedSourceSections(filter, new LoadSourceSectionListener() {
@Override
public void onLoad(LoadSourceSectionEvent event) {
sourceSectionList.add(event.getSourceSection());
}
});
return Collections.unmodifiableList(sourceSectionList);
}
/**
* 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 null
. 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> 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.
*
* @param node an instrumentable node specifying the location
* @param binding the binding to lookup the execution nodes of
* @return the {@link ExecutionEventNode}, or null
.
* @since 19.0
*/
public abstract ExecutionEventNode lookupExecutionEventNode(Node node, EventBinding> binding);
}