changeset 22255:e7643754d982

Truffle/Instrumentation: rename Instrument to ProbeInstrument to distinguish from another kind to be added.
author Michael Van De Vanter <michael.van.de.vanter@oracle.com>
date Fri, 25 Sep 2015 14:58:35 -0700
parents 7ec5eef84ecf
children 75e5db92973a
files truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/instrument/InstrumentationTest.java truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/debug/Breakpoint.java truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/debug/LineBreakpointFactory.java truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/debug/TagBreakpointFactory.java truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/AdvancedInstrumentResultListener.java truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/AdvancedInstrumentRoot.java truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/AdvancedInstrumentRootFactory.java truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/Instrument.java truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/Instrumenter.java truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/Probe.java truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/ProbeInstrument.java truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/ProbeNode.java truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/SimpleInstrumentListener.java truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/StandardInstrumentListener.java truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/WrapperNode.java truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/package-info.java truffle/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/instrument/SLExpressionWrapperNode.java truffle/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/instrument/SLStatementWrapperNode.java truffle/com.oracle.truffle.tools/src/com/oracle/truffle/tools/CoverageTracker.java truffle/com.oracle.truffle.tools/src/com/oracle/truffle/tools/NodeExecCounter.java
diffstat 20 files changed, 699 insertions(+), 697 deletions(-) [+]
line wrap: on
line diff
--- a/truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/instrument/InstrumentationTest.java	Fri Sep 25 14:16:21 2015 -0700
+++ b/truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/instrument/InstrumentationTest.java	Fri Sep 25 14:58:35 2015 -0700
@@ -33,7 +33,7 @@
 
 import com.oracle.truffle.api.frame.VirtualFrame;
 import com.oracle.truffle.api.instrument.ASTProber;
-import com.oracle.truffle.api.instrument.Instrument;
+import com.oracle.truffle.api.instrument.ProbeInstrument;
 import com.oracle.truffle.api.instrument.Instrumenter;
 import com.oracle.truffle.api.instrument.Probe;
 import com.oracle.truffle.api.instrument.SimpleInstrumentListener;
@@ -58,7 +58,7 @@
  *
  * Instrumentation allows the insertion into Truffle ASTs language-specific instances of
  * {@link WrapperNode} that propagate execution events through a {@link Probe} to any instances of
- * {@link Instrument} that might be attached to the particular probe by tools.
+ * {@link ProbeInstrument} that might be attached to the particular probe by tools.
  */
 public class InstrumentationTest {
 
@@ -210,7 +210,7 @@
         public int enterCount = 0;
         public int leaveCount = 0;
         public Instrumenter instrumenter;
-        private Instrument instrument;
+        private ProbeInstrument instrument;
 
         public TestSimpleInstrumentCounter(Instrumenter instrumenter) {
             this.instrumenter = instrumenter;
@@ -263,7 +263,7 @@
         public int enterCount = 0;
         public int leaveCount = 0;
         public final Instrumenter instrumenter;
-        public Instrument instrument;
+        public ProbeInstrument instrument;
 
         public TestStandardInstrumentCounter(Instrumenter instrumenter) {
             this.instrumenter = instrumenter;
--- a/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/debug/Breakpoint.java	Fri Sep 25 14:16:21 2015 -0700
+++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/debug/Breakpoint.java	Fri Sep 25 14:58:35 2015 -0700
@@ -24,10 +24,12 @@
  */
 package com.oracle.truffle.api.debug;
 
-import com.oracle.truffle.api.instrument.Instrument;
+import java.io.IOException;
+
+import javax.sound.midi.Instrument;
+
 import com.oracle.truffle.api.instrument.Probe;
 import com.oracle.truffle.api.source.Source;
-import java.io.IOException;
 
 /**
  * Breakpoint in a {@link com.oracle.truffle.api.vm.TruffleVM} with
--- a/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/debug/LineBreakpointFactory.java	Fri Sep 25 14:16:21 2015 -0700
+++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/debug/LineBreakpointFactory.java	Fri Sep 25 14:58:35 2015 -0700
@@ -48,7 +48,7 @@
 import com.oracle.truffle.api.debug.Debugger.WarningLog;
 import com.oracle.truffle.api.frame.VirtualFrame;
 import com.oracle.truffle.api.instrument.AdvancedInstrumentResultListener;
-import com.oracle.truffle.api.instrument.Instrument;
+import com.oracle.truffle.api.instrument.ProbeInstrument;
 import com.oracle.truffle.api.instrument.Instrumenter;
 import com.oracle.truffle.api.instrument.Probe;
 import com.oracle.truffle.api.instrument.StandardSyntaxTag;
@@ -70,8 +70,8 @@
  * <ol>
  * <li>Line breakpoints can only be set at nodes tagged as {@link StandardSyntaxTag#STATEMENT}.</li>
  * <li>A newly created breakpoint looks for probes matching the location, attaches to them if found
- * by installing an {@link Instrument} that calls back to the breakpoint.</li>
- * <li>When Truffle "splits" or otherwise copies an AST, any attached {@link Instrument} will be
+ * by installing an {@link ProbeInstrument} that calls back to the breakpoint.</li>
+ * <li>When Truffle "splits" or otherwise copies an AST, any attached {@link ProbeInstrument} will be
  * copied along with the rest of the AST and will call back to the same breakpoint.</li>
  * <li>When notification is received of a new Node being tagged as a statement, and if a
  * breakpoint's line location matches the Probe's line location, then the breakpoint will attach a
@@ -291,7 +291,7 @@
          * The instrument(s) that this breakpoint currently has attached to a {@link Probe}:
          * {@code null} if not attached.
          */
-        private List<Instrument> instruments = new ArrayList<>();
+        private List<ProbeInstrument> instruments = new ArrayList<>();
 
         public LineBreakpointImpl(int ignoreCount, LineLocation lineLocation, boolean oneShot) {
             super(ENABLED_UNRESOLVED, ignoreCount, oneShot);
@@ -346,7 +346,7 @@
             if (this.conditionExpr != null || expr != null) {
                 // De-instrument the Probes instrumented by this breakpoint
                 final ArrayList<Probe> probes = new ArrayList<>();
-                for (Instrument instrument : instruments) {
+                for (ProbeInstrument instrument : instruments) {
                     probes.add(instrument.getProbe());
                     instrument.dispose();
                 }
@@ -368,7 +368,7 @@
         @Override
         public void dispose() {
             if (getState() != DISPOSED) {
-                for (Instrument instrument : instruments) {
+                for (ProbeInstrument instrument : instruments) {
                     instrument.dispose();
                 }
                 changeState(DISPOSED);
@@ -380,7 +380,7 @@
             if (getState() == DISPOSED) {
                 throw new IllegalStateException("Attempt to attach a disposed " + BREAKPOINT_NAME);
             }
-            Instrument newInstrument = null;
+            ProbeInstrument newInstrument = null;
             final Instrumenter instrumenter = debugger.getInstrumenter();
             if (conditionExpr == null) {
                 newInstrument = instrumenter.attach(newProbe, new UnconditionalLineBreakInstrumentListener(), BREAKPOINT_NAME);
--- a/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/debug/TagBreakpointFactory.java	Fri Sep 25 14:16:21 2015 -0700
+++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/debug/TagBreakpointFactory.java	Fri Sep 25 14:58:35 2015 -0700
@@ -46,7 +46,7 @@
 import com.oracle.truffle.api.debug.Debugger.WarningLog;
 import com.oracle.truffle.api.frame.VirtualFrame;
 import com.oracle.truffle.api.instrument.AdvancedInstrumentResultListener;
-import com.oracle.truffle.api.instrument.Instrument;
+import com.oracle.truffle.api.instrument.ProbeInstrument;
 import com.oracle.truffle.api.instrument.Instrumenter;
 import com.oracle.truffle.api.instrument.Probe;
 import com.oracle.truffle.api.instrument.SyntaxTag;
@@ -72,8 +72,8 @@
  * <ol>
  * <li>Only one Tag Breakpoint can be active for a specific {@linkplain SyntaxTag Tag}.</li>
  * <li>A newly created breakpoint looks for probes matching the tag, attaches to them if found by
- * installing an {@link Instrument}.</li>
- * <li>When Truffle "splits" or otherwise copies an AST, any attached {@link Instrument} will be
+ * installing an {@link ProbeInstrument}.</li>
+ * <li>When Truffle "splits" or otherwise copies an AST, any attached {@link ProbeInstrument} will be
  * copied along with the rest of the AST and will call back to the same breakpoint.</li>
  * <li>When notification is received that the breakpoint's Tag has been newly added to a Node, then
  * the breakpoint will attach a new Instrument at the probe to activate the breakpoint at that
@@ -260,7 +260,7 @@
          * The instrument(s) that this breakpoint currently has attached to a {@link Probe}:
          * {@code null} if not attached.
          */
-        private List<Instrument> instruments = new ArrayList<>();
+        private List<ProbeInstrument> instruments = new ArrayList<>();
 
         private TagBreakpointImpl(int ignoreCount, SyntaxTag tag, boolean oneShot) {
             super(ENABLED, ignoreCount, oneShot);
@@ -307,7 +307,7 @@
             if (this.conditionExpr != null || expr != null) {
                 // De-instrument the Probes instrumented by this breakpoint
                 final ArrayList<Probe> probes = new ArrayList<>();
-                for (Instrument instrument : instruments) {
+                for (ProbeInstrument instrument : instruments) {
                     probes.add(instrument.getProbe());
                     instrument.dispose();
                 }
@@ -329,7 +329,7 @@
         @Override
         public void dispose() {
             if (getState() != DISPOSED) {
-                for (Instrument instrument : instruments) {
+                for (ProbeInstrument instrument : instruments) {
                     instrument.dispose();
                 }
                 changeState(DISPOSED);
@@ -341,7 +341,7 @@
             if (getState() == DISPOSED) {
                 throw new IllegalStateException("Attempt to attach a disposed " + BREAKPOINT_NAME);
             }
-            Instrument newInstrument = null;
+            ProbeInstrument newInstrument = null;
             final Instrumenter instrumenter = debugger.getInstrumenter();
             if (conditionExpr == null) {
                 newInstrument = instrumenter.attach(newProbe, new UnconditionalTagBreakInstrumentListener(), BREAKPOINT_NAME);
--- a/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/AdvancedInstrumentResultListener.java	Fri Sep 25 14:16:21 2015 -0700
+++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/AdvancedInstrumentResultListener.java	Fri Sep 25 14:58:35 2015 -0700
@@ -37,7 +37,7 @@
  * Notification is fully synchronous, so overrides have performance implications. Non-trivial
  * methods should be coded with Truffle guidelines and cautions in mind.
  *
- * @see Instrument
+ * @see ProbeInstrument
  * @see AdvancedInstrumentRoot
  * @see AdvancedInstrumentRootFactory
  */
--- a/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/AdvancedInstrumentRoot.java	Fri Sep 25 14:16:21 2015 -0700
+++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/AdvancedInstrumentRoot.java	Fri Sep 25 14:58:35 2015 -0700
@@ -33,14 +33,14 @@
  * {@linkplain Instrumenter#attach(Probe, AdvancedInstrumentResultListener, AdvancedInstrumentRootFactory, Class, String)
  * Advanced Instrument}.
  *
- * @see Instrument
+ * @see ProbeInstrument
  * @see AdvancedInstrumentRootFactory
  * @see AdvancedInstrumentResultListener
  */
 public abstract class AdvancedInstrumentRoot extends Node implements InstrumentationNode {
 
     /**
-     * Executes this AST fragment on behalf of a client {@link Instrument}, just before the
+     * Executes this AST fragment on behalf of a client {@link ProbeInstrument}, just before the
      * guest-language AST node to which the {@link Probe} holding the Instrument is executed.
      *
      * @param node the guest-language AST node to which the host Instrument's Probe is attached
--- a/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/AdvancedInstrumentRootFactory.java	Fri Sep 25 14:16:21 2015 -0700
+++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/AdvancedInstrumentRootFactory.java	Fri Sep 25 14:58:35 2015 -0700
@@ -32,7 +32,7 @@
  * {@linkplain Instrumenter#attach(Probe, AdvancedInstrumentResultListener, AdvancedInstrumentRootFactory, Class, String)
  * Advanced Instrument}.
  *
- * @see Instrument
+ * @see ProbeInstrument
  * @see AdvancedInstrumentRoot
  */
 public interface AdvancedInstrumentRootFactory {
--- a/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/Instrument.java	Fri Sep 25 14:16:21 2015 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,619 +0,0 @@
-/*
- * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.truffle.api.instrument;
-
-import com.oracle.truffle.api.CompilerDirectives;
-import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
-import com.oracle.truffle.api.frame.VirtualFrame;
-import com.oracle.truffle.api.nodes.Node;
-import com.oracle.truffle.api.nodes.NodeCost;
-import com.oracle.truffle.api.nodes.NodeInfo;
-import com.oracle.truffle.api.source.SourceSection;
-
-/**
- * A <em>binding</em> between:
- * <ol>
- * <li>A {@link Probe}: a source of <em>execution events</em> taking place at a program location in
- * an executing Truffle AST, and</li>
- * <li>A <em>listener</em>: a consumer of execution events on behalf of an external client.
- * </ol>
- * <p>
- * Client-oriented documentation for the use of Instruments is available online at <a
- * HREF="https://wiki.openjdk.java.net/display/Graal/Listening+for+Execution+Events" >https://
- * wiki.openjdk.java.net/display/Graal/Listening+for+Execution+Events</a>
- *
- * @see Probe
- * @see EventHandlerNode
- */
-public abstract class Instrument {
-
-    /**
-     * Has this instrument been disposed? stays true once set.
-     */
-    private boolean isDisposed = false;
-
-    protected Probe probe = null;
-
-    /**
-     * Optional documentation, mainly for debugging.
-     */
-    private final String instrumentInfo;
-
-    /**
-     * <h4>Implementation Notes</h4>
-     * <p>
-     * The implementation of Instruments is complicated by the requirement that Truffle be able to
-     * clone ASTs at any time. In particular, any instrumentation-supporting Nodes that have been
-     * attached to an AST must be cloned along with the AST: AST clones are not permitted to share
-     * Nodes.
-     * <p>
-     * AST cloning is intended to be as <em>transparent</em> as possible to clients. This is
-     * encouraged by providing the {@link SimpleInstrumentListener} for clients that need know
-     * nothing more than the properties associated with a Probe: its {@link SourceSection} and any
-     * associated instances of {@link SyntaxTag}.
-     * <p>
-     * AST cloning is <em>not transparent</em> to clients that use the
-     * {@link StandardInstrumentListener}, since those event methods identify the concrete Node
-     * instance (and thus the AST instance) where the event takes place.
-     * <p>
-     * <h4>Implementation Notes: the Life Cycle of an {@link Instrument} at a {@link Probe}</h4>
-     * <p>
-     * <ul>
-     * <li>A new Instrument is created in permanent association with a client-provided
-     * <em>listener.</em></li>
-     *
-     * <li>Multiple Instruments may share a single listener.</li>
-     *
-     * <li>An Instrument does nothing until it is {@linkplain Probe#attach(Instrument) attached} to
-     * a Probe, at which time the Instrument begins routing execution events from the Probe's AST
-     * location to the Instrument's listener.</li>
-     *
-     * <li>Neither Instruments nor Probes are {@link Node}s.</li>
-     *
-     * <li>A Probe has a single source-based location in an AST, but manages a separate
-     * <em>instrumentation chain</em> of Nodes at the equivalent location in each clone of the AST.</li>
-     * <li>When a probed AST is cloned, the instrumentation chain associated with each Probe is
-     * cloned along with the rest of the AST.</li>
-     *
-     * <li>When a new Instrument is attached to a Probe, the Instrument inserts a new instance of
-     * its private Node type into <em>each of the instrument chains</em> managed by the Probe, i.e.
-     * one node instance per existing clone of the AST.</li>
-     *
-     * <li>If an Instrument is attached to a Probe in an AST that subsequently gets cloned, then the
-     * Instrument's private Node type will be cloned along with the rest of the the AST.</li>
-     * <li>Each Instrument's private Node type is a dynamic inner class whose only state is in the
-     * shared (outer) Instrument instance; that state includes a reference to the Instrument's
-     * listener.</li>
-     *
-     * <li>When an Instrument that has been attached to a Probe is {@linkplain #dispose() disposed},
-     * the Instrument searches every instrument chain associated with the Probe and removes the
-     * instance of its private Node type.</li>
-     *
-     * <li>Attaching or disposing an Instrument at a Probe <em>deoptimizes</em> any compilations of
-     * the AST.</li>
-     *
-     * </ul>
-     */
-    private Instrument(String instrumentInfo) {
-        this.instrumentInfo = instrumentInfo;
-    }
-
-    /**
-     * Gets the {@link Probe} to which this Instrument is currently attached: {@code null} if not
-     * yet attached to a Probe or if this Instrument has been {@linkplain #dispose() disposed}.
-     */
-    public Probe getProbe() {
-        return probe;
-    }
-
-    /**
-     * Removes this Instrument from the Probe to which it attached and renders this Instrument
-     * inert.
-     *
-     * @throws IllegalStateException if this instrument has already been disposed
-     */
-    public void dispose() throws IllegalStateException {
-        if (isDisposed) {
-            throw new IllegalStateException("Attempt to dispose an already disposed Instrumennt");
-        }
-        if (probe != null) {
-            // It's attached
-            probe.disposeInstrument(this);
-            probe = null;
-        }
-        this.isDisposed = true;
-    }
-
-    /**
-     * For internal implementation only.
-     */
-    void setAttachedTo(Probe probe) {
-        this.probe = probe;
-    }
-
-    /**
-     * Has this instrument been disposed and rendered unusable?
-     */
-    boolean isDisposed() {
-        return isDisposed;
-    }
-
-    abstract AbstractInstrumentNode addToChain(AbstractInstrumentNode nextNode);
-
-    /**
-     * Removes this instrument from an instrument chain.
-     */
-    abstract AbstractInstrumentNode removeFromChain(AbstractInstrumentNode instrumentNode);
-
-    /**
-     * An instrument that propagates events to an instance of {@link SimpleInstrumentListener}.
-     */
-    static final class SimpleInstrument extends Instrument {
-
-        /**
-         * Tool-supplied listener for events.
-         */
-        private final SimpleInstrumentListener simpleListener;
-
-        SimpleInstrument(SimpleInstrumentListener simpleListener, String instrumentInfo) {
-            super(instrumentInfo);
-            this.simpleListener = simpleListener;
-        }
-
-        @Override
-        AbstractInstrumentNode addToChain(AbstractInstrumentNode nextNode) {
-            return new SimpleInstrumentNode(nextNode);
-        }
-
-        @Override
-        AbstractInstrumentNode removeFromChain(AbstractInstrumentNode instrumentNode) {
-            boolean found = false;
-            if (instrumentNode != null) {
-                if (instrumentNode.getInstrument() == this) {
-                    // Found the match at the head of the chain
-                    return instrumentNode.nextInstrumentNode;
-                }
-                // Match not at the head of the chain; remove it.
-                found = instrumentNode.removeFromChain(SimpleInstrument.this);
-            }
-            if (!found) {
-                throw new IllegalStateException("Couldn't find instrument node to remove: " + this);
-            }
-            return instrumentNode;
-        }
-
-        /**
-         * Node that implements a {@link SimpleInstrument} in a particular AST.
-         */
-        @NodeInfo(cost = NodeCost.NONE)
-        private final class SimpleInstrumentNode extends AbstractInstrumentNode {
-
-            private SimpleInstrumentNode(AbstractInstrumentNode nextNode) {
-                super(nextNode);
-            }
-
-            @Override
-            public void enter(Node node, VirtualFrame vFrame) {
-                SimpleInstrument.this.simpleListener.onEnter(SimpleInstrument.this.probe);
-                if (nextInstrumentNode != null) {
-                    nextInstrumentNode.enter(node, vFrame);
-                }
-            }
-
-            @Override
-            public void returnVoid(Node node, VirtualFrame vFrame) {
-                SimpleInstrument.this.simpleListener.onReturnVoid(SimpleInstrument.this.probe);
-                if (nextInstrumentNode != null) {
-                    nextInstrumentNode.returnVoid(node, vFrame);
-                }
-            }
-
-            @Override
-            public void returnValue(Node node, VirtualFrame vFrame, Object result) {
-                SimpleInstrument.this.simpleListener.onReturnValue(SimpleInstrument.this.probe, result);
-                if (nextInstrumentNode != null) {
-                    nextInstrumentNode.returnValue(node, vFrame, result);
-                }
-            }
-
-            @Override
-            public void returnExceptional(Node node, VirtualFrame vFrame, Exception exception) {
-                SimpleInstrument.this.simpleListener.onReturnExceptional(SimpleInstrument.this.probe, exception);
-                if (nextInstrumentNode != null) {
-                    nextInstrumentNode.returnExceptional(node, vFrame, exception);
-                }
-            }
-
-            @Override
-            public String instrumentationInfo() {
-                final String info = getInstrumentInfo();
-                return info != null ? info : simpleListener.getClass().getSimpleName();
-            }
-        }
-    }
-
-    /**
-     * An instrument that propagates events to an instance of {@link StandardInstrumentListener}.
-     */
-    static final class StandardInstrument extends Instrument {
-
-        /**
-         * Tool-supplied listener for AST events.
-         */
-        private final StandardInstrumentListener standardListener;
-
-        StandardInstrument(StandardInstrumentListener standardListener, String instrumentInfo) {
-            super(instrumentInfo);
-            this.standardListener = standardListener;
-        }
-
-        @Override
-        AbstractInstrumentNode addToChain(AbstractInstrumentNode nextNode) {
-            return new StandardInstrumentNode(nextNode);
-        }
-
-        @Override
-        AbstractInstrumentNode removeFromChain(AbstractInstrumentNode instrumentNode) {
-            boolean found = false;
-            if (instrumentNode != null) {
-                if (instrumentNode.getInstrument() == this) {
-                    // Found the match at the head of the chain
-                    return instrumentNode.nextInstrumentNode;
-                }
-                // Match not at the head of the chain; remove it.
-                found = instrumentNode.removeFromChain(StandardInstrument.this);
-            }
-            if (!found) {
-                throw new IllegalStateException("Couldn't find instrument node to remove: " + this);
-            }
-            return instrumentNode;
-        }
-
-        /**
-         * Node that implements a {@link StandardInstrument} in a particular AST.
-         */
-        @NodeInfo(cost = NodeCost.NONE)
-        private final class StandardInstrumentNode extends AbstractInstrumentNode {
-
-            private StandardInstrumentNode(AbstractInstrumentNode nextNode) {
-                super(nextNode);
-            }
-
-            @Override
-            public void enter(Node node, VirtualFrame vFrame) {
-                standardListener.onEnter(StandardInstrument.this.probe, node, vFrame);
-                if (nextInstrumentNode != null) {
-                    nextInstrumentNode.enter(node, vFrame);
-                }
-            }
-
-            @Override
-            public void returnVoid(Node node, VirtualFrame vFrame) {
-                standardListener.onReturnVoid(StandardInstrument.this.probe, node, vFrame);
-                if (nextInstrumentNode != null) {
-                    nextInstrumentNode.returnVoid(node, vFrame);
-                }
-            }
-
-            @Override
-            public void returnValue(Node node, VirtualFrame vFrame, Object result) {
-                standardListener.onReturnValue(StandardInstrument.this.probe, node, vFrame, result);
-                if (nextInstrumentNode != null) {
-                    nextInstrumentNode.returnValue(node, vFrame, result);
-                }
-            }
-
-            @Override
-            public void returnExceptional(Node node, VirtualFrame vFrame, Exception exception) {
-                standardListener.onReturnExceptional(StandardInstrument.this.probe, node, vFrame, exception);
-                if (nextInstrumentNode != null) {
-                    nextInstrumentNode.returnExceptional(node, vFrame, exception);
-                }
-            }
-
-            @Override
-            public String instrumentationInfo() {
-                final String info = getInstrumentInfo();
-                return info != null ? info : standardListener.getClass().getSimpleName();
-            }
-        }
-    }
-
-    /**
-     * An instrument that allows clients to provide an AST fragment to be executed directly from
-     * within a Probe's <em>instrumentation chain</em>, and thus directly in the executing Truffle
-     * AST with potential for full optimization.
-     */
-    static final class AdvancedInstrument extends Instrument {
-
-        private final AdvancedInstrumentResultListener resultListener;
-        private final AdvancedInstrumentRootFactory rootFactory;
-        private final Class<?> requiredResultType;
-
-        AdvancedInstrument(AdvancedInstrumentResultListener resultListener, AdvancedInstrumentRootFactory rootFactory, Class<?> requiredResultType, String instrumentInfo) {
-            super(instrumentInfo);
-            this.resultListener = resultListener;
-            this.rootFactory = rootFactory;
-            this.requiredResultType = requiredResultType;
-        }
-
-        @Override
-        AbstractInstrumentNode addToChain(AbstractInstrumentNode nextNode) {
-            return new AdvancedInstrumentNode(nextNode);
-        }
-
-        @Override
-        AbstractInstrumentNode removeFromChain(AbstractInstrumentNode instrumentNode) {
-            boolean found = false;
-            if (instrumentNode != null) {
-                if (instrumentNode.getInstrument() == this) {
-                    // Found the match at the head of the chain
-                    return instrumentNode.nextInstrumentNode;
-                }
-                // Match not at the head of the chain; remove it.
-                found = instrumentNode.removeFromChain(AdvancedInstrument.this);
-            }
-            if (!found) {
-                throw new IllegalStateException("Couldn't find instrument node to remove: " + this);
-            }
-            return instrumentNode;
-        }
-
-        /**
-         * Node that implements a {@link AdvancedInstrument} in a particular AST.
-         */
-        @NodeInfo(cost = NodeCost.NONE)
-        private final class AdvancedInstrumentNode extends AbstractInstrumentNode {
-
-            @Child private AdvancedInstrumentRoot instrumentRoot;
-
-            private AdvancedInstrumentNode(AbstractInstrumentNode nextNode) {
-                super(nextNode);
-            }
-
-            @Override
-            public void enter(Node node, VirtualFrame vFrame) {
-                if (instrumentRoot == null) {
-                    try {
-                        final AdvancedInstrumentRoot newInstrumentRoot = AdvancedInstrument.this.rootFactory.createInstrumentRoot(AdvancedInstrument.this.probe, node);
-                        if (newInstrumentRoot != null) {
-                            instrumentRoot = newInstrumentRoot;
-                            adoptChildren();
-                            AdvancedInstrument.this.probe.invalidateProbeUnchanged();
-                        }
-                    } catch (RuntimeException ex) {
-                        if (resultListener != null) {
-                            resultListener.onFailure(node, vFrame, ex);
-                        }
-                    }
-                }
-                if (instrumentRoot != null) {
-                    try {
-                        final Object result = instrumentRoot.executeRoot(node, vFrame);
-                        if (resultListener != null) {
-                            checkResultType(result);
-                            resultListener.onExecution(node, vFrame, result);
-                        }
-                    } catch (RuntimeException ex) {
-                        if (resultListener != null) {
-                            resultListener.onFailure(node, vFrame, ex);
-                        }
-                    }
-                }
-                if (nextInstrumentNode != null) {
-                    nextInstrumentNode.enter(node, vFrame);
-                }
-            }
-
-            private void checkResultType(Object result) {
-                if (requiredResultType == null) {
-                    return;
-                }
-                if (result == null) {
-                    throw instrumentResultNull();
-                }
-                if (!(requiredResultType.isAssignableFrom(result.getClass()))) {
-                    throw instrumentResultWrongType(result);
-                }
-            }
-
-            @TruffleBoundary
-            private RuntimeException instrumentResultNull() {
-                return new RuntimeException("Instrument result null: " + requiredResultType.getSimpleName() + " is required");
-            }
-
-            @TruffleBoundary
-            private RuntimeException instrumentResultWrongType(Object result) {
-                return new RuntimeException("Instrument result " + result.toString() + " not assignable to " + requiredResultType.getSimpleName());
-            }
-
-            @Override
-            public void returnVoid(Node node, VirtualFrame vFrame) {
-                if (nextInstrumentNode != null) {
-                    nextInstrumentNode.returnVoid(node, vFrame);
-                }
-            }
-
-            @Override
-            public void returnValue(Node node, VirtualFrame vFrame, Object result) {
-                if (nextInstrumentNode != null) {
-                    nextInstrumentNode.returnValue(node, vFrame, result);
-                }
-            }
-
-            @Override
-            public void returnExceptional(Node node, VirtualFrame vFrame, Exception exception) {
-                if (nextInstrumentNode != null) {
-                    nextInstrumentNode.returnExceptional(node, vFrame, exception);
-                }
-            }
-
-            @Override
-            public String instrumentationInfo() {
-                final String info = getInstrumentInfo();
-                return info != null ? info : rootFactory.getClass().getSimpleName();
-            }
-        }
-    }
-
-    // TODO (mlvdv) experimental
-    public interface TruffleOptListener {
-        void notifyIsCompiled(boolean isCompiled);
-    }
-
-    @SuppressWarnings("unused")
-    private static final class TruffleOptInstrument extends Instrument {
-
-        private final TruffleOptListener toolOptListener;
-
-        private TruffleOptInstrument(TruffleOptListener listener, String instrumentInfo) {
-            super(instrumentInfo);
-            this.toolOptListener = listener;
-        }
-
-        @Override
-        AbstractInstrumentNode addToChain(AbstractInstrumentNode nextNode) {
-            return new TruffleOptInstrumentNode(nextNode);
-        }
-
-        @Override
-        AbstractInstrumentNode removeFromChain(AbstractInstrumentNode instrumentNode) {
-            boolean found = false;
-            if (instrumentNode != null) {
-                if (instrumentNode.getInstrument() == this) {
-                    // Found the match at the head of the chain
-                    return instrumentNode.nextInstrumentNode;
-                }
-                // Match not at the head of the chain; remove it.
-                found = instrumentNode.removeFromChain(TruffleOptInstrument.this);
-            }
-            if (!found) {
-                throw new IllegalStateException("Couldn't find instrument node to remove: " + this);
-            }
-            return instrumentNode;
-        }
-
-        @NodeInfo(cost = NodeCost.NONE)
-        private final class TruffleOptInstrumentNode extends AbstractInstrumentNode {
-
-            private boolean isCompiled;
-
-            private TruffleOptInstrumentNode(AbstractInstrumentNode nextNode) {
-                super(nextNode);
-                this.isCompiled = CompilerDirectives.inCompiledCode();
-            }
-
-            @Override
-            public void enter(Node node, VirtualFrame vFrame) {
-                if (this.isCompiled != CompilerDirectives.inCompiledCode()) {
-                    this.isCompiled = CompilerDirectives.inCompiledCode();
-                    TruffleOptInstrument.this.toolOptListener.notifyIsCompiled(this.isCompiled);
-                }
-                if (nextInstrumentNode != null) {
-                    nextInstrumentNode.enter(node, vFrame);
-                }
-            }
-
-            @Override
-            public void returnVoid(Node node, VirtualFrame vFrame) {
-                if (nextInstrumentNode != null) {
-                    nextInstrumentNode.returnVoid(node, vFrame);
-                }
-            }
-
-            @Override
-            public void returnValue(Node node, VirtualFrame vFrame, Object result) {
-                if (nextInstrumentNode != null) {
-                    nextInstrumentNode.returnValue(node, vFrame, result);
-                }
-            }
-
-            @Override
-            public void returnExceptional(Node node, VirtualFrame vFrame, Exception exception) {
-                if (nextInstrumentNode != null) {
-                    nextInstrumentNode.returnExceptional(node, vFrame, exception);
-                }
-            }
-
-            @Override
-            public String instrumentationInfo() {
-                final String info = getInstrumentInfo();
-                return info != null ? info : toolOptListener.getClass().getSimpleName();
-            }
-        }
-    }
-
-    @NodeInfo(cost = NodeCost.NONE)
-    abstract class AbstractInstrumentNode extends EventHandlerNode {
-
-        @Child protected AbstractInstrumentNode nextInstrumentNode;
-
-        protected AbstractInstrumentNode(AbstractInstrumentNode nextNode) {
-            this.nextInstrumentNode = nextNode;
-        }
-
-        @Override
-        public Probe getProbe() {
-            return probe;
-        }
-
-        /**
-         * Gets the instrument that created this node.
-         */
-        private Instrument getInstrument() {
-            return Instrument.this;
-        }
-
-        /**
-         * Removes the node from this chain that was added by a particular instrument, assuming that
-         * the head of the chain is not the one to be replaced. This is awkward, but is required
-         * because {@link Node#replace(Node)} won't take a {@code null} argument. This doesn't work
-         * for the tail of the list, which would be replacing itself with null. So the replacement
-         * must be directed the parent of the node being removed.
-         */
-        private boolean removeFromChain(Instrument instrument) {
-            assert getInstrument() != instrument;
-            if (nextInstrumentNode == null) {
-                return false;
-            }
-            if (nextInstrumentNode.getInstrument() == instrument) {
-                // Next is the one to remove
-                if (nextInstrumentNode.nextInstrumentNode == null) {
-                    // Next is at the tail; just forget
-                    nextInstrumentNode = null;
-                } else {
-                    // Replace next with its successor
-                    nextInstrumentNode.replace(nextInstrumentNode.nextInstrumentNode);
-                }
-                return true;
-            }
-            return nextInstrumentNode.removeFromChain(instrument);
-        }
-
-        protected String getInstrumentInfo() {
-            return Instrument.this.instrumentInfo;
-        }
-    }
-}
--- a/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/Instrumenter.java	Fri Sep 25 14:16:21 2015 -0700
+++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/Instrumenter.java	Fri Sep 25 14:58:35 2015 -0700
@@ -73,14 +73,14 @@
     }
 
     /**
-     * {@linkplain Instrument Instrumentation}-based collectors of data during Guest Language
+     * {@linkplain ProbeInstrument Instrumentation}-based collectors of data during Guest Language
      * program execution.
      * <p>
      * Tools share a common <em>life cycle</em>:
      * <ul>
      * <li>A newly created tool is inert until {@linkplain Instrumenter#install(Tool) installed}.</li>
      * <li>An installed tool becomes <em>enabled</em> and immediately begins installing
-     * {@linkplain Instrument instrumentation} on ASTs and collecting execution data from them.</li>
+     * {@linkplain ProbeInstrument instrumentation} on ASTs and collecting execution data from them.</li>
      * <li>A tool may only be installed once.</li>
      * <li>It should be possible to install multiple instances of a tool, possibly (but not
      * necessarily) configured differently with respect to what data is being collected.</li>
@@ -247,7 +247,7 @@
     }
 
     /**
-     * Prepares an AST node for {@linkplain Instrument instrumentation}, where the node is presumed
+     * Prepares an AST node for {@linkplain ProbeInstrument instrumentation}, where the node is presumed
      * to be part of a well-formed Truffle AST that has not yet been executed.
      * <p>
      * <em>Probing</em> a node is idempotent:
@@ -422,8 +422,8 @@
 
     /**
      * <em>Attaches</em> a {@link SimpleInstrumentListener listener} to a {@link Probe}, creating a
-     * <em>binding</em> called an {@link Instrument}. Until the Instrument is
-     * {@linkplain Instrument#dispose() disposed}, it routes synchronous notification of
+     * <em>binding</em> called an {@link ProbeInstrument}. Until the Instrument is
+     * {@linkplain ProbeInstrument#dispose() disposed}, it routes synchronous notification of
      * {@linkplain EventHandlerNode execution events} taking place at the Probe's AST location to
      * the listener.
      *
@@ -433,16 +433,16 @@
      * @return a handle for access to the binding
      */
     @SuppressWarnings("static-method")
-    public Instrument attach(Probe probe, SimpleInstrumentListener listener, String instrumentInfo) {
-        final Instrument instrument = new Instrument.SimpleInstrument(listener, instrumentInfo);
+    public ProbeInstrument attach(Probe probe, SimpleInstrumentListener listener, String instrumentInfo) {
+        final ProbeInstrument instrument = new ProbeInstrument.SimpleInstrument(listener, instrumentInfo);
         probe.attach(instrument);
         return instrument;
     }
 
     /**
      * <em>Attaches</em> a {@link StandardInstrumentListener listener} to a {@link Probe}, creating
-     * a <em>binding</em> called an {@link Instrument}. Until the Instrument is
-     * {@linkplain Instrument#dispose() disposed}, it routes synchronous notification of
+     * a <em>binding</em> called an {@link ProbeInstrument}. Until the Instrument is
+     * {@linkplain ProbeInstrument#dispose() disposed}, it routes synchronous notification of
      * {@linkplain EventHandlerNode execution events} taking place at the Probe's AST location to
      * the listener.
      *
@@ -452,16 +452,16 @@
      * @return a handle for access to the binding
      */
     @SuppressWarnings("static-method")
-    public Instrument attach(Probe probe, StandardInstrumentListener listener, String instrumentInfo) {
-        final Instrument instrument = new Instrument.StandardInstrument(listener, instrumentInfo);
+    public ProbeInstrument attach(Probe probe, StandardInstrumentListener listener, String instrumentInfo) {
+        final ProbeInstrument instrument = new ProbeInstrument.StandardInstrument(listener, instrumentInfo);
         probe.attach(instrument);
         return instrument;
     }
 
     /**
      * <em>Attaches</em> a {@link AdvancedInstrumentResultListener listener} to a {@link Probe},
-     * creating a <em>binding</em> called an {@link Instrument}. Until the Instrument is
-     * {@linkplain Instrument#dispose() disposed}, it routes synchronous notification of
+     * creating a <em>binding</em> called an {@link ProbeInstrument}. Until the Instrument is
+     * {@linkplain ProbeInstrument#dispose() disposed}, it routes synchronous notification of
      * {@linkplain EventHandlerNode execution events} taking place at the Probe's AST location to
      * the listener.
      * <p>
@@ -480,8 +480,8 @@
      * @return a handle for access to the binding
      */
     @SuppressWarnings("static-method")
-    public Instrument attach(Probe probe, AdvancedInstrumentResultListener listener, AdvancedInstrumentRootFactory rootFactory, Class<?> requiredResultType, String instrumentInfo) {
-        final Instrument instrument = new Instrument.AdvancedInstrument(listener, rootFactory, requiredResultType, instrumentInfo);
+    public ProbeInstrument attach(Probe probe, AdvancedInstrumentResultListener listener, AdvancedInstrumentRootFactory rootFactory, Class<?> requiredResultType, String instrumentInfo) {
+        final ProbeInstrument instrument = new ProbeInstrument.AdvancedInstrument(listener, rootFactory, requiredResultType, instrumentInfo);
         probe.attach(instrument);
         return instrument;
     }
--- a/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/Probe.java	Fri Sep 25 14:16:21 2015 -0700
+++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/Probe.java	Fri Sep 25 14:58:35 2015 -0700
@@ -44,7 +44,7 @@
  * <ol>
  * <li>A <em>guest language program location</em> in an executing Truffle AST (corresponding to a
  * {@link SourceSection}), and</li>
- * <li>A dynamically managed collection of <em>attached</em> {@linkplain Instrument Instruments}
+ * <li>A dynamically managed collection of <em>attached</em> {@linkplain ProbeInstrument Instruments}
  * that receive event notifications from the Probe's AST location on behalf of external clients.</li>
  * </ol>
  * <strong>Note</strong>:The relationship must be with an AST <em>location</em>, not a specific
@@ -57,7 +57,7 @@
  * <p>
  *
  * @see Instrumenter
- * @see Instrument
+ * @see ProbeInstrument
  * @see ASTProber
  * @see ProbeListener
  * @see SyntaxTag
@@ -115,7 +115,7 @@
      * </ul>
      * </li>
      * <li>The effect of the binding is to intercept {@linkplain EventHandlerNode execution events}
-     * arriving at the "probed" AST Node and notify each attached {@link Instrument} before
+     * arriving at the "probed" AST Node and notify each attached {@link ProbeInstrument} before
      * execution is allowed to proceed to the child and again after execution completes.</li>
      *
      * <li>The method {@link Instrumenter#probe(Node)} creates a Probe on an AST Node; redundant
@@ -130,7 +130,7 @@
      * <li>The "probing" of an AST Node is implemented by insertion of a
      * {@link ProbeNode.WrapperNode} into the AST (as new parent of the Node being probed), together
      * with an associated {@link ProbeNode} that routes execution events at the probed Node to all
-     * the {@linkplain Instrument Instruments} attached to the Probe's <em>instrument chain</em>.</li>
+     * the {@linkplain ProbeInstrument Instruments} attached to the Probe's <em>instrument chain</em>.</li>
      *
      * <li>When Truffle clones an AST, any attached WrapperNodes and ProbeNodes are cloned as well,
      * together with their attached instrument chains. Each Probe instance intercepts cloning events
@@ -207,7 +207,7 @@
      * @param instrument an instrument not yet attached to a probe
      * @throws IllegalStateException if the instrument has ever been attached before
      */
-    void attach(Instrument instrument) throws IllegalStateException {
+    void attach(ProbeInstrument instrument) throws IllegalStateException {
         if (instrument.isDisposed()) {
             throw new IllegalStateException("Attempt to attach disposed instrument");
         }
@@ -243,9 +243,9 @@
      *
      * @param instrument an instrument already attached
      * @throws IllegalStateException if instrument not attached at this Probe
-     * @see Instrument#dispose()
+     * @see ProbeInstrument#dispose()
      */
-    void disposeInstrument(Instrument instrument) throws IllegalStateException {
+    void disposeInstrument(ProbeInstrument instrument) throws IllegalStateException {
         for (WeakReference<ProbeNode> ref : probeNodeClones) {
             final ProbeNode probeNode = ref.get();
             if (probeNode != null) {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/ProbeInstrument.java	Fri Sep 25 14:58:35 2015 -0700
@@ -0,0 +1,619 @@
+/*
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.api.instrument;
+
+import com.oracle.truffle.api.CompilerDirectives;
+import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
+import com.oracle.truffle.api.frame.VirtualFrame;
+import com.oracle.truffle.api.nodes.Node;
+import com.oracle.truffle.api.nodes.NodeCost;
+import com.oracle.truffle.api.nodes.NodeInfo;
+import com.oracle.truffle.api.source.SourceSection;
+
+/**
+ * A <em>binding</em> between:
+ * <ol>
+ * <li>A {@link Probe}: a source of <em>execution events</em> taking place at a program location in
+ * an executing Truffle AST, and</li>
+ * <li>A <em>listener</em>: a consumer of execution events on behalf of an external client.
+ * </ol>
+ * <p>
+ * Client-oriented documentation for the use of Instruments is available online at <a
+ * HREF="https://wiki.openjdk.java.net/display/Graal/Listening+for+Execution+Events" >https://
+ * wiki.openjdk.java.net/display/Graal/Listening+for+Execution+Events</a>
+ *
+ * @see Probe
+ * @see EventHandlerNode
+ */
+public abstract class ProbeInstrument {
+
+    /**
+     * Has this instrument been disposed? stays true once set.
+     */
+    private boolean isDisposed = false;
+
+    protected Probe probe = null;
+
+    /**
+     * Optional documentation, mainly for debugging.
+     */
+    private final String instrumentInfo;
+
+    /**
+     * <h4>Implementation Notes</h4>
+     * <p>
+     * The implementation of Instruments is complicated by the requirement that Truffle be able to
+     * clone ASTs at any time. In particular, any instrumentation-supporting Nodes that have been
+     * attached to an AST must be cloned along with the AST: AST clones are not permitted to share
+     * Nodes.
+     * <p>
+     * AST cloning is intended to be as <em>transparent</em> as possible to clients. This is
+     * encouraged by providing the {@link SimpleInstrumentListener} for clients that need know
+     * nothing more than the properties associated with a Probe: its {@link SourceSection} and any
+     * associated instances of {@link SyntaxTag}.
+     * <p>
+     * AST cloning is <em>not transparent</em> to clients that use the
+     * {@link StandardInstrumentListener}, since those event methods identify the concrete Node
+     * instance (and thus the AST instance) where the event takes place.
+     * <p>
+     * <h4>Implementation Notes: the Life Cycle of an {@link ProbeInstrument} at a {@link Probe}</h4>
+     * <p>
+     * <ul>
+     * <li>A new Instrument is created in permanent association with a client-provided
+     * <em>listener.</em></li>
+     *
+     * <li>Multiple Instruments may share a single listener.</li>
+     *
+     * <li>An Instrument does nothing until it is {@linkplain Probe#attach(ProbeInstrument) attached} to
+     * a Probe, at which time the Instrument begins routing execution events from the Probe's AST
+     * location to the Instrument's listener.</li>
+     *
+     * <li>Neither Instruments nor Probes are {@link Node}s.</li>
+     *
+     * <li>A Probe has a single source-based location in an AST, but manages a separate
+     * <em>instrumentation chain</em> of Nodes at the equivalent location in each clone of the AST.</li>
+     * <li>When a probed AST is cloned, the instrumentation chain associated with each Probe is
+     * cloned along with the rest of the AST.</li>
+     *
+     * <li>When a new Instrument is attached to a Probe, the Instrument inserts a new instance of
+     * its private Node type into <em>each of the instrument chains</em> managed by the Probe, i.e.
+     * one node instance per existing clone of the AST.</li>
+     *
+     * <li>If an Instrument is attached to a Probe in an AST that subsequently gets cloned, then the
+     * Instrument's private Node type will be cloned along with the rest of the the AST.</li>
+     * <li>Each Instrument's private Node type is a dynamic inner class whose only state is in the
+     * shared (outer) Instrument instance; that state includes a reference to the Instrument's
+     * listener.</li>
+     *
+     * <li>When an Instrument that has been attached to a Probe is {@linkplain #dispose() disposed},
+     * the Instrument searches every instrument chain associated with the Probe and removes the
+     * instance of its private Node type.</li>
+     *
+     * <li>Attaching or disposing an Instrument at a Probe <em>deoptimizes</em> any compilations of
+     * the AST.</li>
+     *
+     * </ul>
+     */
+    private ProbeInstrument(String instrumentInfo) {
+        this.instrumentInfo = instrumentInfo;
+    }
+
+    /**
+     * Gets the {@link Probe} to which this Instrument is currently attached: {@code null} if not
+     * yet attached to a Probe or if this Instrument has been {@linkplain #dispose() disposed}.
+     */
+    public Probe getProbe() {
+        return probe;
+    }
+
+    /**
+     * Removes this Instrument from the Probe to which it attached and renders this Instrument
+     * inert.
+     *
+     * @throws IllegalStateException if this instrument has already been disposed
+     */
+    public void dispose() throws IllegalStateException {
+        if (isDisposed) {
+            throw new IllegalStateException("Attempt to dispose an already disposed Instrumennt");
+        }
+        if (probe != null) {
+            // It's attached
+            probe.disposeInstrument(this);
+            probe = null;
+        }
+        this.isDisposed = true;
+    }
+
+    /**
+     * For internal implementation only.
+     */
+    void setAttachedTo(Probe probe) {
+        this.probe = probe;
+    }
+
+    /**
+     * Has this instrument been disposed and rendered unusable?
+     */
+    boolean isDisposed() {
+        return isDisposed;
+    }
+
+    abstract AbstractInstrumentNode addToChain(AbstractInstrumentNode nextNode);
+
+    /**
+     * Removes this instrument from an instrument chain.
+     */
+    abstract AbstractInstrumentNode removeFromChain(AbstractInstrumentNode instrumentNode);
+
+    /**
+     * An instrument that propagates events to an instance of {@link SimpleInstrumentListener}.
+     */
+    static final class SimpleInstrument extends ProbeInstrument {
+
+        /**
+         * Tool-supplied listener for events.
+         */
+        private final SimpleInstrumentListener simpleListener;
+
+        SimpleInstrument(SimpleInstrumentListener simpleListener, String instrumentInfo) {
+            super(instrumentInfo);
+            this.simpleListener = simpleListener;
+        }
+
+        @Override
+        AbstractInstrumentNode addToChain(AbstractInstrumentNode nextNode) {
+            return new SimpleInstrumentNode(nextNode);
+        }
+
+        @Override
+        AbstractInstrumentNode removeFromChain(AbstractInstrumentNode instrumentNode) {
+            boolean found = false;
+            if (instrumentNode != null) {
+                if (instrumentNode.getInstrument() == this) {
+                    // Found the match at the head of the chain
+                    return instrumentNode.nextInstrumentNode;
+                }
+                // Match not at the head of the chain; remove it.
+                found = instrumentNode.removeFromChain(SimpleInstrument.this);
+            }
+            if (!found) {
+                throw new IllegalStateException("Couldn't find instrument node to remove: " + this);
+            }
+            return instrumentNode;
+        }
+
+        /**
+         * Node that implements a {@link SimpleInstrument} in a particular AST.
+         */
+        @NodeInfo(cost = NodeCost.NONE)
+        private final class SimpleInstrumentNode extends AbstractInstrumentNode {
+
+            private SimpleInstrumentNode(AbstractInstrumentNode nextNode) {
+                super(nextNode);
+            }
+
+            @Override
+            public void enter(Node node, VirtualFrame vFrame) {
+                SimpleInstrument.this.simpleListener.onEnter(SimpleInstrument.this.probe);
+                if (nextInstrumentNode != null) {
+                    nextInstrumentNode.enter(node, vFrame);
+                }
+            }
+
+            @Override
+            public void returnVoid(Node node, VirtualFrame vFrame) {
+                SimpleInstrument.this.simpleListener.onReturnVoid(SimpleInstrument.this.probe);
+                if (nextInstrumentNode != null) {
+                    nextInstrumentNode.returnVoid(node, vFrame);
+                }
+            }
+
+            @Override
+            public void returnValue(Node node, VirtualFrame vFrame, Object result) {
+                SimpleInstrument.this.simpleListener.onReturnValue(SimpleInstrument.this.probe, result);
+                if (nextInstrumentNode != null) {
+                    nextInstrumentNode.returnValue(node, vFrame, result);
+                }
+            }
+
+            @Override
+            public void returnExceptional(Node node, VirtualFrame vFrame, Exception exception) {
+                SimpleInstrument.this.simpleListener.onReturnExceptional(SimpleInstrument.this.probe, exception);
+                if (nextInstrumentNode != null) {
+                    nextInstrumentNode.returnExceptional(node, vFrame, exception);
+                }
+            }
+
+            @Override
+            public String instrumentationInfo() {
+                final String info = getInstrumentInfo();
+                return info != null ? info : simpleListener.getClass().getSimpleName();
+            }
+        }
+    }
+
+    /**
+     * An instrument that propagates events to an instance of {@link StandardInstrumentListener}.
+     */
+    static final class StandardInstrument extends ProbeInstrument {
+
+        /**
+         * Tool-supplied listener for AST events.
+         */
+        private final StandardInstrumentListener standardListener;
+
+        StandardInstrument(StandardInstrumentListener standardListener, String instrumentInfo) {
+            super(instrumentInfo);
+            this.standardListener = standardListener;
+        }
+
+        @Override
+        AbstractInstrumentNode addToChain(AbstractInstrumentNode nextNode) {
+            return new StandardInstrumentNode(nextNode);
+        }
+
+        @Override
+        AbstractInstrumentNode removeFromChain(AbstractInstrumentNode instrumentNode) {
+            boolean found = false;
+            if (instrumentNode != null) {
+                if (instrumentNode.getInstrument() == this) {
+                    // Found the match at the head of the chain
+                    return instrumentNode.nextInstrumentNode;
+                }
+                // Match not at the head of the chain; remove it.
+                found = instrumentNode.removeFromChain(StandardInstrument.this);
+            }
+            if (!found) {
+                throw new IllegalStateException("Couldn't find instrument node to remove: " + this);
+            }
+            return instrumentNode;
+        }
+
+        /**
+         * Node that implements a {@link StandardInstrument} in a particular AST.
+         */
+        @NodeInfo(cost = NodeCost.NONE)
+        private final class StandardInstrumentNode extends AbstractInstrumentNode {
+
+            private StandardInstrumentNode(AbstractInstrumentNode nextNode) {
+                super(nextNode);
+            }
+
+            @Override
+            public void enter(Node node, VirtualFrame vFrame) {
+                standardListener.onEnter(StandardInstrument.this.probe, node, vFrame);
+                if (nextInstrumentNode != null) {
+                    nextInstrumentNode.enter(node, vFrame);
+                }
+            }
+
+            @Override
+            public void returnVoid(Node node, VirtualFrame vFrame) {
+                standardListener.onReturnVoid(StandardInstrument.this.probe, node, vFrame);
+                if (nextInstrumentNode != null) {
+                    nextInstrumentNode.returnVoid(node, vFrame);
+                }
+            }
+
+            @Override
+            public void returnValue(Node node, VirtualFrame vFrame, Object result) {
+                standardListener.onReturnValue(StandardInstrument.this.probe, node, vFrame, result);
+                if (nextInstrumentNode != null) {
+                    nextInstrumentNode.returnValue(node, vFrame, result);
+                }
+            }
+
+            @Override
+            public void returnExceptional(Node node, VirtualFrame vFrame, Exception exception) {
+                standardListener.onReturnExceptional(StandardInstrument.this.probe, node, vFrame, exception);
+                if (nextInstrumentNode != null) {
+                    nextInstrumentNode.returnExceptional(node, vFrame, exception);
+                }
+            }
+
+            @Override
+            public String instrumentationInfo() {
+                final String info = getInstrumentInfo();
+                return info != null ? info : standardListener.getClass().getSimpleName();
+            }
+        }
+    }
+
+    /**
+     * An instrument that allows clients to provide an AST fragment to be executed directly from
+     * within a Probe's <em>instrumentation chain</em>, and thus directly in the executing Truffle
+     * AST with potential for full optimization.
+     */
+    static final class AdvancedInstrument extends ProbeInstrument {
+
+        private final AdvancedInstrumentResultListener resultListener;
+        private final AdvancedInstrumentRootFactory rootFactory;
+        private final Class<?> requiredResultType;
+
+        AdvancedInstrument(AdvancedInstrumentResultListener resultListener, AdvancedInstrumentRootFactory rootFactory, Class<?> requiredResultType, String instrumentInfo) {
+            super(instrumentInfo);
+            this.resultListener = resultListener;
+            this.rootFactory = rootFactory;
+            this.requiredResultType = requiredResultType;
+        }
+
+        @Override
+        AbstractInstrumentNode addToChain(AbstractInstrumentNode nextNode) {
+            return new AdvancedInstrumentNode(nextNode);
+        }
+
+        @Override
+        AbstractInstrumentNode removeFromChain(AbstractInstrumentNode instrumentNode) {
+            boolean found = false;
+            if (instrumentNode != null) {
+                if (instrumentNode.getInstrument() == this) {
+                    // Found the match at the head of the chain
+                    return instrumentNode.nextInstrumentNode;
+                }
+                // Match not at the head of the chain; remove it.
+                found = instrumentNode.removeFromChain(AdvancedInstrument.this);
+            }
+            if (!found) {
+                throw new IllegalStateException("Couldn't find instrument node to remove: " + this);
+            }
+            return instrumentNode;
+        }
+
+        /**
+         * Node that implements a {@link AdvancedInstrument} in a particular AST.
+         */
+        @NodeInfo(cost = NodeCost.NONE)
+        private final class AdvancedInstrumentNode extends AbstractInstrumentNode {
+
+            @Child private AdvancedInstrumentRoot instrumentRoot;
+
+            private AdvancedInstrumentNode(AbstractInstrumentNode nextNode) {
+                super(nextNode);
+            }
+
+            @Override
+            public void enter(Node node, VirtualFrame vFrame) {
+                if (instrumentRoot == null) {
+                    try {
+                        final AdvancedInstrumentRoot newInstrumentRoot = AdvancedInstrument.this.rootFactory.createInstrumentRoot(AdvancedInstrument.this.probe, node);
+                        if (newInstrumentRoot != null) {
+                            instrumentRoot = newInstrumentRoot;
+                            adoptChildren();
+                            AdvancedInstrument.this.probe.invalidateProbeUnchanged();
+                        }
+                    } catch (RuntimeException ex) {
+                        if (resultListener != null) {
+                            resultListener.onFailure(node, vFrame, ex);
+                        }
+                    }
+                }
+                if (instrumentRoot != null) {
+                    try {
+                        final Object result = instrumentRoot.executeRoot(node, vFrame);
+                        if (resultListener != null) {
+                            checkResultType(result);
+                            resultListener.onExecution(node, vFrame, result);
+                        }
+                    } catch (RuntimeException ex) {
+                        if (resultListener != null) {
+                            resultListener.onFailure(node, vFrame, ex);
+                        }
+                    }
+                }
+                if (nextInstrumentNode != null) {
+                    nextInstrumentNode.enter(node, vFrame);
+                }
+            }
+
+            private void checkResultType(Object result) {
+                if (requiredResultType == null) {
+                    return;
+                }
+                if (result == null) {
+                    throw instrumentResultNull();
+                }
+                if (!(requiredResultType.isAssignableFrom(result.getClass()))) {
+                    throw instrumentResultWrongType(result);
+                }
+            }
+
+            @TruffleBoundary
+            private RuntimeException instrumentResultNull() {
+                return new RuntimeException("Instrument result null: " + requiredResultType.getSimpleName() + " is required");
+            }
+
+            @TruffleBoundary
+            private RuntimeException instrumentResultWrongType(Object result) {
+                return new RuntimeException("Instrument result " + result.toString() + " not assignable to " + requiredResultType.getSimpleName());
+            }
+
+            @Override
+            public void returnVoid(Node node, VirtualFrame vFrame) {
+                if (nextInstrumentNode != null) {
+                    nextInstrumentNode.returnVoid(node, vFrame);
+                }
+            }
+
+            @Override
+            public void returnValue(Node node, VirtualFrame vFrame, Object result) {
+                if (nextInstrumentNode != null) {
+                    nextInstrumentNode.returnValue(node, vFrame, result);
+                }
+            }
+
+            @Override
+            public void returnExceptional(Node node, VirtualFrame vFrame, Exception exception) {
+                if (nextInstrumentNode != null) {
+                    nextInstrumentNode.returnExceptional(node, vFrame, exception);
+                }
+            }
+
+            @Override
+            public String instrumentationInfo() {
+                final String info = getInstrumentInfo();
+                return info != null ? info : rootFactory.getClass().getSimpleName();
+            }
+        }
+    }
+
+    // TODO (mlvdv) experimental
+    public interface TruffleOptListener {
+        void notifyIsCompiled(boolean isCompiled);
+    }
+
+    @SuppressWarnings("unused")
+    private static final class TruffleOptInstrument extends ProbeInstrument {
+
+        private final TruffleOptListener toolOptListener;
+
+        private TruffleOptInstrument(TruffleOptListener listener, String instrumentInfo) {
+            super(instrumentInfo);
+            this.toolOptListener = listener;
+        }
+
+        @Override
+        AbstractInstrumentNode addToChain(AbstractInstrumentNode nextNode) {
+            return new TruffleOptInstrumentNode(nextNode);
+        }
+
+        @Override
+        AbstractInstrumentNode removeFromChain(AbstractInstrumentNode instrumentNode) {
+            boolean found = false;
+            if (instrumentNode != null) {
+                if (instrumentNode.getInstrument() == this) {
+                    // Found the match at the head of the chain
+                    return instrumentNode.nextInstrumentNode;
+                }
+                // Match not at the head of the chain; remove it.
+                found = instrumentNode.removeFromChain(TruffleOptInstrument.this);
+            }
+            if (!found) {
+                throw new IllegalStateException("Couldn't find instrument node to remove: " + this);
+            }
+            return instrumentNode;
+        }
+
+        @NodeInfo(cost = NodeCost.NONE)
+        private final class TruffleOptInstrumentNode extends AbstractInstrumentNode {
+
+            private boolean isCompiled;
+
+            private TruffleOptInstrumentNode(AbstractInstrumentNode nextNode) {
+                super(nextNode);
+                this.isCompiled = CompilerDirectives.inCompiledCode();
+            }
+
+            @Override
+            public void enter(Node node, VirtualFrame vFrame) {
+                if (this.isCompiled != CompilerDirectives.inCompiledCode()) {
+                    this.isCompiled = CompilerDirectives.inCompiledCode();
+                    TruffleOptInstrument.this.toolOptListener.notifyIsCompiled(this.isCompiled);
+                }
+                if (nextInstrumentNode != null) {
+                    nextInstrumentNode.enter(node, vFrame);
+                }
+            }
+
+            @Override
+            public void returnVoid(Node node, VirtualFrame vFrame) {
+                if (nextInstrumentNode != null) {
+                    nextInstrumentNode.returnVoid(node, vFrame);
+                }
+            }
+
+            @Override
+            public void returnValue(Node node, VirtualFrame vFrame, Object result) {
+                if (nextInstrumentNode != null) {
+                    nextInstrumentNode.returnValue(node, vFrame, result);
+                }
+            }
+
+            @Override
+            public void returnExceptional(Node node, VirtualFrame vFrame, Exception exception) {
+                if (nextInstrumentNode != null) {
+                    nextInstrumentNode.returnExceptional(node, vFrame, exception);
+                }
+            }
+
+            @Override
+            public String instrumentationInfo() {
+                final String info = getInstrumentInfo();
+                return info != null ? info : toolOptListener.getClass().getSimpleName();
+            }
+        }
+    }
+
+    @NodeInfo(cost = NodeCost.NONE)
+    abstract class AbstractInstrumentNode extends EventHandlerNode {
+
+        @Child protected AbstractInstrumentNode nextInstrumentNode;
+
+        protected AbstractInstrumentNode(AbstractInstrumentNode nextNode) {
+            this.nextInstrumentNode = nextNode;
+        }
+
+        @Override
+        public Probe getProbe() {
+            return probe;
+        }
+
+        /**
+         * Gets the instrument that created this node.
+         */
+        private ProbeInstrument getInstrument() {
+            return ProbeInstrument.this;
+        }
+
+        /**
+         * Removes the node from this chain that was added by a particular instrument, assuming that
+         * the head of the chain is not the one to be replaced. This is awkward, but is required
+         * because {@link Node#replace(Node)} won't take a {@code null} argument. This doesn't work
+         * for the tail of the list, which would be replacing itself with null. So the replacement
+         * must be directed the parent of the node being removed.
+         */
+        private boolean removeFromChain(ProbeInstrument instrument) {
+            assert getInstrument() != instrument;
+            if (nextInstrumentNode == null) {
+                return false;
+            }
+            if (nextInstrumentNode.getInstrument() == instrument) {
+                // Next is the one to remove
+                if (nextInstrumentNode.nextInstrumentNode == null) {
+                    // Next is at the tail; just forget
+                    nextInstrumentNode = null;
+                } else {
+                    // Replace next with its successor
+                    nextInstrumentNode.replace(nextInstrumentNode.nextInstrumentNode);
+                }
+                return true;
+            }
+            return nextInstrumentNode.removeFromChain(instrument);
+        }
+
+        protected String getInstrumentInfo() {
+            return ProbeInstrument.this.instrumentInfo;
+        }
+    }
+}
--- a/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/ProbeNode.java	Fri Sep 25 14:16:21 2015 -0700
+++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/ProbeNode.java	Fri Sep 25 14:58:35 2015 -0700
@@ -27,7 +27,7 @@
 import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.api.frame.VirtualFrame;
-import com.oracle.truffle.api.instrument.Instrument.AbstractInstrumentNode;
+import com.oracle.truffle.api.instrument.ProbeInstrument.AbstractInstrumentNode;
 import com.oracle.truffle.api.nodes.Node;
 import com.oracle.truffle.api.nodes.NodeCost;
 import com.oracle.truffle.api.nodes.NodeInfo;
@@ -36,11 +36,11 @@
  * Implementation class & interface for enabling the attachment of {@linkplain Probe Probes} to
  * Truffle ASTs.
  * <p>
- * A {@link ProbeNode} is the head of a chain of nodes acting on behalf of {@linkplain Instrument
+ * A {@link ProbeNode} is the head of a chain of nodes acting on behalf of {@linkplain ProbeInstrument
  * instruments}. It is attached to an AST as a child of a guest-language-specific
  * {@link WrapperNode} node.
  * <p>
- * When Truffle clones an AST, the chain, including all attached {@linkplain Instrument instruments}
+ * When Truffle clones an AST, the chain, including all attached {@linkplain ProbeInstrument instruments}
  * will be cloned along with the {@link WrapperNode} to which it is attached. An instance of
  * {@link Probe} represents abstractly the instrumentation at a particular location in a Guest
  * Language AST, tracks the clones of the chain, and keeps the instrumentation attached to the
@@ -135,7 +135,7 @@
      * Adds an {@link AbstractInstrumentNode} to this chain.
      */
     @TruffleBoundary
-    void addInstrument(Instrument instrument) {
+    void addInstrument(ProbeInstrument instrument) {
         assert instrument.getProbe() == probe;
         // The existing chain of nodes may be empty
         // Attach the modified chain.
@@ -148,7 +148,7 @@
      * @throws RuntimeException if no matching instrument is found,
      */
     @TruffleBoundary
-    void removeInstrument(Instrument instrument) {
+    void removeInstrument(ProbeInstrument instrument) {
         assert instrument.getProbe() == probe;
         final AbstractInstrumentNode modifiedChain = instrument.removeFromChain(firstInstrumentNode);
         if (modifiedChain == null) {
--- a/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/SimpleInstrumentListener.java	Fri Sep 25 14:16:21 2015 -0700
+++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/SimpleInstrumentListener.java	Fri Sep 25 14:58:35 2015 -0700
@@ -37,7 +37,7 @@
  * execution state should use {@link StandardInstrumentListener}.
  * <p>
  * Clients are free, of course, to record additional information in the listener implementation that
- * carries additional information about the context and reason for the particular {@link Instrument}
+ * carries additional information about the context and reason for the particular {@link ProbeInstrument}
  * that is to be created from the listener.
  * <p>
  * Notification is fully synchronous, so overrides have performance implications. Non-trivial
--- a/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/StandardInstrumentListener.java	Fri Sep 25 14:16:21 2015 -0700
+++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/StandardInstrumentListener.java	Fri Sep 25 14:58:35 2015 -0700
@@ -39,7 +39,7 @@
  * {@link SimpleInstrumentListener}.
  * <p>
  * Clients are free, of course, to record additional information in the listener implementation that
- * carries additional information about the context and reason for the particular {@link Instrument}
+ * carries additional information about the context and reason for the particular {@link ProbeInstrument}
  * that is to be created from the listener.
  * <p>
  * Notification is fully synchronous, so overrides have performance implications. Non-trivial
--- a/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/WrapperNode.java	Fri Sep 25 14:16:21 2015 -0700
+++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/WrapperNode.java	Fri Sep 25 14:58:35 2015 -0700
@@ -28,7 +28,7 @@
 
 /**
  * A {@link Node} instance that must be inserted into a Truffle AST in order to enable
- * {@linkplain Instrument instrumentation} at a particular Guest Language (GL) node.
+ * {@linkplain ProbeInstrument instrumentation} at a particular Guest Language (GL) node.
  * <p>
  * The implementation must be GL-specific. A wrapper <em>decorates</em> a GL AST node (the wrapper's
  * <em>child</em>) by acting as a transparent <em>proxy</em> with respect to the GL's execution
@@ -41,7 +41,7 @@
  * at the wrapped AST node during program execution.
  * <p>
  * When a GL AST is cloned, the {@link WrapperNode}, its {@link EventHandlerNode} and any
- * {@linkplain Instrument instrumentation} are also cloned; they are in effect part of the GL AST.
+ * {@linkplain ProbeInstrument instrumentation} are also cloned; they are in effect part of the GL AST.
  * An instance of {@link Probe} represents abstractly the instrumentation at a particular location
  * in a GL AST; it tracks all the copies of the Wrapper and attached instrumentation, and acts as a
  * single point of access for tools.
@@ -60,11 +60,11 @@
  * <li>Method {@code insertProbe(EventHandlerNode)} should be implemented as
  * {@code this.eventHandlerNode=insert(eventHandlerNode);}</li>
  * <li>Most importantly, Wrappers must be implemented so that Truffle optimization will reduce their
- * runtime overhead to zero when there are no attached {@link Instrument}s.</li>
+ * runtime overhead to zero when there are no attached {@link ProbeInstrument}s.</li>
  * </ol>
  * <p>
  *
- * @see Instrument
+ * @see ProbeInstrument
  */
 public interface WrapperNode extends InstrumentationNode {
 
--- a/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/package-info.java	Fri Sep 25 14:16:21 2015 -0700
+++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/package-info.java	Fri Sep 25 14:58:35 2015 -0700
@@ -119,12 +119,12 @@
  * <li>Clients can be notified of <em>AST execution events</em> by creating one of several kinds of
  * <em>event listener</em> and <em>attaching</em> it to a
  * {@linkplain com.oracle.truffle.api.instrument.Probe Probe}. This creates an
- * {@linkplain com.oracle.truffle.api.instrument.Instrument Instrument} that notifies the listener
+ * {@linkplain com.oracle.truffle.api.instrument.ProbeInstrument Instrument} that notifies the listener
  * of every subsequent execution event at the AST location corresponding to the
  * {@linkplain com.oracle.truffle.api.instrument.Probe Probe}.</li>
  * <li>An
- * {@linkplain com.oracle.truffle.api.instrument.Instrument Instrument} can be
- * {@linkplain com.oracle.truffle.api.instrument.Instrument#dispose() disposed}, at which time
+ * {@linkplain com.oracle.truffle.api.instrument.ProbeInstrument Instrument} can be
+ * {@linkplain com.oracle.truffle.api.instrument.ProbeInstrument#dispose() disposed}, at which time
  * it is removed from service at every clone of the AST, incurs no further overhead, and is
  * permanently unusable.</li>
  * <li>Many clients need only implement a
@@ -140,7 +140,7 @@
  * {@linkplain com.oracle.truffle.api.nodes.Node AST location} and current
  * {@linkplain com.oracle.truffle.api.frame.Frame stack frame}.</li>
  * <li>Clients can also create an
- * {@linkplain com.oracle.truffle.api.instrument.Instrument Instrument} (whose design is currently
+ * {@linkplain com.oracle.truffle.api.instrument.ProbeInstrument Instrument} (whose design is currently
  * under revision) that supports (effectively) inserting a Truffle AST fragment into the AST
  * location, where it will be executed subject to full Truffle optimization.</li>
  * </ul></li>
--- a/truffle/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/instrument/SLExpressionWrapperNode.java	Fri Sep 25 14:16:21 2015 -0700
+++ b/truffle/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/instrument/SLExpressionWrapperNode.java	Fri Sep 25 14:58:35 2015 -0700
@@ -42,7 +42,7 @@
 
 import com.oracle.truffle.api.frame.VirtualFrame;
 import com.oracle.truffle.api.instrument.EventHandlerNode;
-import com.oracle.truffle.api.instrument.Instrument;
+import com.oracle.truffle.api.instrument.ProbeInstrument;
 import com.oracle.truffle.api.instrument.KillException;
 import com.oracle.truffle.api.instrument.Probe;
 import com.oracle.truffle.api.instrument.WrapperNode;
@@ -57,7 +57,7 @@
 /**
  * A Truffle node that can be inserted into a Simple AST (assumed not to have executed yet) to
  * enable "instrumentation" of an {@link SLExpressionNode}. Tools wishing to interact with AST
- * execution may attach {@link Instrument}s to the {@link Probe} uniquely associated with the
+ * execution may attach {@link ProbeInstrument}s to the {@link Probe} uniquely associated with the
  * wrapper, and to which this wrapper routes execution events.
  */
 @NodeInfo(cost = NodeCost.NONE)
--- a/truffle/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/instrument/SLStatementWrapperNode.java	Fri Sep 25 14:16:21 2015 -0700
+++ b/truffle/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/instrument/SLStatementWrapperNode.java	Fri Sep 25 14:58:35 2015 -0700
@@ -42,7 +42,7 @@
 
 import com.oracle.truffle.api.frame.VirtualFrame;
 import com.oracle.truffle.api.instrument.EventHandlerNode;
-import com.oracle.truffle.api.instrument.Instrument;
+import com.oracle.truffle.api.instrument.ProbeInstrument;
 import com.oracle.truffle.api.instrument.KillException;
 import com.oracle.truffle.api.instrument.Probe;
 import com.oracle.truffle.api.instrument.WrapperNode;
@@ -54,7 +54,7 @@
 /**
  * A Truffle node that can be inserted into a Simple AST (assumed not to have executed yet) to
  * enable "instrumentation" of a {@link SLStatementNode}. Tools wishing to interact with AST
- * execution may attach {@link Instrument}s to the {@link Probe} uniquely associated with the
+ * execution may attach {@link ProbeInstrument}s to the {@link Probe} uniquely associated with the
  * wrapper, and to which this wrapper routes execution events.
  */
 @NodeInfo(cost = NodeCost.NONE)
--- a/truffle/com.oracle.truffle.tools/src/com/oracle/truffle/tools/CoverageTracker.java	Fri Sep 25 14:16:21 2015 -0700
+++ b/truffle/com.oracle.truffle.tools/src/com/oracle/truffle/tools/CoverageTracker.java	Fri Sep 25 14:58:35 2015 -0700
@@ -33,7 +33,7 @@
 import java.util.Map.Entry;
 import java.util.TreeSet;
 
-import com.oracle.truffle.api.instrument.Instrument;
+import com.oracle.truffle.api.instrument.ProbeInstrument;
 import com.oracle.truffle.api.instrument.Instrumenter;
 import com.oracle.truffle.api.instrument.Probe;
 import com.oracle.truffle.api.instrument.ProbeListener;
@@ -79,7 +79,7 @@
  * any time in a simple textual format, with no other effect on the state of the tool.
  * </p>
  *
- * @see Instrument
+ * @see ProbeInstrument
  * @see SyntaxTag
  */
 public final class CoverageTracker extends Instrumenter.Tool<CoverageTracker> {
@@ -88,7 +88,7 @@
     private final Map<LineLocation, CoverageRecord> coverageMap = new HashMap<>();
 
     /** Needed for disposal. */
-    private final List<Instrument> instruments = new ArrayList<>();
+    private final List<ProbeInstrument> instruments = new ArrayList<>();
 
     /**
      * Coverage counting is restricted to nodes holding this tag.
@@ -132,7 +132,7 @@
     @Override
     protected void internalDispose() {
         getInstrumenter().removeProbeListener(probeListener);
-        for (Instrument instrument : instruments) {
+        for (ProbeInstrument instrument : instruments) {
             instrument.dispose();
         }
     }
@@ -247,7 +247,7 @@
     private final class CoverageRecord extends DefaultSimpleInstrumentListener {
 
         private final SourceSection srcSection; // The text of the code being counted
-        private Instrument instrument;  // The attached Instrument, in case need to remove.
+        private ProbeInstrument instrument;  // The attached Instrument, in case need to remove.
         private long count = 0;
 
         CoverageRecord(SourceSection srcSection) {
@@ -304,7 +304,7 @@
         }
 
         final CoverageRecord coverageRecord = new CoverageRecord(srcSection);
-        final Instrument instrument = getInstrumenter().attach(probe, coverageRecord, CoverageTracker.class.getSimpleName());
+        final ProbeInstrument instrument = getInstrumenter().attach(probe, coverageRecord, CoverageTracker.class.getSimpleName());
         coverageRecord.instrument = instrument;
         instruments.add(instrument);
         coverageMap.put(lineLocation, coverageRecord);
--- a/truffle/com.oracle.truffle.tools/src/com/oracle/truffle/tools/NodeExecCounter.java	Fri Sep 25 14:16:21 2015 -0700
+++ b/truffle/com.oracle.truffle.tools/src/com/oracle/truffle/tools/NodeExecCounter.java	Fri Sep 25 14:58:35 2015 -0700
@@ -37,7 +37,7 @@
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.api.frame.VirtualFrame;
 import com.oracle.truffle.api.instrument.ASTProber;
-import com.oracle.truffle.api.instrument.Instrument;
+import com.oracle.truffle.api.instrument.ProbeInstrument;
 import com.oracle.truffle.api.instrument.Instrumenter;
 import com.oracle.truffle.api.instrument.Probe;
 import com.oracle.truffle.api.instrument.ProbeException;
@@ -93,7 +93,7 @@
  * any time in a simple textual format, without effect on the state of the tool.
  * </p>
  *
- * @see Instrument
+ * @see ProbeInstrument
  * @see SyntaxTag
  * @see ProbeFailure
  */
@@ -110,7 +110,7 @@
 
     /**
      * Listener for events at instrumented nodes. Counts are maintained in a shared table, so the
-     * listener is stateless and can be shared by every {@link Instrument}.
+     * listener is stateless and can be shared by every {@link ProbeInstrument}.
      */
     private final StandardInstrumentListener instrumentListener = new DefaultStandardInstrumentListener() {
         @Override
@@ -151,7 +151,7 @@
     private final List<ProbeFailure> failures = new ArrayList<>();
 
     /** For disposal. */
-    private final List<Instrument> instruments = new ArrayList<>();
+    private final List<ProbeInstrument> instruments = new ArrayList<>();
 
     /**
      * If non-null, counting is restricted to nodes holding this tag.
@@ -209,7 +209,7 @@
         if (probeListener != null) {
             getInstrumenter().removeProbeListener(probeListener);
         }
-        for (Instrument instrument : instruments) {
+        for (ProbeInstrument instrument : instruments) {
             instrument.dispose();
         }
     }
@@ -301,7 +301,7 @@
                     try {
 
                         final Probe probe = instrumenter.probe(node);
-                        final Instrument instrument = instrumenter.attach(probe, instrumentListener, "NodeExecCounter");
+                        final ProbeInstrument instrument = instrumenter.attach(probe, instrumentListener, "NodeExecCounter");
                         instruments.add(instrument);
                     } catch (ProbeException ex) {
                         failures.add(ex.getFailure());
@@ -322,7 +322,7 @@
         @Override
         public void probeTaggedAs(Probe probe, SyntaxTag tag, Object tagValue) {
             if (countingTag == tag) {
-                final Instrument instrument = getInstrumenter().attach(probe, instrumentListener, NodeExecCounter.class.getSimpleName());
+                final ProbeInstrument instrument = getInstrumenter().attach(probe, instrumentListener, NodeExecCounter.class.getSimpleName());
                 instruments.add(instrument);
             }
         }