changeset 20911:518ce9a36939

Merge with f0d8a33aebd1e67d464ea8479d4777d73c146648
author Michael Van De Vanter <michael.van.de.vanter@oracle.com>
date Mon, 13 Apr 2015 16:26:28 -0700
parents 0b2e4d40b683 (diff) f0d8a33aebd1 (current diff)
children b14a235f06eb 21298b90a6bf
files graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/InvocationPluginIdHolder.java
diffstat 15 files changed, 425 insertions(+), 402 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/InstrumentationPartialEvaluationTest.java	Mon Apr 13 15:55:23 2015 -0700
+++ b/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/InstrumentationPartialEvaluationTest.java	Mon Apr 13 16:26:28 2015 -0700
@@ -205,43 +205,45 @@
     }
 
     @Test
-    public void constantValueInertToolNodeInstrumentListener() {
+    public void constantValueInertSpliceInstrumentListener() {
         FrameDescriptor fd = new FrameDescriptor();
         AbstractTestNode result = new ConstantTestNode(42);
         RootTestNode root = new RootTestNode(fd, "constantValue", result);
         root.adoptChildren();
         Probe probe = result.probe();
-        // A listener that could insert a "tool node" into the AST, but which never does.
-        Instrument instrument = Instrument.create(new ToolNodeInstrumentListener() {
+        // A listener that could insert a SplicedNode into the AST, but which never does.
+        Instrument instrument = Instrument.create(new SpliceInstrumentListener() {
 
-            public ToolNode getToolNode(Probe p) {
+            public SplicedNode getSpliceNode(Probe p) {
                 return null;
             }
 
         }, null);
         probe.attach(instrument);
 
+        // It all gets compiled away
         assertPartialEvalEquals("constant42", root);
     }
 
     @Test
-    public void constantValueInertToolNode() {
+    public void constantValueInertSplicedNode() {
         FrameDescriptor fd = new FrameDescriptor();
         AbstractTestNode result = new ConstantTestNode(42);
         RootTestNode root = new RootTestNode(fd, "constantValue", result);
         root.adoptChildren();
         Probe probe = result.probe();
-        // A listener that inserts a "tool node" with empty methods into the AST.
-        Instrument instrument = Instrument.create(new ToolNodeInstrumentListener() {
+        // A listener that inserts a SplicedNode with empty methods into the AST.
+        Instrument instrument = Instrument.create(new SpliceInstrumentListener() {
 
-            public ToolNode getToolNode(Probe p) {
-                return new ToolNode() {
+            public SplicedNode getSpliceNode(Probe p) {
+                return new SplicedNode() {
                 };
             }
 
         }, null);
         probe.attach(instrument);
 
+        // It all gets compiled away.
         assertPartialEvalEquals("constant42", root);
     }
 
--- a/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/instrument/InstrumentationTestNodes.java	Mon Apr 13 15:55:23 2015 -0700
+++ b/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/instrument/InstrumentationTestNodes.java	Mon Apr 13 16:26:28 2015 -0700
@@ -86,7 +86,6 @@
         public Object execute(VirtualFrame vFrame) {
             probeNode.enter(child, vFrame);
             Object result;
-
             try {
                 result = child.execute(vFrame);
                 probeNode.returnValue(child, vFrame, result);
@@ -96,7 +95,6 @@
                 probeNode.returnExceptional(child, vFrame, e);
                 throw (e);
             }
-
             return result;
         }
     }
@@ -169,4 +167,17 @@
         }
     }
 
+    static class TestSplicedCounterNode extends SplicedNode {
+
+        private long count;
+
+        @Override
+        public void enter(Node node, VirtualFrame vFrame) {
+            count++;
+        }
+
+        public long getCount() {
+            return count;
+        }
+    }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/instrument/SpliceInstrumentTest.java	Mon Apr 13 16:26:28 2015 -0700
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 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.
+ *
+ * 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.test.instrument;
+
+import static org.junit.Assert.*;
+
+import org.junit.*;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.instrument.*;
+import com.oracle.truffle.api.test.instrument.InstrumentationTestNodes.TestAdditionNode;
+import com.oracle.truffle.api.test.instrument.InstrumentationTestNodes.TestRootNode;
+import com.oracle.truffle.api.test.instrument.InstrumentationTestNodes.TestValueNode;
+import com.oracle.truffle.api.test.instrument.InstrumentationTestNodes.TestSplicedCounterNode;
+
+/**
+ * Tests the kind of instrumentation where a client can provide an AST fragment to be
+ * <em>spliced</em> directly into the AST.
+ */
+public class SpliceInstrumentTest {
+
+    @Test
+    public void testSpliceInstrumentListener() {
+        // Create a simple addition AST
+        final TruffleRuntime runtime = Truffle.getRuntime();
+        final TestValueNode leftValueNode = new TestValueNode(6);
+        final TestValueNode rightValueNode = new TestValueNode(7);
+        final TestAdditionNode addNode = new TestAdditionNode(leftValueNode, rightValueNode);
+        final TestRootNode rootNode = new TestRootNode(addNode);
+        final CallTarget callTarget1 = runtime.createCallTarget(rootNode);
+
+        // Ensure it executes correctly
+        assertEquals(13, callTarget1.call());
+
+        // Probe the addition node
+        final Probe probe = addNode.probe();
+
+        assertEquals(13, callTarget1.call());
+
+        // Attach a null listener; it never actually attaches a node.
+        final Instrument instrument = Instrument.create(new SpliceInstrumentListener() {
+
+            public SplicedNode getSpliceNode(Probe p) {
+                return null;
+            }
+
+        }, null);
+        probe.attach(instrument);
+
+        assertEquals(13, callTarget1.call());
+
+        final TestSplicedCounterNode counter = new TestSplicedCounterNode();
+
+        // Attach a listener that splices an execution counter into the AST.
+        probe.attach(Instrument.create(new SpliceInstrumentListener() {
+
+            public SplicedNode getSpliceNode(Probe p) {
+                return counter;
+            }
+
+        }, null));
+        assertEquals(0, counter.getCount());
+
+        assertEquals(13, callTarget1.call());
+
+        assertEquals(1, counter.getCount());
+
+    }
+
+}
--- a/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/instrument/ToolNodeInstrumentationTest.java	Mon Apr 13 15:55:23 2015 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,96 +0,0 @@
-/*
- * Copyright (c) 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.
- *
- * 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.test.instrument;
-
-import static org.junit.Assert.*;
-
-import org.junit.*;
-
-import com.oracle.truffle.api.*;
-import com.oracle.truffle.api.frame.*;
-import com.oracle.truffle.api.instrument.*;
-import com.oracle.truffle.api.nodes.*;
-import com.oracle.truffle.api.test.instrument.InstrumentationTestNodes.TestAdditionNode;
-import com.oracle.truffle.api.test.instrument.InstrumentationTestNodes.TestRootNode;
-import com.oracle.truffle.api.test.instrument.InstrumentationTestNodes.TestValueNode;
-
-/**
- * Tests instrumentation where a client can attach a node that gets attached into the AST.
- */
-public class ToolNodeInstrumentationTest {
-
-    @Test
-    public void testToolNodeListener() {
-        // Create a simple addition AST
-        final TruffleRuntime runtime = Truffle.getRuntime();
-        final TestValueNode leftValueNode = new TestValueNode(6);
-        final TestValueNode rightValueNode = new TestValueNode(7);
-        final TestAdditionNode addNode = new TestAdditionNode(leftValueNode, rightValueNode);
-        final TestRootNode rootNode = new TestRootNode(addNode);
-        final CallTarget callTarget1 = runtime.createCallTarget(rootNode);
-
-        // Ensure it executes correctly
-        assertEquals(13, callTarget1.call());
-
-        // Probe the addition node
-        final Probe probe = addNode.probe();
-
-        assertEquals(13, callTarget1.call());
-
-        // Attach a listener that never actually attaches a node.
-        final Instrument instrument = Instrument.create(new ToolNodeInstrumentListener() {
-
-            public ToolNode getToolNode(Probe p) {
-                return null;
-            }
-
-        }, null);
-        probe.attach(instrument);
-
-        assertEquals(13, callTarget1.call());
-
-        final int[] count = new int[1];
-
-        // Attach a listener that never actually attaches a node.
-        probe.attach(Instrument.create(new ToolNodeInstrumentListener() {
-
-            public ToolNode getToolNode(Probe p) {
-                return new ToolNode() {
-
-                    @Override
-                    public void enter(Node node, VirtualFrame vFrame) {
-                        count[0] = count[0] + 1;
-                    }
-                };
-            }
-
-        }, null));
-        assertEquals(0, count[0]);
-
-        assertEquals(13, callTarget1.call());
-
-        assertEquals(1, count[0]);
-
-    }
-
-}
--- a/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/source/SourceTest.java	Mon Apr 13 15:55:23 2015 -0700
+++ b/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/source/SourceTest.java	Mon Apr 13 16:26:28 2015 -0700
@@ -54,9 +54,9 @@
         // Initially has only the default tag
         assertEquals(source.getSourceTags().size(), 1);
 
-        assertTrue(source.getSourceTags().contains(StandardSourceTag.FROM_LITERAL));
-        assertTrue(source.isTaggedAs(StandardSourceTag.FROM_LITERAL));
-        assertTrue(Source.findSourcesTaggedAs(StandardSourceTag.FROM_LITERAL).contains(source));
+        assertTrue(source.getSourceTags().contains(Source.Tags.FROM_LITERAL));
+        assertTrue(source.isTaggedAs(Source.Tags.FROM_LITERAL));
+        assertTrue(Source.findSourcesTaggedAs(Source.Tags.FROM_LITERAL).contains(source));
 
         assertFalse(source.isTaggedAs(testTag));
         assertEquals(Source.findSourcesTaggedAs(testTag).size(), 0);
@@ -67,9 +67,9 @@
         // Now there are exactly two tags
         assertEquals(source.getSourceTags().size(), 2);
 
-        assertTrue(source.getSourceTags().contains(StandardSourceTag.FROM_LITERAL));
-        assertTrue(source.isTaggedAs(StandardSourceTag.FROM_LITERAL));
-        assertTrue(Source.findSourcesTaggedAs(StandardSourceTag.FROM_LITERAL).contains(source));
+        assertTrue(source.getSourceTags().contains(Source.Tags.FROM_LITERAL));
+        assertTrue(source.isTaggedAs(Source.Tags.FROM_LITERAL));
+        assertTrue(Source.findSourcesTaggedAs(Source.Tags.FROM_LITERAL).contains(source));
 
         assertTrue(source.getSourceTags().contains(testTag));
         assertTrue(source.isTaggedAs(testTag));
@@ -82,9 +82,9 @@
         // Nothing has changed
         assertEquals(source.getSourceTags().size(), 2);
 
-        assertTrue(source.getSourceTags().contains(StandardSourceTag.FROM_LITERAL));
-        assertTrue(source.isTaggedAs(StandardSourceTag.FROM_LITERAL));
-        assertTrue(Source.findSourcesTaggedAs(StandardSourceTag.FROM_LITERAL).contains(source));
+        assertTrue(source.getSourceTags().contains(Source.Tags.FROM_LITERAL));
+        assertTrue(source.isTaggedAs(Source.Tags.FROM_LITERAL));
+        assertTrue(Source.findSourcesTaggedAs(Source.Tags.FROM_LITERAL).contains(source));
 
         assertTrue(source.getSourceTags().contains(testTag));
         assertTrue(source.isTaggedAs(testTag));
@@ -135,7 +135,7 @@
         assertEquals(newSource[0], source);
         assertEquals(newTagEvents[0], 1);
         assertEquals(taggedSource[0], source);
-        assertEquals(newTag[0], StandardSourceTag.FROM_LITERAL);
+        assertEquals(newTag[0], Source.Tags.FROM_LITERAL);
 
         // reset
         newSource[0] = null;
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/Instrument.java	Mon Apr 13 15:55:23 2015 -0700
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/Instrument.java	Mon Apr 13 16:26:28 2015 -0700
@@ -30,8 +30,9 @@
 import com.oracle.truffle.api.nodes.*;
 import com.oracle.truffle.api.source.*;
 
-// TODO (mlvdv) move all this to a factory implemented in .impl (together with Probe),
-// then break out some of the nested classes into package privates.
+// TODO (mlvdv) these statics should not be global.  Move them to some kind of context.
+// TODO (mlvdv) migrate factory into .impl (together with Probe)? break out nested classes?
+
 /**
  * A <em>binding</em> between:
  * <ol>
@@ -41,8 +42,8 @@
  * </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">Listening for
- * Execution Events</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
@@ -62,29 +63,38 @@
  * <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 of {@link SimpleInstrument} is attached to a
  * Probe, the Instrument inserts a new instance of its private Node type,
  * {@link SimpleInstrument.SimpleInstrumentNode}, 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
@@ -118,15 +128,16 @@
 
     /**
      * Creates an instrument that, when executed the first time in any particular AST location,
-     * invites the tool to provide an AST fragment for attachment/adoption into the running AST.
+     * invites the tool to provide an AST fragment for <em>splicing</em> directly into the running
+     * AST.
      *
-     * @param toolNodeListener a listener for the tool that can request an AST fragment
+     * @param spliceListener a callback to the client that requests an AST node to be splice.
      * @param instrumentInfo instrumentInfo optional description of the instrument's role, useful
      *            for debugging.
      * @return a new instrument, ready for attachment at a probe.
      */
-    public static Instrument create(ToolNodeInstrumentListener toolNodeListener, String instrumentInfo) {
-        return new ToolNodeInstrument(toolNodeListener, instrumentInfo);
+    public static Instrument create(SpliceInstrumentListener spliceListener, String instrumentInfo) {
+        return new SpliceInstrument(spliceListener, instrumentInfo);
     }
 
     // TODO (mlvdv) experimental
@@ -187,6 +198,11 @@
     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}.
      */
     private static final class SimpleInstrument extends Instrument {
@@ -266,11 +282,6 @@
     }
 
     /**
-     * Removes this instrument from an instrument chain.
-     */
-    abstract AbstractInstrumentNode removeFromChain(AbstractInstrumentNode instrumentNode);
-
-    /**
      * An instrument that propagates events to an instance of {@link StandardInstrumentListener}.
      */
     private static final class StandardInstrument extends Instrument {
@@ -351,23 +362,24 @@
 
     // TODO (mlvdv) EXPERIMENTAL- UNDER DEVELOPMENT
     /**
-     * An instrument that propagates events to an instance of {@link StandardInstrumentListener}.
+     * An instrument that allows clients to "splice" an AST fragment directly into a Probe's
+     * <em>instrumentation chain</em>, and thus directly into the executing Truffle AST.
      */
-    private static final class ToolNodeInstrument extends Instrument {
+    private static final class SpliceInstrument extends Instrument {
 
         /**
          * Tool-supplied listener for AST events.
          */
-        private final ToolNodeInstrumentListener toolNodeListener;
+        private final SpliceInstrumentListener spliceListener;
 
-        private ToolNodeInstrument(ToolNodeInstrumentListener toolNodeListener, String instrumentInfo) {
+        private SpliceInstrument(SpliceInstrumentListener spliceListener, String instrumentInfo) {
             super(instrumentInfo);
-            this.toolNodeListener = toolNodeListener;
+            this.spliceListener = spliceListener;
         }
 
         @Override
         AbstractInstrumentNode addToChain(AbstractInstrumentNode nextNode) {
-            return new ToolInstrumentNode(nextNode);
+            return new SpliceInstrumentNode(nextNode);
         }
 
         @Override
@@ -379,7 +391,7 @@
                     return instrumentNode.nextInstrumentNode;
                 }
                 // Match not at the head of the chain; remove it.
-                found = instrumentNode.removeFromChain(ToolNodeInstrument.this);
+                found = instrumentNode.removeFromChain(SpliceInstrument.this);
             }
             if (!found) {
                 throw new IllegalStateException("Couldn't find instrument node to remove: " + this);
@@ -388,25 +400,25 @@
         }
 
         @NodeInfo(cost = NodeCost.NONE)
-        private final class ToolInstrumentNode extends AbstractInstrumentNode {
+        private final class SpliceInstrumentNode extends AbstractInstrumentNode {
 
-            @Child ToolNode toolNode;
+            @Child SplicedNode splicedNode;
 
-            private ToolInstrumentNode(AbstractInstrumentNode nextNode) {
+            private SpliceInstrumentNode(AbstractInstrumentNode nextNode) {
                 super(nextNode);
             }
 
             public void enter(Node node, VirtualFrame vFrame) {
-                if (toolNode == null) {
-                    final ToolNode newToolNode = ToolNodeInstrument.this.toolNodeListener.getToolNode(ToolNodeInstrument.this.probe);
-                    if (newToolNode != null) {
-                        toolNode = newToolNode;
+                if (splicedNode == null) {
+                    final SplicedNode newSplicedNode = SpliceInstrument.this.spliceListener.getSpliceNode(SpliceInstrument.this.probe);
+                    if (newSplicedNode != null) {
+                        splicedNode = newSplicedNode;
                         adoptChildren();
-                        ToolNodeInstrument.this.probe.invalidateProbeUnchanged();
+                        SpliceInstrument.this.probe.invalidateProbeUnchanged();
                     }
                 }
-                if (toolNode != null) {
-                    toolNode.enter(node, vFrame);
+                if (splicedNode != null) {
+                    splicedNode.enter(node, vFrame);
                 }
                 if (nextInstrumentNode != null) {
                     nextInstrumentNode.enter(node, vFrame);
@@ -414,8 +426,8 @@
             }
 
             public void returnVoid(Node node, VirtualFrame vFrame) {
-                if (toolNode != null) {
-                    toolNode.returnVoid(node, vFrame);
+                if (splicedNode != null) {
+                    splicedNode.returnVoid(node, vFrame);
                 }
                 if (nextInstrumentNode != null) {
                     nextInstrumentNode.returnVoid(node, vFrame);
@@ -423,8 +435,8 @@
             }
 
             public void returnValue(Node node, VirtualFrame vFrame, Object result) {
-                if (toolNode != null) {
-                    toolNode.returnValue(node, vFrame, result);
+                if (splicedNode != null) {
+                    splicedNode.returnValue(node, vFrame, result);
                 }
                 if (nextInstrumentNode != null) {
                     nextInstrumentNode.returnValue(node, vFrame, result);
@@ -432,8 +444,8 @@
             }
 
             public void returnExceptional(Node node, VirtualFrame vFrame, Exception exception) {
-                if (toolNode != null) {
-                    toolNode.returnExceptional(node, vFrame, exception);
+                if (splicedNode != null) {
+                    splicedNode.returnExceptional(node, vFrame, exception);
                 }
                 if (nextInstrumentNode != null) {
                     nextInstrumentNode.returnExceptional(node, vFrame, exception);
@@ -442,7 +454,7 @@
 
             public String instrumentationInfo() {
                 final String info = getInstrumentInfo();
-                return info != null ? info : toolNodeListener.getClass().getSimpleName();
+                return info != null ? info : spliceListener.getClass().getSimpleName();
             }
         }
     }
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/Probe.java	Mon Apr 13 15:55:23 2015 -0700
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/Probe.java	Mon Apr 13 16:26:28 2015 -0700
@@ -34,38 +34,62 @@
 import com.oracle.truffle.api.source.*;
 import com.oracle.truffle.api.utilities.*;
 
-//TODO (mlvdv) migrate some of this to external documentation.
+//TODO (mlvdv) these statics should not be global.  Move them to some kind of context.
+
 /**
- * A binding between a particular <em>location</em> in the Truffle AST representation of a running
- * Guest Language (GL) program (i.e. a {@link Node}) and a dynamically managed collection of
- * "attached" {@linkplain Instrument instrumentation} for use by external tools. The instrumentation
- * is intended to persist at the location, even if the specific node instance is
- * {@linkplain Node#replace(Node) replaced}.
+ * A <em>binding</em> between:
+ * <ol>
+ * <li>A program location in an executing Truffle AST (defined by a {@link SourceSection}), and</li>
+ * <li>A dynamically managed collection of "attached" {@linkplain Instrument Instruments} that
+ * receive event notifications on behalf of external clients.</li>
+ * </ol>
  * <p>
- * The effect of a binding is to intercept {@linkplain TruffleEvents execution events} arriving at
- * the node and notify each attached {@link Instrument} before execution is allowed to proceed to
- * the child.
+ * Client-oriented documentation for the use of Probes is available online at <a
+ * HREF="https://wiki.openjdk.java.net/display/Graal/Finding+Probes"
+ * >https://wiki.openjdk.java.net/display/Graal/Finding+Probes</a>
  * <p>
- * A Probe is "inserted" into a GL node via a call to {@link Node#probe()}. No more than one Probe
- * can be inserted at a node.
+ * <h4>Implementation notes:</h4>
  * <p>
- * The "probing" of a Truffle AST must be done after it is complete (i.e. with parent pointers
- * correctly assigned), but before any executions. This is done by creating an instance of
- * {@link ASTProber} and registering it via {@link #registerASTProber(ASTProber)}, after which it
- * will be automatically applied to newly created ASTs.
- * <p>
- * Each Probe may also have assigned to it any number of {@link SyntaxTag}s, for example identifying
- * a node as a {@linkplain StandardSyntaxTag#STATEMENT STATEMENT}. Tags can be queried by tools to
- * configure behavior relevant to each probed node.
- * <p>
- * Instrumentation is implemented by modifying ASTs, both by inserting nodes into each AST at probed
- * locations and by attaching additional nodes that implement dynamically attached instruments.
- * Attached instrumentation code become, in effect, part of the GL program, and is subject to the
- * same levels of optimization as other GL code. This implementation accounts properly for the fact
- * that Truffle frequently <em>clones</em> ASTs, along with any attached instrumentation nodes. A
- * {@link Probe}, along with attached {@link Instrument}s, represents a <em>logical</em> binding
- * with a source code location, producing event notifications that are (mostly) independent of which
- * AST clone is executing.
+ * <ul>
+ * <li>A Probe must be permanently associated with a <em>program location</em>, defined by a
+ * particular {@link SourceSection}, even though:
+ * <ul>
+ * <li>that location is represented in an AST as a {@link Node}, which might be replaced through
+ * optimizations such as specialization, and</li>
+ * <li>Truffle may <em>clone</em> the AST so that the location is actually represented by multiple
+ * Nodes in multiple ASTs.</li>
+ * </ul>
+ * </li>
+ *
+ * <li>The effect of the binding is to intercept {@linkplain TruffleEvents execution events}
+ * arriving at the "probed" AST node and notify each attached {@link Instrument} before execution is
+ * allowed to proceed to the child and again after execution completes.</li>
+ *
+ * <li>A Probe is "inserted" into a GL node via a call to {@link Node#probe()}. No more than one
+ * Probe can be inserted at a node; a redundant call returns the existing Probe<./li>
+ *
+ * <li>The "probing" of a Truffle AST must be done after the AST is complete (i.e. parent pointers
+ * correctly assigned), but before any cloning or executions. This is done by creating an instance
+ * of {@link ASTProber} and registering it via {@link #registerASTProber(ASTProber)}, after which it
+ * will be applied automatically to every newly created AST.</li>
+ *
+ * <li>An AST node becomes <em>probed</em> by insertion of a {@link ProbeNode.WrapperNode} into the
+ * AST, together with an associated {@link ProbeNode} that routes events to all the
+ * {@linkplain Instrument Instruments} attached to its <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. The {@link Probe} instance intercepts cloning
+ * events and keeps track of all copies.</li>
+ *
+ * <li>All attached {@link InstrumentationNode}s effectively become part of the running program:
+ * <ul>
+ * <li>Good News: instrumentation code implicitly benefits from every kind of Truffle optimization.</li>
+ * <li>Bad News: instrumentation code must be implemented carefully to avoid interfering with any
+ * Truffle optimizations.</li>
+ * </ul>
+ * </li>
+ *
+ * </ul>
  *
  * @see Instrument
  * @see ASTProber
@@ -173,6 +197,7 @@
         return taggedProbes;
     }
 
+    // TODO (mlvdv) can this be generalized to permit multiple traps without a performance hit?
     /**
      * Sets the current "tag trap"; there can be no more than one set at a time.
      * <ul>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/SpliceInstrumentListener.java	Mon Apr 13 16:26:28 2015 -0700
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 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;
+
+/**
+ * Instrument listener for a tool that works by providing an AST to be <em>spliced</em> directly
+ * into the AST.
+ */
+public interface SpliceInstrumentListener {
+
+    /**
+     * Receive notification that a probed AST node to which the {@link Instrument} is attached is
+     * about to be executed for the first time. This is a lazy opportunity for the tool to
+     * optionally add the root of a newly created AST fragment that will be <em>spliced</em>
+     * directly into the executing AST. The new AST fragment will immediately begin receiving
+     * {@link InstrumentationNode.TruffleEvents}, beginning with the current execution event.
+     * <p>
+     * AST fragments must be written to Truffle conventions. Some of these conventions are
+     * especially important if the fragment is to be fully optimized along with it's new parent AST.
+     * <p>
+     * If this method returns {@code null} then it will be called again the next time the probed
+     * node is about to be executed.
+     * <p>
+     * In some situations, this method will be called more than once for a particular Probe, and a
+     * new instance must be supplied each time. Each instance will be attached at the equivalent
+     * location in clones of the AST, and so should be behave as if equivalent for most purposes.
+     * <p>
+     * In some situations the AST fragment supplied by this method maybe cloned for attachment to
+     * equivalent locations in cloned AST, so care should be taken about any state local to each
+     * instance of the AST fragment.
+     *
+     * @see Instrument
+     */
+    SplicedNode getSpliceNode(Probe probe);
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/SplicedNode.java	Mon Apr 13 16:26:28 2015 -0700
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 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.frame.*;
+import com.oracle.truffle.api.nodes.*;
+
+/**
+ * Root of a client-provided AST fragment that can be spliced directly into an executing AST via
+ * {@link Instrument#create(SpliceInstrumentListener, String)}.
+ * <p>
+ * <strong>Note:</strong> Instances of this class will in some situations be cloned by the
+ * instrumentation platform for attachment at equivalent locations in cloned ASTs.
+ */
+public abstract class SplicedNode extends Node implements InstrumentationNode.TruffleEvents, InstrumentationNode {
+
+    public void enter(Node node, VirtualFrame vFrame) {
+    }
+
+    public void returnVoid(Node node, VirtualFrame vFrame) {
+    }
+
+    public void returnValue(Node node, VirtualFrame vFrame, Object result) {
+    }
+
+    public void returnExceptional(Node node, VirtualFrame vFrame, Exception exception) {
+    }
+
+    public String instrumentationInfo() {
+        return null;
+    }
+
+}
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/ToolNode.java	Mon Apr 13 15:55:23 2015 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,55 +0,0 @@
-/*
- * Copyright (c) 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.frame.*;
-import com.oracle.truffle.api.nodes.*;
-
-/**
- * Root of a tool-provided AST fragment that can be attached directly into an executing AST via
- * {@link Instrument#create(ToolNodeInstrumentListener, String)}.
- * <p>
- * <strong>Note:</strong> Instances of this class will in some situations be cloned by the
- * instrumentation platform for attachment at equivalent locations in cloned parent ASTs.
- */
-public abstract class ToolNode extends Node implements InstrumentationNode.TruffleEvents, InstrumentationNode {
-
-    public void enter(Node node, VirtualFrame vFrame) {
-    }
-
-    public void returnVoid(Node node, VirtualFrame vFrame) {
-    }
-
-    public void returnValue(Node node, VirtualFrame vFrame, Object result) {
-    }
-
-    public void returnExceptional(Node node, VirtualFrame vFrame, Exception exception) {
-    }
-
-    public String instrumentationInfo() {
-        return null;
-    }
-
-}
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/ToolNodeInstrumentListener.java	Mon Apr 13 15:55:23 2015 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,58 +0,0 @@
-/*
- * Copyright (c) 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;
-
-/**
- * Instrument listener for a tool that works by providing an AST to be attached/adopted directly
- * into the AST.
- */
-public interface ToolNodeInstrumentListener {
-
-    /**
-     * Receive notification that a probed AST node to which the {@link Instrument} is attached is
-     * about to be executed for the first time. This is a lazy opportunity for the tool to
-     * optionally add the root of a newly created AST fragment that will be attached/adopted
-     * directly into the executing AST. The new AST fragment will immediately begin receiving
-     * {@link InstrumentationNode.TruffleEvents}, beginning with the current execution event.
-     * <p>
-     * AST fragments must be written to Truffle conventions. Some of these conventions are
-     * especially important if the fragment is to be fully optimized along with it's new parent AST.
-     * <p>
-     * If this method returns {@code null} then it will be called again the next time the probed
-     * node is about to be executed.
-     * <p>
-     * In some situations, this method will be called more than once for a particular Probe, and a
-     * new instance must be supplied each time. Each instance will be attached at the equivalent
-     * location in clones of the AST, and so should be behave as if equivalent for most purposes.
-     * <p>
-     * In some situations the AST fragment supplied by this method maybe cloned for attachment to
-     * equivalent locations in cloned AST, so care should be taken about any state local to each
-     * instance of the AST fragment.
-     *
-     * @see Instrument
-     */
-    ToolNode getToolNode(Probe probe);
-
-}
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/source/Source.java	Mon Apr 13 15:55:23 2015 -0700
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/source/Source.java	Mon Apr 13 16:26:28 2015 -0700
@@ -78,6 +78,51 @@
     // TODO (mlvdv) consider canonicalizing and reusing SourceSection instances
     // TOOD (mlvdv) connect SourceSections into a spatial tree for fast geometric lookup
 
+    public enum Tags implements SourceTag {
+
+        /**
+         * From bytes.
+         */
+        FROM_BYTES("bytes", "read from bytes"),
+
+        /**
+         * Read from a file.
+         */
+        FROM_FILE("file", "read from a file"),
+
+        /**
+         * From literal text.
+         */
+        FROM_LITERAL("literal", "from literal text"),
+
+        /**
+         * From a {@linkplain java.io.Reader Reader}.
+         */
+        FROM_READER("reader", "read from a Java Reader"),
+
+        /**
+         * Read from a URL.
+         */
+        FROM_URL("URL", "read from a URL");
+
+        private final String name;
+        private final String description;
+
+        private Tags(String name, String description) {
+            this.name = name;
+            this.description = description;
+        }
+
+        public String getName() {
+            return name;
+        }
+
+        public String getDescription() {
+            return description;
+        }
+
+    }
+
     /**
      * All Sources that have been created.
      */
@@ -119,7 +164,7 @@
         if (reset) {
             source.reset();
         }
-        notifyNewSource(source).tagAs(StandardSourceTag.FROM_FILE);
+        notifyNewSource(source).tagAs(Tags.FROM_FILE);
         return source;
     }
 
@@ -161,7 +206,7 @@
                 filePathToSource.put(path, new WeakReference<>(source));
             }
         }
-        notifyNewSource(source).tagAs(StandardSourceTag.FROM_FILE);
+        notifyNewSource(source).tagAs(Tags.FROM_FILE);
         return source;
     }
 
@@ -176,7 +221,7 @@
     public static Source fromText(CharSequence chars, String description) {
         assert chars != null;
         final LiteralSource source = new LiteralSource(description, chars.toString());
-        notifyNewSource(source).tagAs(StandardSourceTag.FROM_LITERAL);
+        notifyNewSource(source).tagAs(Tags.FROM_LITERAL);
         return source;
     }
 
@@ -190,7 +235,7 @@
      */
     public static Source fromURL(URL url, String description) throws IOException {
         final URLSource source = URLSource.get(url, description);
-        notifyNewSource(source).tagAs(StandardSourceTag.FROM_URL);
+        notifyNewSource(source).tagAs(Tags.FROM_URL);
         return source;
     }
 
@@ -204,7 +249,7 @@
      */
     public static Source fromReader(Reader reader, String description) throws IOException {
         final LiteralSource source = new LiteralSource(description, read(reader));
-        notifyNewSource(source).tagAs(StandardSourceTag.FROM_READER);
+        notifyNewSource(source).tagAs(Tags.FROM_READER);
         return source;
     }
 
@@ -237,7 +282,7 @@
      */
     public static Source fromBytes(byte[] bytes, int byteIndex, int length, String description, BytesDecoder decoder) {
         final BytesSource source = new BytesSource(description, bytes, byteIndex, length, decoder);
-        notifyNewSource(source).tagAs(StandardSourceTag.FROM_BYTES);
+        notifyNewSource(source).tagAs(Tags.FROM_BYTES);
         return source;
     }
 
@@ -252,7 +297,7 @@
     public static Source asPseudoFile(CharSequence chars, String pseudoFileName) {
         final Source source = new LiteralSource(pseudoFileName, chars.toString());
         filePathToSource.put(pseudoFileName, new WeakReference<>(source));
-        notifyNewSource(source).tagAs(StandardSourceTag.FROM_LITERAL);
+        notifyNewSource(source).tagAs(Tags.FROM_LITERAL);
         return source;
     }
 
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/source/SourceTag.java	Mon Apr 13 15:55:23 2015 -0700
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/source/SourceTag.java	Mon Apr 13 16:26:28 2015 -0700
@@ -27,16 +27,14 @@
 /**
  * Categorical information (best implemented as enums} about particular sources of Guest Language
  * code that can be useful to configure behavior of both the language runtime and external tools.
- * These might include {@linkplain StandardSourceTag standard tags} noting, for example, whether the
+ * These might include {@linkplain Source.Tags standard tags} noting, for example, whether the
  * source was read from a file and whether it should be considered library code.
  * <p>
- * An untagged {@link Source} should by default be considered application code.
- * <p>
  * The need for additional tags is likely to arise, in some cases because of issue specific to a
  * Guest Language, but also for help configuring the behavior of particular tools.
  *
  * @see Source
- * @see StandardSourceTag
+ * @see Source.Tags
  */
 public interface SourceTag {
 
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/source/StandardSourceTag.java	Mon Apr 13 15:55:23 2015 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,91 +0,0 @@
-/*
- * Copyright (c) 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.source;
-
-/**
- * A general set of "properties" or "categories" that might be usefully attached to a particular
- * source of code, both for use by the language runtime and by external tools. This set of tags
- * includes some intended to be applied by default by {@link Source} factory methods or other
- * services built into the Truffle platform.
- * <p>
- * The need for additional tags is likely to arise, in some cases because of issue specific to a
- * Guest Language, but also for help configuring the behavior of particular tools.
- *
- * @see Source
- */
-public enum StandardSourceTag implements SourceTag {
-
-    /**
-     * Builtin.
-     */
-    BUILTIN("builtin", "implementation of language builtins"),
-
-    /**
-     * From bytes.
-     */
-    FROM_BYTES("bytes", "read from bytes"),
-
-    /**
-     * Read from a file.
-     */
-    FROM_FILE("file", "read from a file"),
-
-    /**
-     * From literal text.
-     */
-    FROM_LITERAL("literal", "from literal text"),
-
-    /**
-     * From a {@linkplain java.io.Reader Reader}.
-     */
-    FROM_READER("reader", "read from a Java Reader"),
-
-    /**
-     * Read from a URL.
-     */
-    FROM_URL("URL", "read from a URL"),
-
-    /**
-     * Treat as LIBRARY code.
-     */
-    LIBRARY("library", "library code");
-
-    private final String name;
-    private final String description;
-
-    private StandardSourceTag(String name, String description) {
-        this.name = name;
-        this.description = description;
-    }
-
-    public String getName() {
-        return name;
-    }
-
-    public String getDescription() {
-        return description;
-    }
-
-}
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/tools/CoverageTracker.java	Mon Apr 13 15:55:23 2015 -0700
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/tools/CoverageTracker.java	Mon Apr 13 16:26:28 2015 -0700
@@ -35,10 +35,13 @@
 
 /**
  * An {@link InstrumentationTool} that counts interpreter <em>execution calls</em> to AST nodes that
- * hold a specified {@linkplain SyntaxTag tag}, tabulated by source and line number associated with
- * each node. Tags are presumed to be applied external to the tool. If no tag is specified,
- * {@linkplain StandardSyntaxTag#STATEMENT STATEMENT} is used, corresponding to conventional
- * behavior for code coverage tools.
+ * hold a specified {@linkplain SyntaxTag syntax tag}, tabulated by source and line number
+ * associated with each node. Syntax tags are presumed to be applied external to the tool. If no tag
+ * is specified, {@linkplain StandardSyntaxTag#STATEMENT STATEMENT} is used, corresponding to
+ * conventional behavior for code coverage tools.
+ * <p>
+ * No counts will be kept for execution in sources that hold the {@link SourceTag}
+ * {@link Tags#NO_COVERAGE}.
  * <p>
  * <b>Tool Life Cycle</b>
  * <p>
@@ -70,6 +73,30 @@
  */
 public final class CoverageTracker extends InstrumentationTool {
 
+    public enum Tags implements SourceTag {
+
+        /**
+         * Report no counts for sources holding this tag.
+         */
+        NO_COVERAGE("No Coverage", "Coverage Tracker will igore");
+
+        private final String name;
+        private final String description;
+
+        private Tags(String name, String description) {
+            this.name = name;
+            this.description = description;
+        }
+
+        public String getName() {
+            return name;
+        }
+
+        public String getDescription() {
+            return description;
+        }
+    }
+
     /** Counting data. */
     private final Map<LineLocation, CoverageRecord> coverageMap = new HashMap<>();
 
@@ -264,7 +291,7 @@
                 final SourceSection srcSection = probe.getProbedSourceSection();
                 if (srcSection == null) {
                     // TODO (mlvdv) report this?
-                } else {
+                } else if (!srcSection.getSource().isTaggedAs(Tags.NO_COVERAGE)) {
                     // Get the source line where the
                     final LineLocation lineLocation = srcSection.getLineLocation();
                     CoverageRecord record = coverageMap.get(lineLocation);