changeset 22225:a0fa69e3e60e

Truffle/Instrumentation: remove static Instrument factory methods, now supported by Instrumenter
author Michael Van De Vanter <michael.van.de.vanter@oracle.com>
date Sat, 19 Sep 2015 16:29:32 -0700
parents 776dc0a09749
children c896a8e70777
files truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/instrument/AdvancedInstrumentTest.java 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/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/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.sl.test/src/com/oracle/truffle/sl/test/instrument/SLInstrumentTestRunner.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 10 files changed, 207 insertions(+), 153 deletions(-) [+]
line wrap: on
line diff
--- a/truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/instrument/AdvancedInstrumentTest.java	Sat Sep 19 13:56:42 2015 -0700
+++ b/truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/instrument/AdvancedInstrumentTest.java	Sat Sep 19 16:29:32 2015 -0700
@@ -33,7 +33,6 @@
 
 import com.oracle.truffle.api.instrument.AdvancedInstrumentRoot;
 import com.oracle.truffle.api.instrument.AdvancedInstrumentRootFactory;
-import com.oracle.truffle.api.instrument.Instrument;
 import com.oracle.truffle.api.instrument.Instrumenter;
 import com.oracle.truffle.api.instrument.Probe;
 import com.oracle.truffle.api.instrument.ProbeListener;
@@ -82,26 +81,27 @@
         assertEquals(vm.eval(source).get(), 13);
         assertNotNull("Add node should be probed", addNodeProbe[0]);
 
-        // Attach a null factory; it never actually attaches a node.
-        final Instrument instrument = Instrument.create(null, new AdvancedInstrumentRootFactory() {
+        // Attach a factory that never actually attaches a node.
+        final AdvancedInstrumentRootFactory rootFactory1 = new AdvancedInstrumentRootFactory() {
 
             public AdvancedInstrumentRoot createInstrumentRoot(Probe p, Node n) {
                 return null;
             }
-        }, null, "test AdvancedInstrument");
-        addNodeProbe[0].attach(instrument);
+        };
+        instrumenter.attach(addNodeProbe[0], null, rootFactory1, null, "test AdvancedInstrument");
 
         assertEquals(vm.eval(source).get(), 13);
 
+        // Attach a factory that splices an execution counter into the AST.
         final TestAdvancedInstrumentCounterRoot counter = new TestAdvancedInstrumentCounterRoot();
-
-        // Attach a factory that splices an execution counter into the AST.
-        addNodeProbe[0].attach(Instrument.create(null, new AdvancedInstrumentRootFactory() {
+        final AdvancedInstrumentRootFactory rootFactory2 = new AdvancedInstrumentRootFactory() {
 
             public AdvancedInstrumentRoot createInstrumentRoot(Probe p, Node n) {
                 return counter;
             }
-        }, null, "test AdvancedInstrument"));
+        };
+        instrumenter.attach(addNodeProbe[0], null, rootFactory2, null, "test AdvancedInstrument");
+
         assertEquals(0, counter.getCount());
         assertEquals(vm.eval(source).get(), 13);
         assertEquals(1, counter.getCount());
--- a/truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/instrument/InstrumentationTest.java	Sat Sep 19 13:56:42 2015 -0700
+++ b/truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/instrument/InstrumentationTest.java	Sat Sep 19 16:29:32 2015 -0700
@@ -116,10 +116,10 @@
         assertNotNull("Value nodes should be probed", probes[2]);
         // Check instrumentation with the simplest kind of counters.
         // They should all be removed when the check is finished.
-        checkCounters(probes[0], vm, source, new TestSimpleInstrumentCounter(), new TestSimpleInstrumentCounter(), new TestSimpleInstrumentCounter());
+        checkCounters(probes[0], vm, source, new TestSimpleInstrumentCounter(instrumenter), new TestSimpleInstrumentCounter(instrumenter), new TestSimpleInstrumentCounter(instrumenter));
 
         // Now try with the more complex flavor of listener
-        checkCounters(probes[0], vm, source, new TestStandardInstrumentCounter(), new TestStandardInstrumentCounter(), new TestStandardInstrumentCounter());
+        checkCounters(probes[0], vm, source, new TestStandardInstrumentCounter(instrumenter), new TestStandardInstrumentCounter(instrumenter), new TestStandardInstrumentCounter(instrumenter));
 
     }
 
@@ -230,28 +230,11 @@
 
         public int enterCount = 0;
         public int leaveCount = 0;
-        public final Instrument instrument;
-
-        public TestSimpleInstrumentCounter() {
-            this.instrument = Instrument.create(new SimpleInstrumentListener() {
-
-                public void enter(Probe probe) {
-                    enterCount++;
-                }
+        public Instrumenter instrumenter;
+        private Instrument instrument;
 
-                public void returnVoid(Probe probe) {
-                    leaveCount++;
-                }
-
-                public void returnValue(Probe probe, Object result) {
-                    leaveCount++;
-                }
-
-                public void returnExceptional(Probe probe, Exception exception) {
-                    leaveCount++;
-                }
-
-            }, "Instrumentation Test Counter");
+        public TestSimpleInstrumentCounter(Instrumenter instrumenter) {
+            this.instrumenter = instrumenter;
         }
 
         @Override
@@ -266,7 +249,25 @@
 
         @Override
         public void attach(Probe probe) {
-            probe.attach(instrument);
+            instrument = instrumenter.attach(probe, new SimpleInstrumentListener() {
+
+                public void enter(Probe p) {
+                    enterCount++;
+                }
+
+                public void returnVoid(Probe p) {
+                    leaveCount++;
+                }
+
+                public void returnValue(Probe p, Object result) {
+                    leaveCount++;
+                }
+
+                public void returnExceptional(Probe p, Exception exception) {
+                    leaveCount++;
+                }
+
+            }, "Instrumentation Test Counter");
         }
 
         @Override
@@ -282,28 +283,11 @@
 
         public int enterCount = 0;
         public int leaveCount = 0;
-        public final Instrument instrument;
-
-        public TestStandardInstrumentCounter() {
-            this.instrument = Instrument.create(new StandardInstrumentListener() {
-
-                public void enter(Probe probe, Node node, VirtualFrame vFrame) {
-                    enterCount++;
-                }
+        public final Instrumenter instrumenter;
+        public Instrument instrument;
 
-                public void returnVoid(Probe probe, Node node, VirtualFrame vFrame) {
-                    leaveCount++;
-                }
-
-                public void returnValue(Probe probe, Node node, VirtualFrame vFrame, Object result) {
-                    leaveCount++;
-                }
-
-                public void returnExceptional(Probe probe, Node node, VirtualFrame vFrame, Exception exception) {
-                    leaveCount++;
-                }
-
-            }, "Instrumentation Test Counter");
+        public TestStandardInstrumentCounter(Instrumenter instrumenter) {
+            this.instrumenter = instrumenter;
         }
 
         @Override
@@ -318,7 +302,25 @@
 
         @Override
         public void attach(Probe probe) {
-            probe.attach(instrument);
+            instrument = instrumenter.attach(probe, new StandardInstrumentListener() {
+
+                public void enter(Probe p, Node node, VirtualFrame vFrame) {
+                    enterCount++;
+                }
+
+                public void returnVoid(Probe p, Node node, VirtualFrame vFrame) {
+                    leaveCount++;
+                }
+
+                public void returnValue(Probe p, Node node, VirtualFrame vFrame, Object result) {
+                    leaveCount++;
+                }
+
+                public void returnExceptional(Probe p, Node node, VirtualFrame vFrame, Exception exception) {
+                    leaveCount++;
+                }
+
+            }, "Instrumentation Test Counter");
         }
 
         @Override
--- a/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/debug/LineBreakpointFactory.java	Sat Sep 19 13:56:42 2015 -0700
+++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/debug/LineBreakpointFactory.java	Sat Sep 19 16:29:32 2015 -0700
@@ -382,12 +382,12 @@
                 throw new IllegalStateException("Attempt to attach a disposed " + BREAKPOINT_NAME);
             }
             Instrument newInstrument = null;
+            final Instrumenter instrumenter = debugger.getInstrumenter();
             if (conditionExpr == null) {
-                newInstrument = Instrument.create(new UnconditionalLineBreakInstrumentListener(), BREAKPOINT_NAME);
+                newInstrument = instrumenter.attach(newProbe, new UnconditionalLineBreakInstrumentListener(), BREAKPOINT_NAME);
             } else {
-                newInstrument = Instrument.create(this, debugger.createAdvancedInstrumentRootFactory(newProbe, conditionExpr, this), Boolean.class, BREAKPOINT_NAME);
+                newInstrument = instrumenter.attach(newProbe, this, debugger.createAdvancedInstrumentRootFactory(newProbe, conditionExpr, this), Boolean.class, BREAKPOINT_NAME);
             }
-            newProbe.attach(newInstrument);
             instruments.add(newInstrument);
             changeState(isEnabled ? ENABLED : DISABLED);
         }
--- a/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/debug/TagBreakpointFactory.java	Sat Sep 19 13:56:42 2015 -0700
+++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/debug/TagBreakpointFactory.java	Sat Sep 19 16:29:32 2015 -0700
@@ -342,12 +342,12 @@
                 throw new IllegalStateException("Attempt to attach a disposed " + BREAKPOINT_NAME);
             }
             Instrument newInstrument = null;
+            final Instrumenter instrumenter = debugger.getInstrumenter();
             if (conditionExpr == null) {
-                newInstrument = Instrument.create(new UnconditionalTagBreakInstrumentListener(), BREAKPOINT_NAME);
+                newInstrument = instrumenter.attach(newProbe, new UnconditionalTagBreakInstrumentListener(), BREAKPOINT_NAME);
             } else {
-                newInstrument = Instrument.create(this, debugger.createAdvancedInstrumentRootFactory(newProbe, conditionExpr, this), Boolean.class, BREAKPOINT_NAME);
+                instrumenter.attach(newProbe, this, debugger.createAdvancedInstrumentRootFactory(newProbe, conditionExpr, this), Boolean.class, BREAKPOINT_NAME);
             }
-            newProbe.attach(newInstrument);
             instruments.add(newInstrument);
             changeState(isEnabled ? ENABLED : DISABLED);
         }
--- a/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/Instrument.java	Sat Sep 19 13:56:42 2015 -0700
+++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/Instrument.java	Sat Sep 19 16:29:32 2015 -0700
@@ -33,9 +33,6 @@
 import com.oracle.truffle.api.nodes.NodeInfo;
 import com.oracle.truffle.api.source.SourceSection;
 
-// TODO (mlvdv) these statics should not be global.  Move them to some kind of context.
-// TODO (mlvdv) migrate factory (together with Probe)? break out nested classes?
-
 /**
  * A <em>binding</em> between:
  * <ol>
@@ -47,73 +44,13 @@
  * 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>
- * <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: it's {@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 (for example an instance created by
- * {@link Instrument#create(com.oracle.truffle.api.instrument.SimpleInstrumentListener, java.lang.String)}
- * 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 and disposing an Instrument at a Probe <em>deoptimizes</em> any compilations of the
- * AST.</li>
- *
- * </ul>
  *
  * @see Probe
  * @see TruffleEvents
  */
 public abstract class Instrument {
 
-    /**
-     * Creates a <em>Simple Instrument</em>: this Instrument routes execution events to a
-     * client-provided listener.
-     *
-     * @param listener a listener for execution events
-     * @param instrumentInfo optional description of the instrument's role, intended for debugging.
-     * @return a new instrument, ready for attachment at a probe
-     */
+    @Deprecated
     public static Instrument create(SimpleInstrumentListener listener, String instrumentInfo) {
         return new SimpleInstrument(listener, instrumentInfo);
     }
@@ -126,6 +63,7 @@
      * @param instrumentInfo optional description of the instrument's role, intended for debugging.
      * @return a new instrument, ready for attachment at a probe
      */
+    @Deprecated
     public static Instrument create(StandardInstrumentListener standardListener, String instrumentInfo) {
         return new StandardInstrument(standardListener, instrumentInfo);
     }
@@ -145,18 +83,11 @@
      * @param instrumentInfo optional description of the instrument's role, intended for debugging.
      * @return a new instrument, ready for attachment at a probe
      */
+    @Deprecated
     public static Instrument create(AdvancedInstrumentResultListener resultListener, AdvancedInstrumentRootFactory rootFactory, Class<?> requiredResultType, String instrumentInfo) {
         return new AdvancedInstrument(resultListener, rootFactory, requiredResultType, instrumentInfo);
     }
 
-    // TODO (mlvdv) experimental
-    /**
-     * For implementation testing.
-     */
-    public static Instrument create(TruffleOptListener listener) {
-        return new TruffleOptInstrument(listener, null);
-    }
-
     /**
      * Has this instrument been disposed? stays true once set.
      */
@@ -169,6 +100,61 @@
      */
     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;
     }
@@ -223,14 +209,14 @@
     /**
      * An instrument that propagates events to an instance of {@link SimpleInstrumentListener}.
      */
-    private static final class SimpleInstrument extends Instrument {
+    static final class SimpleInstrument extends Instrument {
 
         /**
          * Tool-supplied listener for events.
          */
         private final SimpleInstrumentListener simpleListener;
 
-        private SimpleInstrument(SimpleInstrumentListener simpleListener, String instrumentInfo) {
+        SimpleInstrument(SimpleInstrumentListener simpleListener, String instrumentInfo) {
             super(instrumentInfo);
             this.simpleListener = simpleListener;
         }
@@ -305,14 +291,14 @@
     /**
      * An instrument that propagates events to an instance of {@link StandardInstrumentListener}.
      */
-    private static final class StandardInstrument extends Instrument {
+    static final class StandardInstrument extends Instrument {
 
         /**
          * Tool-supplied listener for AST events.
          */
         private final StandardInstrumentListener standardListener;
 
-        private StandardInstrument(StandardInstrumentListener standardListener, String instrumentInfo) {
+        StandardInstrument(StandardInstrumentListener standardListener, String instrumentInfo) {
             super(instrumentInfo);
             this.standardListener = standardListener;
         }
@@ -389,13 +375,13 @@
      * within a Probe's <em>instrumentation chain</em>, and thus directly in the executing Truffle
      * AST with potential for full optimization.
      */
-    private static final class AdvancedInstrument extends Instrument {
+    static final class AdvancedInstrument extends Instrument {
 
         private final AdvancedInstrumentResultListener resultListener;
         private final AdvancedInstrumentRootFactory rootFactory;
         private final Class<?> requiredResultType;
 
-        private AdvancedInstrument(AdvancedInstrumentResultListener resultListener, AdvancedInstrumentRootFactory rootFactory, Class<?> requiredResultType, String instrumentInfo) {
+        AdvancedInstrument(AdvancedInstrumentResultListener resultListener, AdvancedInstrumentRootFactory rootFactory, Class<?> requiredResultType, String instrumentInfo) {
             super(instrumentInfo);
             this.resultListener = resultListener;
             this.rootFactory = rootFactory;
@@ -516,10 +502,12 @@
         }
     }
 
+    // TODO (mlvdv) experimental
     public interface TruffleOptListener {
         void notifyIsCompiled(boolean isCompiled);
     }
 
+    @SuppressWarnings("unused")
     private static final class TruffleOptInstrument extends Instrument {
 
         private final TruffleOptListener toolOptListener;
--- a/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/Instrumenter.java	Sat Sep 19 13:56:42 2015 -0700
+++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/Instrumenter.java	Sat Sep 19 16:29:32 2015 -0700
@@ -36,6 +36,7 @@
 import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
 import com.oracle.truffle.api.TruffleLanguage;
 import com.oracle.truffle.api.impl.Accessor;
+import com.oracle.truffle.api.instrument.InstrumentationNode.TruffleEvents;
 import com.oracle.truffle.api.instrument.ProbeNode.WrapperNode;
 import com.oracle.truffle.api.nodes.Node;
 import com.oracle.truffle.api.nodes.NodeVisitor;
@@ -309,6 +310,72 @@
         astProbers.remove(prober);
     }
 
+    /**
+     * <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 notification of
+     * {@linkplain TruffleEvents execution events} taking place at the Probe's AST location to the
+     * listener.
+     *
+     * @param probe source of execution events
+     * @param listener receiver of execution events
+     * @param instrumentInfo optional documentation about the Instrument
+     * @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);
+        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 notification of
+     * {@linkplain TruffleEvents execution events} taking place at the Probe's AST location to the
+     * listener.
+     *
+     * @param probe source of execution events
+     * @param listener receiver of execution events
+     * @param instrumentInfo optional documentation about the Instrument
+     * @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);
+        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 notification of
+     * {@linkplain TruffleEvents execution events} taking place at the Probe's AST location to the
+     * listener.
+     * <p>
+     * This Instrument executes efficiently, subject to full Truffle optimization, a client-provided
+     * AST fragment every time the Probed node is entered.
+     * <p>
+     * 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 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
+     *            the listener, if any, as a failure
+     * @param instrumentInfo instrumentInfo optional documentation about the Instrument
+     * @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);
+        probe.attach(instrument);
+        return instrument;
+    }
+
     @SuppressWarnings("unused")
     void executionStarted(Source s) {
     }
--- a/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/Probe.java	Sat Sep 19 13:56:42 2015 -0700
+++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/Probe.java	Sat Sep 19 16:29:32 2015 -0700
@@ -208,7 +208,7 @@
      * @param instrument an instrument not yet attached to a probe
      * @throws IllegalStateException if the instrument has ever been attached before
      */
-    public void attach(Instrument instrument) throws IllegalStateException {
+    void attach(Instrument instrument) throws IllegalStateException {
         if (instrument.isDisposed()) {
             throw new IllegalStateException("Attempt to attach disposed instrument");
         }
--- a/truffle/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/instrument/SLInstrumentTestRunner.java	Sat Sep 19 13:56:42 2015 -0700
+++ b/truffle/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/instrument/SLInstrumentTestRunner.java	Sat Sep 19 16:29:32 2015 -0700
@@ -70,7 +70,6 @@
 import org.junit.runners.model.InitializationError;
 
 import com.oracle.truffle.api.instrument.ASTProber;
-import com.oracle.truffle.api.instrument.Instrument;
 import com.oracle.truffle.api.instrument.Instrumenter;
 import com.oracle.truffle.api.instrument.Probe;
 import com.oracle.truffle.api.instrument.StandardSyntaxTag;
@@ -255,7 +254,7 @@
                 // Attach an instrument to every probe tagged as an assignment
                 for (Probe probe : instrumenter.findProbesTaggedAs(StandardSyntaxTag.ASSIGNMENT)) {
                     SLPrintAssigmentValueListener slPrintAssigmentValueListener = new SLPrintAssigmentValueListener(printer);
-                    probe.attach(Instrument.create(slPrintAssigmentValueListener, "SL print assignment value"));
+                    instrumenter.attach(probe, slPrintAssigmentValueListener, "SL print assignment value");
                 }
 
                 TruffleVM.Symbol main = vm.findGlobalSymbol("main");
--- a/truffle/com.oracle.truffle.tools/src/com/oracle/truffle/tools/CoverageTracker.java	Sat Sep 19 13:56:42 2015 -0700
+++ b/truffle/com.oracle.truffle.tools/src/com/oracle/truffle/tools/CoverageTracker.java	Sat Sep 19 16:29:32 2015 -0700
@@ -304,12 +304,10 @@
             }
         }
 
-        final CoverageRecord coverage = new CoverageRecord(srcSection);
-        final Instrument instrument = Instrument.create(coverage, CoverageTracker.class.getSimpleName());
-        coverage.instrument = instrument;
+        final CoverageRecord coverageRecord = new CoverageRecord(srcSection);
+        final Instrument instrument = getInstrumenter().attach(probe, coverageRecord, CoverageTracker.class.getSimpleName());
+        coverageRecord.instrument = instrument;
         instruments.add(instrument);
-        probe.attach(instrument);
-        coverageMap.put(lineLocation, coverage);
+        coverageMap.put(lineLocation, coverageRecord);
     }
-
 }
--- a/truffle/com.oracle.truffle.tools/src/com/oracle/truffle/tools/NodeExecCounter.java	Sat Sep 19 13:56:42 2015 -0700
+++ b/truffle/com.oracle.truffle.tools/src/com/oracle/truffle/tools/NodeExecCounter.java	Sat Sep 19 16:29:32 2015 -0700
@@ -120,7 +120,7 @@
                 /*
                  * Everything up to here is inlined by Truffle compilation. Delegate the next part
                  * to a method behind an inlining boundary.
-                 * 
+                 *
                  * Note that it is not permitted to pass a {@link VirtualFrame} across an inlining
                  * boundary; they are truly virtual in inlined code.
                  */
@@ -301,9 +301,10 @@
 
                     if (instrumenter.isInstrumentable(node)) {
                         try {
-                            final Instrument instrument = Instrument.create(instrumentListener, "NodeExecCounter");
+
+                            final Probe probe = instrumenter.probe(node);
+                            final Instrument instrument = instrumenter.attach(probe, instrumentListener, "NodeExecCounter");
                             instruments.add(instrument);
-                            instrumenter.probe(node).attach(instrument);
                         } catch (ProbeException ex) {
                             failures.add(ex.getFailure());
                         }
@@ -324,9 +325,8 @@
         @Override
         public void probeTaggedAs(Probe probe, SyntaxTag tag, Object tagValue) {
             if (countingTag == tag) {
-                final Instrument instrument = Instrument.create(instrumentListener, NodeExecCounter.class.getSimpleName());
+                final Instrument instrument = getInstrumenter().attach(probe, instrumentListener, NodeExecCounter.class.getSimpleName());
                 instruments.add(instrument);
-                probe.attach(instrument);
             }
         }
     }