Mercurial > hg > truffle
changeset 22258:ff9d1426d744
Truffle/Instrumentation: add missing notification of TagInstrument disposal; extensive Javadoc on Instrumenter
author | Michael Van De Vanter <michael.van.de.vanter@oracle.com> |
---|---|
date | Mon, 28 Sep 2015 11:27:48 -0700 |
parents | 3168715cb34d |
children | 1348cc2e084e |
files | truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/Instrumenter.java truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/TagInstrument.java |
diffstat | 2 files changed, 98 insertions(+), 29 deletions(-) [+] |
line wrap: on
line diff
--- a/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/Instrumenter.java Sun Sep 27 21:50:58 2015 -0700 +++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/Instrumenter.java Mon Sep 28 11:27:48 2015 -0700 @@ -45,7 +45,47 @@ import com.oracle.truffle.api.source.SourceSection; /** - * Access to instrumentation services in an execution instance. + * Client access to instrumentation services in a Truffle execution environment. + * <p> + * Services include: + * <ul> + * <li>A collection of {@linkplain Probe Probes}, each of which is {@linkplain #probe(Node) created} + * by clients in permanent association with a particular {@linkplain SourceSection source code + * location} in an AST executing in this environment. The Probe keeps tracks of all <em>clones</em> + * of the AST and ensures that any instrumentation <em>attached</em> to the Probe is put into effect + * in each AST clone at the {@link Node} that corresponds to the Probe's source code location.</li> + * <p> + * <li>A collection of {@linkplain ProbeListener listeners} that have registered to be notified + * whenever a new {@link Probe} is created in this environment and whenever a new {@link SyntaxTag} + * (or simply "tag") is newly added to an existing {@link Probe} in this environment.</li> + * <p> + * <li>The ability to {@linkplain #findProbesTaggedAs(SyntaxTag) enumerate} all existing + * {@linkplain Probe Probes} in this environment, optionally filtered to include only those to which + * a specific {@linkplain SyntaxTag tag} has been added.</li> + * <p> + * <li>The ability to <em>attach</em> a client-provided <em>event listener</em> to an existing + * {@link Probe} in this environment. The listener subsequently receives notification of execution + * events at the {@linkplain Node Nodes} corresponding to the Probe's {@linkplain SourceSection + * source code location}. The <em>attachment</em> also produces a {@link ProbeInstrument} that + * represents the binding, and which can be used to {@linkplain Instrument#dispose() detach} the + * listener from the Probe and stop event notification. A listener can be attached to any number of + * Probes, each time producing a new {@linkplain ProbeInstrument} that represents the binding.</li> + * <p> + * <li>The ability to <em>attach</em> a client-provided <em>event listener</em> to a specific + * {@linkplain SyntaxTag tag} for all {@linkplain Probe Probes} in the environment. A maximum of + * <em>one</em> listener may be attached to receive notification of "<em>before</em>" execution + * events (i.e. the flow of execution is just about to enter a {@link Node}), and a maximum of + * <em>one</em> listener may be attached to receive notification of "<em>after</em>" execution + * events. The <em>attachment</em> also produces a {@link TagInstrument} that represents the + * binding, and which can be used to {@linkplain Instrument#dispose() detach} the listener from the + * Probes and stop event notification. This mechanism is designed for much lower runtime overhead + * than other ways to accomplish the same thing, e.g. by attaching one listener individually to + * every Probe with the desired tag.</li> + * <p> + * <li>A collection of {@linkplain Tool Tools}, possibly client-provided, that can be + * {@linkplain #install(Tool) installed} for data collection, possibly providing their own services + * with the resulting information.</li> + * </ul> */ public final class Instrumenter { @@ -75,7 +115,7 @@ } /** - * {@linkplain ProbeInstrument Instrumentation}-based collectors of data during Guest Language + * {@linkplain Instrumenter Instrumentation}-based collectors of data during Guest Language * program execution. * <p> * Tools share a common <em>life cycle</em>: @@ -265,7 +305,7 @@ * It is a runtime error to attempt Probing an AST node with no parent. * * @return a (possibly newly created) {@link Probe} associated with this node. - * @throws ProbeException (unchecked) when a probe cannot be created, leaving the AST unchanged + * @throws ProbeException (unchecked) when a Probe cannot be created, leaving the AST unchanged */ @SuppressWarnings("rawtypes") public Probe probe(Node node) { @@ -295,7 +335,7 @@ throw new ProbeException(ProbeFailure.Reason.NOT_INSTRUMENTABLE, parent, node, null); } - // Create a new wrapper/probe with this node as its child. + // Create a new wrapper/Probe with this node as its child. final WrapperNode wrapper = createWrapperNode(node); if (wrapper == null || !(wrapper instanceof Node)) { @@ -382,7 +422,7 @@ * {@linkplain EventHandlerNode execution events} taking place at the Probe's AST location to * the listener. * - * @param probe source of execution events + * @param probe source of AST execution events * @param listener receiver of execution events * @param instrumentInfo optional documentation about the Instrument * @return a handle for access to the binding @@ -401,7 +441,7 @@ * {@linkplain EventHandlerNode execution events} taking place at the Probe's AST location to * the listener. * - * @param probe source of execution events + * @param probe source of AST execution events * @param listener receiver of execution events * @param instrumentInfo optional documentation about the Instrument * @return a handle for access to the binding @@ -426,7 +466,7 @@ * Any {@link RuntimeException} thrown by execution of the fragment is caught by the framework * and reported to the listener; there is no other notification. * - * @param probe probe source of execution events + * @param probe source of AST execution events * @param listener optional client callback for results/failure notification * @param rootFactory provider of AST fragments on behalf of the client * @param requiredResultType optional requirement, any non-assignable result is reported to the @@ -461,13 +501,8 @@ if (beforeTagInstrument != null) { throw new IllegalStateException("Only one 'before' TagInstrument at a time"); } - this.beforeTagInstrument = new TagInstrument.BeforeTagInstrument(tag, listener, instrumentInfo); - for (WeakReference<Probe> ref : probes) { - final Probe probe = ref.get(); - if (probe != null) { - probe.notifyTagInstrumentsChanged(); - } - } + this.beforeTagInstrument = new TagInstrument.BeforeTagInstrument(this, tag, listener, instrumentInfo); + notifyTagInstrumentChange(); return beforeTagInstrument; } @@ -491,13 +526,8 @@ if (afterTagInstrument != null) { throw new IllegalStateException("Only one 'afater' TagInstrument at a time"); } - this.afterTagInstrument = new TagInstrument.AfterTagInstrument(tag, listener, instrumentInfo); - for (WeakReference<Probe> ref : probes) { - final Probe probe = ref.get(); - if (probe != null) { - probe.notifyTagInstrumentsChanged(); - } - } + this.afterTagInstrument = new TagInstrument.AfterTagInstrument(this, tag, listener, instrumentInfo); + notifyTagInstrumentChange(); return afterTagInstrument; } @@ -537,6 +567,25 @@ return afterTagInstrument; } + void disposeBeforeTagInstrument() { + beforeTagInstrument = null; + notifyTagInstrumentChange(); + } + + void disposeAfterTagInstrument() { + afterTagInstrument = null; + notifyTagInstrumentChange(); + } + + private void notifyTagInstrumentChange() { + for (WeakReference<Probe> ref : probes) { + final Probe probe = ref.get(); + if (probe != null) { + probe.notifyTagInstrumentsChanged(); + } + } + } + // TODO (mlvdv) build this in as a VM event? /** * Enables instrumentation in a newly created AST by applying all registered instances of
--- a/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/TagInstrument.java Sun Sep 27 21:50:58 2015 -0700 +++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/TagInstrument.java Mon Sep 28 11:27:48 2015 -0700 @@ -45,14 +45,17 @@ */ @SuppressWarnings("unused") private final String instrumentInfo; + protected Instrumenter instrumenter; + /** * Has this instrument been disposed? stays true once set. */ - private boolean isDisposed = false; + protected boolean isDisposed = false; private SyntaxTag tag = null; - protected TagInstrument(SyntaxTag tag, String instrumentInfo) { + protected TagInstrument(Instrumenter instrumenter, SyntaxTag tag, String instrumentInfo) { + this.instrumenter = instrumenter; this.tag = tag; this.instrumentInfo = instrumentInfo; } @@ -62,8 +65,7 @@ if (isDisposed) { throw new IllegalStateException("Attempt to dispose an already disposed Instrumennt"); } - - // TODO (mlvdv) + instrumenter.disposeAfterTagInstrument(); this.isDisposed = true; } @@ -80,27 +82,45 @@ private final StandardBeforeInstrumentListener listener; - BeforeTagInstrument(SyntaxTag tag, StandardBeforeInstrumentListener listener, String instrumentInfo) { - super(tag, instrumentInfo); + BeforeTagInstrument(Instrumenter instrumenter, SyntaxTag tag, StandardBeforeInstrumentListener listener, String instrumentInfo) { + super(instrumenter, tag, instrumentInfo); this.listener = listener; } StandardBeforeInstrumentListener getListener() { return listener; } + + @Override + public void dispose() throws IllegalStateException { + if (isDisposed) { + throw new IllegalStateException("Disposed Instrument can not be disposed again"); + } + instrumenter.disposeBeforeTagInstrument(); + this.isDisposed = true; + } } static final class AfterTagInstrument extends TagInstrument { private final StandardAfterInstrumentListener listener; - AfterTagInstrument(SyntaxTag tag, StandardAfterInstrumentListener listener, String instrumentInfo) { - super(tag, instrumentInfo); + AfterTagInstrument(Instrumenter instrumenter, SyntaxTag tag, StandardAfterInstrumentListener listener, String instrumentInfo) { + super(instrumenter, tag, instrumentInfo); this.listener = listener; } StandardAfterInstrumentListener getListener() { return listener; } + + @Override + public void dispose() throws IllegalStateException { + if (isDisposed) { + throw new IllegalStateException("Disposed Instrument can not be disposed again"); + } + instrumenter.disposeAfterTagInstrument(); + this.isDisposed = true; + } } }