changeset 19818:907128d02b31

Truffle/Instrumentation: For clients of Instrumentation, replace the TruffleEventListener interface with two: InstrumentListener, and ASTInstrumentListener. The former is simple, completely Truffle-safe (can't affect Truffle execution), and designed for simple tools. The latter is similar to the previous interface.
author Michael Van De Vanter <michael.van.de.vanter@oracle.com>
date Thu, 12 Mar 2015 18:03:05 -0700
parents 8b7a143aea6b
children a5b09092003a
files graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/InstrumentationPartialEvaluationTest.java graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/instrument/InstrumentationTest.java graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/Instrument.java graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/InstrumentationNode.java graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/Probe.java graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/ProbeNode.java graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/Node.java graal/com.oracle.truffle.api/src/com/oracle/truffle/api/tools/CoverageTracker.java graal/com.oracle.truffle.api/src/com/oracle/truffle/api/tools/NodeExecCounter.java graal/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/instrument/SLInstrumentTestRunner.java
diffstat 10 files changed, 521 insertions(+), 351 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/InstrumentationPartialEvaluationTest.java	Thu Mar 12 15:02:01 2015 -0700
+++ b/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/InstrumentationPartialEvaluationTest.java	Thu Mar 12 18:03:05 2015 -0700
@@ -61,72 +61,144 @@
     }
 
     @Test
-    public void constantValueProbedNullInstrument() {
+    public void constantValueProbedNullInstrument1() {
+        FrameDescriptor fd = new FrameDescriptor();
+        AbstractTestNode result = new ConstantTestNode(42);
+        RootTestNode root = new RootTestNode(fd, "constantValue", result);
+        root.adoptChildren();
+        Probe probe = result.probe();
+        Instrument instrument = Instrument.create(new DefaultInstrumentListener(), "Null test Instrument");
+        probe.attach(instrument);
+        assertPartialEvalEquals("constant42", root);
+    }
+
+    @Test
+    public void constantValueProbedNullInstrument2() {
         FrameDescriptor fd = new FrameDescriptor();
         AbstractTestNode result = new ConstantTestNode(42);
         RootTestNode root = new RootTestNode(fd, "constantValue", result);
         root.adoptChildren();
         Probe probe = result.probe();
-        Instrument instrument = Instrument.create(new DefaultEventListener(), "Null test Instrument");
+        Instrument instrument = Instrument.create(new DefaultASTInstrumentListener(), "Null test Instrument");
         probe.attach(instrument);
         assertPartialEvalEquals("constant42", root);
     }
 
     @Test
-    public void constantValueProbedNullInstrumentDisposed() {
+    public void constantValueProbedNullInstrumentDisposed1() {
         FrameDescriptor fd = new FrameDescriptor();
         AbstractTestNode result = new ConstantTestNode(42);
         RootTestNode root = new RootTestNode(fd, "constantValue", result);
         root.adoptChildren();
         Probe probe = result.probe();
-        Instrument instrument = Instrument.create(new DefaultEventListener(), "Null test Instrument");
+        Instrument instrument = Instrument.create(new DefaultInstrumentListener(), "Null test Instrument");
+        probe.attach(instrument);
+        instrument.dispose();
+        assertPartialEvalEquals("constant42", root);
+    }
+
+    @Test
+    public void constantValueProbedNullInstrumentDisposed2() {
+        FrameDescriptor fd = new FrameDescriptor();
+        AbstractTestNode result = new ConstantTestNode(42);
+        RootTestNode root = new RootTestNode(fd, "constantValue", result);
+        root.adoptChildren();
+        Probe probe = result.probe();
+        Instrument instrument = Instrument.create(new DefaultASTInstrumentListener(), "Null test Instrument");
         probe.attach(instrument);
         instrument.dispose();
         assertPartialEvalEquals("constant42", root);
     }
 
     @Test
-    public void constantValueProbedTwoNullInstruments() {
+    public void constantValueProbedTwoNullInstruments1() {
         FrameDescriptor fd = new FrameDescriptor();
         AbstractTestNode result = new ConstantTestNode(42);
         RootTestNode root = new RootTestNode(fd, "constantValue", result);
         root.adoptChildren();
         Probe probe = result.probe();
-        Instrument instrument1 = Instrument.create(new DefaultEventListener(), "Null test Instrument 1");
+        Instrument instrument1 = Instrument.create(new DefaultInstrumentListener(), "Null test Instrument 1");
         probe.attach(instrument1);
-        Instrument instrument2 = Instrument.create(new DefaultEventListener(), "Null test Instrument 2");
+        Instrument instrument2 = Instrument.create(new DefaultInstrumentListener(), "Null test Instrument 2");
         probe.attach(instrument2);
         assertPartialEvalEquals("constant42", root);
     }
 
     @Test
-    public void constantValueProbedThreeNullInstruments() {
+    public void constantValueProbedTwoNullInstruments2() {
+        FrameDescriptor fd = new FrameDescriptor();
+        AbstractTestNode result = new ConstantTestNode(42);
+        RootTestNode root = new RootTestNode(fd, "constantValue", result);
+        root.adoptChildren();
+        Probe probe = result.probe();
+        Instrument instrument1 = Instrument.create(new DefaultASTInstrumentListener(), "Null test Instrument 1");
+        probe.attach(instrument1);
+        Instrument instrument2 = Instrument.create(new DefaultASTInstrumentListener(), "Null test Instrument 2");
+        probe.attach(instrument2);
+        assertPartialEvalEquals("constant42", root);
+    }
+
+    @Test
+    public void constantValueProbedThreeNullInstruments1() {
         FrameDescriptor fd = new FrameDescriptor();
         AbstractTestNode result = new ConstantTestNode(42);
         RootTestNode root = new RootTestNode(fd, "constantValue", result);
         root.adoptChildren();
         Probe probe = result.probe();
-        Instrument instrument1 = Instrument.create(new DefaultEventListener(), "Null test Instrument 1");
+        Instrument instrument1 = Instrument.create(new DefaultInstrumentListener(), "Null test Instrument 1");
         probe.attach(instrument1);
-        Instrument instrument2 = Instrument.create(new DefaultEventListener(), "Null test Instrument 2");
+        Instrument instrument2 = Instrument.create(new DefaultInstrumentListener(), "Null test Instrument 2");
         probe.attach(instrument2);
-        Instrument instrument3 = Instrument.create(new DefaultEventListener(), "Null test Instrument 3");
+        Instrument instrument3 = Instrument.create(new DefaultInstrumentListener(), "Null test Instrument 3");
+        probe.attach(instrument3);
+        assertPartialEvalEquals("constant42", root);
+    }
+
+    @Test
+    public void constantValueProbedThreeNullInstruments2() {
+        FrameDescriptor fd = new FrameDescriptor();
+        AbstractTestNode result = new ConstantTestNode(42);
+        RootTestNode root = new RootTestNode(fd, "constantValue", result);
+        root.adoptChildren();
+        Probe probe = result.probe();
+        Instrument instrument1 = Instrument.create(new DefaultASTInstrumentListener(), "Null test Instrument 1");
+        probe.attach(instrument1);
+        Instrument instrument2 = Instrument.create(new DefaultASTInstrumentListener(), "Null test Instrument 2");
+        probe.attach(instrument2);
+        Instrument instrument3 = Instrument.create(new DefaultASTInstrumentListener(), "Null test Instrument 3");
         probe.attach(instrument3);
         assertPartialEvalEquals("constant42", root);
     }
 
     @Test
-    public void constantValueProbedThreeNullInstrumentsOneDisposed() {
+    public void constantValueProbedThreeNullInstrumentsOneDisposed1() {
         FrameDescriptor fd = new FrameDescriptor();
         AbstractTestNode result = new ConstantTestNode(42);
         RootTestNode root = new RootTestNode(fd, "constantValue", result);
         root.adoptChildren();
         Probe probe = result.probe();
-        Instrument instrument1 = Instrument.create(new DefaultEventListener(), "Null test Instrument 1");
+        Instrument instrument1 = Instrument.create(new DefaultInstrumentListener(), "Null test Instrument 1");
         probe.attach(instrument1);
-        Instrument instrument2 = Instrument.create(new DefaultEventListener(), "Null test Instrument 2");
+        Instrument instrument2 = Instrument.create(new DefaultInstrumentListener(), "Null test Instrument 2");
         probe.attach(instrument2);
-        Instrument instrument3 = Instrument.create(new DefaultEventListener(), "Null test Instrument 3");
+        Instrument instrument3 = Instrument.create(new DefaultInstrumentListener(), "Null test Instrument 3");
+        probe.attach(instrument3);
+        instrument2.dispose();
+        assertPartialEvalEquals("constant42", root);
+    }
+
+    @Test
+    public void constantValueProbedThreeNullInstrumentsOneDisposed2() {
+        FrameDescriptor fd = new FrameDescriptor();
+        AbstractTestNode result = new ConstantTestNode(42);
+        RootTestNode root = new RootTestNode(fd, "constantValue", result);
+        root.adoptChildren();
+        Probe probe = result.probe();
+        Instrument instrument1 = Instrument.create(new DefaultASTInstrumentListener(), "Null test Instrument 1");
+        probe.attach(instrument1);
+        Instrument instrument2 = Instrument.create(new DefaultASTInstrumentListener(), "Null test Instrument 2");
+        probe.attach(instrument2);
+        Instrument instrument3 = Instrument.create(new DefaultASTInstrumentListener(), "Null test Instrument 3");
         probe.attach(instrument3);
         instrument2.dispose();
         assertPartialEvalEquals("constant42", root);
@@ -167,13 +239,13 @@
             Assert.assertEquals(0, count[0]);           // Didn't count anything
 
             // Add a counting instrument; this changes the "Probe state" and should cause a deopt
-            final Instrument countingInstrument = Instrument.create(new DefaultEventListener() {
+            final Instrument countingInstrument = Instrument.create(new DefaultInstrumentListener() {
 
                 @Override
-                public void enter(Node node, VirtualFrame frame) {
+                public void enter(Probe p) {
                     count[0] = count[0] + 1;
                 }
-            });
+            }, null);
             probe[0].attach(countingInstrument);
 
             Assert.assertEquals(42, callTarget.call()); // Correct result
--- a/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/instrument/InstrumentationTest.java	Thu Mar 12 15:02:01 2015 -0700
+++ b/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/instrument/InstrumentationTest.java	Thu Mar 12 18:03:05 2015 -0700
@@ -83,7 +83,7 @@
     };
 
     @Test
-    public void testBasicInstrumentation() {
+    public void testInstrumentationStructure() {
         // Create a simple addition AST
         final TruffleRuntime runtime = Truffle.getRuntime();
         final TestValueNode leftValueNode = new TestValueNode(6);
@@ -117,7 +117,7 @@
         assertEquals(13, callTarget1.call());
 
         // Probe the addition node
-        final Probe probe = addNode.probe();
+        addNode.probe();
 
         // Check the modified tree structure
         assertEquals(addNode, leftValueNode.getParent());
@@ -153,103 +153,129 @@
         // Check that the "probed" AST still executes correctly
         assertEquals(13, callTarget1.call());
 
+    }
+
+    @Test
+    public void testListeners() {
+
+        // 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);
+
+        // Creating a call target sets the parent pointers in this tree and is necessary prior to
+        // checking any parent/child relationships
+        final CallTarget callTarget = runtime.createCallTarget(rootNode);
+        // Probe the addition node
+        final Probe probe = addNode.probe();
+
+        // Check instrumentation with the simplest kind of counters.
+        // They should all be removed when the check is finished.
+        checkCounters(probe, callTarget, rootNode, new TestInstrumentCounter(), new TestInstrumentCounter(), new TestInstrumentCounter());
+
+        // Now try with the more complex flavor of listener
+        checkCounters(probe, callTarget, rootNode, new TestASTInstrumentCounter(), new TestASTInstrumentCounter(), new TestASTInstrumentCounter());
+
+    }
+
+    private static void checkCounters(Probe probe, CallTarget callTarget, RootNode rootNode, TestCounter counterA, TestCounter counterB, TestCounter counterC) {
+
         // Attach a counting instrument to the probe
-        final TestCounter counterA = new TestCounter();
         counterA.attach(probe);
 
         // Attach a second counting instrument to the probe
-        final TestCounter counterB = new TestCounter();
         counterB.attach(probe);
 
         // Run it again and check that the two instruments are working
-        assertEquals(13, callTarget1.call());
-        assertEquals(counterA.enterCount, 1);
-        assertEquals(counterA.leaveCount, 1);
-        assertEquals(counterB.enterCount, 1);
-        assertEquals(counterB.leaveCount, 1);
+        assertEquals(13, callTarget.call());
+        assertEquals(counterA.enterCount(), 1);
+        assertEquals(counterA.leaveCount(), 1);
+        assertEquals(counterB.enterCount(), 1);
+        assertEquals(counterB.leaveCount(), 1);
 
-        // Remove counterA and check the "instrument chain"
+        // Remove counterA
         counterA.dispose();
-        iterator = probeNode.getChildren().iterator();
 
         // Run it again and check that instrument B is still working but not A
-        assertEquals(13, callTarget1.call());
-        assertEquals(counterA.enterCount, 1);
-        assertEquals(counterA.leaveCount, 1);
-        assertEquals(counterB.enterCount, 2);
-        assertEquals(counterB.leaveCount, 2);
+        assertEquals(13, callTarget.call());
+        assertEquals(counterA.enterCount(), 1);
+        assertEquals(counterA.leaveCount(), 1);
+        assertEquals(counterB.enterCount(), 2);
+        assertEquals(counterB.leaveCount(), 2);
 
         // Simulate a split by cloning the AST
-        final CallTarget callTarget2 = runtime.createCallTarget((TestRootNode) rootNode.copy());
+        final CallTarget callTarget2 = Truffle.getRuntime().createCallTarget((TestRootNode) rootNode.copy());
         // Run the clone and check that instrument B is still working but not A
         assertEquals(13, callTarget2.call());
-        assertEquals(counterA.enterCount, 1);
-        assertEquals(counterA.leaveCount, 1);
-        assertEquals(counterB.enterCount, 3);
-        assertEquals(counterB.leaveCount, 3);
+        assertEquals(counterA.enterCount(), 1);
+        assertEquals(counterA.leaveCount(), 1);
+        assertEquals(counterB.enterCount(), 3);
+        assertEquals(counterB.leaveCount(), 3);
 
         // Run the original and check that instrument B is still working but not A
         assertEquals(13, callTarget2.call());
-        assertEquals(counterA.enterCount, 1);
-        assertEquals(counterA.leaveCount, 1);
-        assertEquals(counterB.enterCount, 4);
-        assertEquals(counterB.leaveCount, 4);
+        assertEquals(counterA.enterCount(), 1);
+        assertEquals(counterA.leaveCount(), 1);
+        assertEquals(counterB.enterCount(), 4);
+        assertEquals(counterB.leaveCount(), 4);
 
         // Attach a second instrument to the probe
-        final TestCounter counterC = new TestCounter();
         counterC.attach(probe);
 
         // Run the original and check that instruments B,C working but not A
-        assertEquals(13, callTarget1.call());
-        assertEquals(counterA.enterCount, 1);
-        assertEquals(counterA.leaveCount, 1);
-        assertEquals(counterB.enterCount, 5);
-        assertEquals(counterB.leaveCount, 5);
-        assertEquals(counterC.enterCount, 1);
-        assertEquals(counterC.leaveCount, 1);
+        assertEquals(13, callTarget.call());
+        assertEquals(counterA.enterCount(), 1);
+        assertEquals(counterA.leaveCount(), 1);
+        assertEquals(counterB.enterCount(), 5);
+        assertEquals(counterB.leaveCount(), 5);
+        assertEquals(counterC.enterCount(), 1);
+        assertEquals(counterC.leaveCount(), 1);
 
         // Run the clone and check that instruments B,C working but not A
         assertEquals(13, callTarget2.call());
-        assertEquals(counterA.enterCount, 1);
-        assertEquals(counterA.leaveCount, 1);
-        assertEquals(counterB.enterCount, 6);
-        assertEquals(counterB.leaveCount, 6);
-        assertEquals(counterC.enterCount, 2);
-        assertEquals(counterC.leaveCount, 2);
+        assertEquals(counterA.enterCount(), 1);
+        assertEquals(counterA.leaveCount(), 1);
+        assertEquals(counterB.enterCount(), 6);
+        assertEquals(counterB.leaveCount(), 6);
+        assertEquals(counterC.enterCount(), 2);
+        assertEquals(counterC.leaveCount(), 2);
 
         // Remove instrumentC
         counterC.dispose();
 
         // Run the original and check that instrument B working but not A,C
-        assertEquals(13, callTarget1.call());
-        assertEquals(counterA.enterCount, 1);
-        assertEquals(counterA.leaveCount, 1);
-        assertEquals(counterB.enterCount, 7);
-        assertEquals(counterB.leaveCount, 7);
-        assertEquals(counterC.enterCount, 2);
-        assertEquals(counterC.leaveCount, 2);
+        assertEquals(13, callTarget.call());
+        assertEquals(counterA.enterCount(), 1);
+        assertEquals(counterA.leaveCount(), 1);
+        assertEquals(counterB.enterCount(), 7);
+        assertEquals(counterB.leaveCount(), 7);
+        assertEquals(counterC.enterCount(), 2);
+        assertEquals(counterC.leaveCount(), 2);
 
         // Run the clone and check that instrument B working but not A,C
         assertEquals(13, callTarget2.call());
-        assertEquals(counterA.enterCount, 1);
-        assertEquals(counterA.leaveCount, 1);
-        assertEquals(counterB.enterCount, 8);
-        assertEquals(counterB.leaveCount, 8);
-        assertEquals(counterC.enterCount, 2);
-        assertEquals(counterC.leaveCount, 2);
+        assertEquals(counterA.enterCount(), 1);
+        assertEquals(counterA.leaveCount(), 1);
+        assertEquals(counterB.enterCount(), 8);
+        assertEquals(counterB.leaveCount(), 8);
+        assertEquals(counterC.enterCount(), 2);
+        assertEquals(counterC.leaveCount(), 2);
 
         // Remove instrumentB
         counterB.dispose();
 
         // Run both the original and clone, check that no instruments working
-        assertEquals(13, callTarget1.call());
+        assertEquals(13, callTarget.call());
         assertEquals(13, callTarget2.call());
-        assertEquals(counterA.enterCount, 1);
-        assertEquals(counterA.leaveCount, 1);
-        assertEquals(counterB.enterCount, 8);
-        assertEquals(counterB.leaveCount, 8);
-        assertEquals(counterC.enterCount, 2);
-        assertEquals(counterC.leaveCount, 2);
+        assertEquals(counterA.enterCount(), 1);
+        assertEquals(counterA.leaveCount(), 1);
+        assertEquals(counterB.enterCount(), 8);
+        assertEquals(counterB.leaveCount(), 8);
+        assertEquals(counterC.enterCount(), 2);
+        assertEquals(counterC.leaveCount(), 2);
+
     }
 
     @Test
@@ -313,131 +339,6 @@
 
     }
 
-    @Test
-    public void testProbeLite() {
-
-        // Use the "lite-probing" option, limited to a single pass of
-        // probing and a single Instrument at each probed node. This
-        // particular test uses a shared event listener at every
-        // lite-probed node.
-        final TestEventListener listener = new TestEventListener();
-
-        TestASTLiteProber astLiteProber = new TestASTLiteProber(listener);
-        Probe.registerASTProber(astLiteProber);
-
-        // 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);
-
-        // Creating a call target sets the parent pointers in this tree and is necessary prior to
-        // checking any parent/child relationships
-        final CallTarget callTarget = runtime.createCallTarget(rootNode);
-
-        // Check that the instrument is working as expected.
-        assertEquals(0, listener.counter);
-        callTarget.call();
-        assertEquals(2, listener.counter);
-
-        // Check that you can't probe a node that's already received a probeLite() call
-        try {
-            leftValueNode.probe();
-            fail();
-        } catch (IllegalStateException e) {
-        }
-
-        try {
-            rightValueNode.probe();
-            fail();
-        } catch (IllegalStateException e) {
-        }
-
-        // Check tree structure
-        assertTrue(leftValueNode.getParent() instanceof TestLanguageWrapperNode);
-        assertTrue(rightValueNode.getParent() instanceof TestLanguageWrapperNode);
-        TestLanguageWrapperNode leftWrapper = (TestLanguageWrapperNode) leftValueNode.getParent();
-        TestLanguageWrapperNode rightWrapper = (TestLanguageWrapperNode) rightValueNode.getParent();
-        assertEquals(addNode, leftWrapper.getParent());
-        assertEquals(addNode, rightWrapper.getParent());
-        Iterator<Node> iterator = addNode.getChildren().iterator();
-        assertEquals(leftWrapper, iterator.next());
-        assertEquals(rightWrapper, iterator.next());
-        assertFalse(iterator.hasNext());
-        assertEquals(rootNode, addNode.getParent());
-        iterator = rootNode.getChildren().iterator();
-        assertEquals(addNode, iterator.next());
-        assertFalse(iterator.hasNext());
-
-        // Check that you can't get a probe on the wrappers because they were "lite-probed"
-        try {
-            leftWrapper.getProbe();
-            fail();
-        } catch (IllegalStateException e) {
-        }
-        try {
-            rightWrapper.getProbe();
-            fail();
-        } catch (IllegalStateException e) {
-        }
-
-        // Check that you can't probe the wrappers
-        try {
-            leftWrapper.probe();
-            fail();
-        } catch (ProbeException e) {
-            assertEquals(e.getFailure().getReason(), ProbeFailure.Reason.WRAPPER_NODE);
-        }
-        try {
-            rightWrapper.probe();
-            fail();
-        } catch (ProbeException e) {
-            assertEquals(e.getFailure().getReason(), ProbeFailure.Reason.WRAPPER_NODE);
-        }
-        try {
-            leftWrapper.probeLite(null);
-            fail();
-        } catch (ProbeException e) {
-            assertEquals(e.getFailure().getReason(), ProbeFailure.Reason.WRAPPER_NODE);
-        }
-        try {
-            rightWrapper.probeLite(null);
-            fail();
-        } catch (ProbeException e) {
-            assertEquals(e.getFailure().getReason(), ProbeFailure.Reason.WRAPPER_NODE);
-        }
-
-        // Use reflection to check that each WrapperNode has a ProbeLiteNode with a
-        // SimpleEventListener
-        try {
-            java.lang.reflect.Field probeNodeField = leftWrapper.getClass().getDeclaredField("probeNode");
-
-            // cheat: probeNode is private, so we change it's accessibility at runtime
-            probeNodeField.setAccessible(true);
-            ProbeNode probeNode = (ProbeNode) probeNodeField.get(leftWrapper);
-
-            // hack: Since ProbeLiteNode is not visible, we do a string compare here
-            assertTrue(probeNode.getClass().toString().endsWith("ProbeLiteNode"));
-
-            // Now we do the same to check the type of the eventListener in ProbeLiteNode
-            java.lang.reflect.Field eventListenerField = probeNode.getClass().getDeclaredField("eventListener");
-            eventListenerField.setAccessible(true);
-            TruffleEventListener eventListener = (TruffleEventListener) eventListenerField.get(probeNode);
-            assertTrue(eventListener instanceof SimpleEventListener);
-
-            // Reset accessibility
-            probeNodeField.setAccessible(false);
-            eventListenerField.setAccessible(false);
-
-        } catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e) {
-            fail();
-        }
-
-        Probe.unregisterASTProber(astLiteProber);
-
-    }
-
     private abstract class TestLanguageNode extends Node {
         public abstract Object execute(VirtualFrame vFrame);
 
@@ -578,28 +479,51 @@
         }
     }
 
+    private interface TestCounter {
+
+        int enterCount();
+
+        int leaveCount();
+
+        void attach(Probe probe);
+
+        void dispose();
+
+    }
+
     /**
-     * A counter for the number of times execution enters and leaves a probed AST node.
+     * A counter for the number of times execution enters and leaves a probed AST node, using the
+     * simplest kind of listener.
      */
-    private class TestCounter {
+    private class TestInstrumentCounter implements TestCounter {
 
         public int enterCount = 0;
         public int leaveCount = 0;
         public final Instrument instrument;
 
-        public TestCounter() {
-            instrument = Instrument.create(new SimpleEventListener() {
+        public TestInstrumentCounter() {
+            this.instrument = Instrument.create(new SimpleInstrumentListener() {
 
                 @Override
-                public void enter(Node node, VirtualFrame vFrame) {
+                public void enter(Probe probe) {
                     enterCount++;
                 }
 
                 @Override
-                public void returnAny(Node node, VirtualFrame vFrame) {
+                public void returnAny(Probe probe) {
                     leaveCount++;
                 }
+
             }, "Instrumentation Test Counter");
+
+        }
+
+        public int enterCount() {
+            return enterCount;
+        }
+
+        public int leaveCount() {
+            return leaveCount;
         }
 
         public void attach(Probe probe) {
@@ -609,7 +533,50 @@
         public void dispose() {
             instrument.dispose();
         }
+    }
 
+    /**
+     * A counter for the number of times execution enters and leaves a probed AST node, using the
+     * simplest kind of listener.
+     */
+    private class TestASTInstrumentCounter implements TestCounter {
+
+        public int enterCount = 0;
+        public int leaveCount = 0;
+        public final Instrument instrument;
+
+        public TestASTInstrumentCounter() {
+            this.instrument = Instrument.create(new SimpleASTInstrumentListener() {
+
+                @Override
+                public void enter(Probe probe, Node node, VirtualFrame vFrame) {
+                    enterCount++;
+                }
+
+                @Override
+                public void returnAny(Probe probe, Node node, VirtualFrame vFrame) {
+                    leaveCount++;
+                }
+
+            }, "Instrumentation Test Counter");
+
+        }
+
+        public int enterCount() {
+            return enterCount;
+        }
+
+        public int leaveCount() {
+            return leaveCount;
+        }
+
+        public void attach(Probe probe) {
+            probe.attach(instrument);
+        }
+
+        public void dispose() {
+            instrument.dispose();
+        }
     }
 
     /**
@@ -641,38 +608,28 @@
     }
 
     /**
-     * "lite-probes" every value node with a shared event listener.
+     * Counts the number of "enter" events at probed nodes using the simplest AST listener.
      */
-    private static final class TestASTLiteProber implements NodeVisitor, ASTProber {
-        private final TruffleEventListener eventListener;
-
-        public TestASTLiteProber(SimpleEventListener simpleEventListener) {
-            this.eventListener = simpleEventListener;
-        }
-
-        public boolean visit(Node node) {
-            if (node instanceof TestValueNode) {
-                final TestLanguageNode testNode = (TestValueNode) node;
-                testNode.probeLite(eventListener);
-            }
-            return true;
-        }
-
-        public void probeAST(Node node) {
-            node.accept(this);
-        }
-    }
-
-    /**
-     * Counts the number of "enter" events at probed nodes.
-     *
-     */
-    static final class TestEventListener extends SimpleEventListener {
+    static final class TestInstrumentListener extends DefaultInstrumentListener {
 
         public int counter = 0;
 
         @Override
-        public void enter(Node node, VirtualFrame frame) {
+        public void enter(Probe probe) {
+            counter++;
+        }
+
+    }
+
+    /**
+     * Counts the number of "enter" events at probed nodes using the AST listener.
+     */
+    static final class TestASTInstrumentListener extends DefaultASTInstrumentListener {
+
+        public int counter = 0;
+
+        @Override
+        public void enter(Probe probe, Node node, VirtualFrame vFrame) {
             counter++;
         }
 
@@ -692,10 +649,10 @@
             // where we want to count executions.
             // it will get copied when ASTs cloned, so
             // keep the count in this outer class.
-            probe.attach(Instrument.create(new SimpleEventListener() {
+            probe.attach(Instrument.create(new DefaultInstrumentListener() {
 
                 @Override
-                public void enter(Node node, VirtualFrame vFrame) {
+                public void enter(Probe p) {
                     count++;
                 }
             }, "Instrumentation Test MultiCounter"));
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/Instrument.java	Thu Mar 12 15:02:01 2015 -0700
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/Instrument.java	Thu Mar 12 18:03:05 2015 -0700
@@ -27,45 +27,71 @@
 import com.oracle.truffle.api.*;
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.instrument.InstrumentationNode.TruffleEvents;
 import com.oracle.truffle.api.instrument.impl.*;
 import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.api.source.*;
 
 // TODO (mlvdv) migrate some of this to external documentation.
 // 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.
 /**
  * A dynamically added/removed binding between a {@link Probe}, which provides notification of
- * {@linkplain TruffleEventListener execution events} taking place at a {@link Node} in a Guest
- * Language (GL) Truffle AST, and a {@linkplain TruffleEventListener listener}, which consumes
- * notifications on behalf of an external tool.
+ * <em>execution events</em> taking place at a {@link Node} in a Guest Language (GL) Truffle AST,
+ * and a <em>listener</em>, which consumes notifications on behalf of an external tool. There are at
+ * present two kinds of listeners that be used:
+ * <ol>
+ * <li>{@link InstrumentListener} is the simplest and is intended for tools that require no access
+ * to the <em>internal execution state</em> of the Truffle execution, only that execution has passed
+ * through a particular location in the program. Information about that location is made available
+ * via the {@link Probe} argument in notification methods, including the {@linkplain SourceSection
+ * source location} of the node and any {@linkplain SyntaxTag tags} that have been applied to the
+ * node.</li>
+ * <li>{@link ASTInstrumentListener} reports the same events and {@link Probe} argument, but
+ * additionally provides access to the execution state via the explicit {@link Node} and
+ * {@link Frame} at the current execution site.</li>
+ * </ol>
  * <p>
  * <h4>Summary: How to "instrument" an AST location:</h4>
+ * <p>
  * <ol>
- * <li>Create an implementation of {@link TruffleEventListener} that responds to events on behalf of
- * a tool.</li>
- * <li>Create an Instrument via factory method {@link Instrument#create(TruffleEventListener)}.</li>
+ * <li>Create an implementation of a <em>listener</em> interface.</li>
+ * <li>Create an Instrument via factory methods
+ * {@link Instrument#create(InstrumentListener, String)} or
+ * {@link Instrument#create(ASTInstrumentListener, String)}.</li>
  * <li>"Attach" the Instrument to a Probe via {@link Probe#attach(Instrument)}, at which point event
  * notifications begin to arrive at the listener.</li>
- * <li>When no longer needed, "detach" the Instrument via {@link TruffleEventInstrument#dispose()},
- * at which point event notifications to the listener cease, and the Instrument becomes unusable.</li>
+ * <li>When no longer needed, "detach" the Instrument via {@link ASTInstrument#dispose()}, at which
+ * point event notifications to the listener cease, and the Instrument becomes unusable.</li>
  * </ol>
  * <p>
  * <h4>Options for creating listeners:</h4>
  * <p>
  * <ol>
- * <li>Implement the interface {@link TruffleEventListener}. The event handling methods account for
- * both the entry into an AST node (about to call) and several possible kinds of exit from an AST
- * node (just returned).</li>
- * <li>Extend {@link DefaultEventListener}, which provides a no-op implementation of every
- * {@link TruffleEventListener} method; override the methods of interest.</li>
- * <li>Extend {@link SimpleEventListener}, where return values are ignored so only two methods (for
- * "enter" and "return") will notify all events.</li>
+ * <li>Implement one of the <em>listener interfaces</em>: {@link InstrumentListener} or
+ * {@link ASTInstrumentListener} . Their event handling methods account for both the entry into an
+ * AST node (about to call) and three possible kinds of <em>execution return</em> from an AST node.</li>
+ * <li>Extend one of the <em>helper implementations</em>: {@link DefaultInstrumentListener} or
+ * {@link DefaultASTInstrumentListener}. These provide no-op implementation of every listener
+ * method, so only the methods of interest need to be overridden.</li>
+ * <li>Extend one of the <em>helper implementations</em>: {@link SimpleInstrumentListener} or
+ * {@link SimpleASTInstrumentListener}. These re-route all <em>execution returns</em> to a single
+ * method, ignoring return values, so only two methods (for "enter" and "return") will notify all
+ * events.</li>
  * </ol>
  * <p>
- * <h4>General guidelines for listener implementation:</h4>
+ * <h4>General guidelines for {@link ASTInstrumentListener} implementation:</h4>
  * <p>
- * When an Instrument is attached to a Probe, the listener effectively becomes part of the executing
- * GL program; performance can be affected by the listener's implementation.
+ * Unlike the listener interface {@link InstrumentListener}, which isolates implementations
+ * completely from Truffle internals (and is thus <em>Truffle-safe</em>), implementations of
+ * {@link ASTInstrumentListener} can interact directly with (and potentially affect) Truffle
+ * execution in general and Truffle optimization in particular. For example, it is possible to
+ * implement a debugger with this interface.
+ * </p>
+ * <p>
+ * As a consequence, implementations of {@link ASTInstrumentListener} effectively become part of the
+ * Truffle execution and must be coded according to general guidelines for Truffle implementations.
+ * For example:
  * <ul>
  * <li>Do not store {@link Frame} or {@link Node} references in fields.</li>
  * <li>Prefer {@code final} fields and (where performance is important) short methods.</li>
@@ -78,16 +104,18 @@
  * should be minimal.</li>
  * <li>On the other hand, implementations should prevent Truffle from inlining beyond a reasonable
  * point with the method annotation {@link TruffleBoundary}.</li>
- * <li>The implicit "outer" pointer in a non-static inner class is a useful way to implement
- * callbacks to owner tools.</li>
- * <li>Primitive-valued return events are boxed for notification, but Truffle will eliminate the
- * boxing if they are cast back to their primitive values quickly (in particular before crossing any
- * {@link TruffleBoundary} annotations).
+ * <li>The implicit "outer" pointer in a non-static inner class is a useful (and
+ * Truffle-optimizable) way to implement callbacks to owner tools.</li>
+ * <li>Primitive-valued return events are boxed for event notification, but Truffle will eliminate
+ * the boxing if they are cast back to their primitive values quickly (in particular before crossing
+ * any {@link TruffleBoundary} annotations).
  * </ul>
  * <p>
  * <h4>Allowing for AST cloning:</h4>
  * <p>
- * Truffle routinely <em>clones</em> ASTs, which has consequences for listener implementation.
+ * Truffle routinely <em>clones</em> ASTs, which has consequences for implementations of
+ * {@link ASTInstrumentListener} (but not for implementations of {@link InstrumentListener}, from
+ * which cloning is hidden).
  * <ul>
  * <li>Even though a {@link Probe} is uniquely associated with a particular location in the
  * executing Guest Language program, execution events at that location will in general be
@@ -98,22 +126,18 @@
  * be treated as equivalent for most purposes.</li>
  * </ul>
  * <p>
- * <h4>Access to execution state:</h4>
+ * <h4>Access to execution state via {@link ASTInstrumentListener}:</h4>
  * <p>
  * <ul>
- * <li>Event notification arguments provide primary access to the GL program's execution states:
+ * <li>Notification arguments provide primary access to the GL program's execution states:
  * <ul>
  * <li>{@link Node}: the concrete node (in one of the AST's clones) from which the event originated.
  * </li>
  * <li>{@link VirtualFrame}: the current execution frame.
  * </ul>
- * <li>Some global information is available, for example the execution
+ * <li>Truffle global information is available, for example the execution
  * {@linkplain TruffleRuntime#iterateFrames(FrameInstanceVisitor) stack}.</li>
- * <li>Additional information needed by a listener could be stored when created, preferably
- * {@code final} of course. For example, a reference to the {@link Probe} to which the listener's
- * Instrument has been attached would give access to its corresponding
- * {@linkplain Probe#getProbedSourceSection() source location} or to the collection of
- * {@linkplain SyntaxTag tags} currently applied to the Probe.</li>
+ * <li>Additional API access to execution state may be added in the future.</li>
  * </ul>
  * <p>
  * <h4>Activating and deactivating Instruments:</h4>
@@ -125,8 +149,8 @@
  * error to attempt attaching a previously attached instrument.</li>
  * <li>Attaching an instrument modifies every existing clone of the AST to which it is being
  * attached, which can trigger deoptimization.</li>
- * <li>The method {@link TruffleEventInstrument#dispose()} makes an instrument inactive by removing
- * it from the Probe to which it was attached and rendering it permanently inert.</li>
+ * <li>The method {@link Instrument#dispose()} makes an instrument inactive by removing it from the
+ * Probe to which it was attached and rendering it permanently inert.</li>
  * <li>Disposal removes the implementation of an instrument from all ASTs to which it was attached,
  * which can trigger deoptimization.</li>
  * </ul>
@@ -142,26 +166,32 @@
  * <strong>Disclaimer:</strong> experimental; under development.
  *
  * @see Probe
- * @see TruffleEventListener
+ * @see TruffleEvents
  */
 public abstract class Instrument {
 
     /**
      * Creates an instrument that will route execution events to a listener.
      *
-     * @param listener a listener for event generated by the instrument
-     * @param instrumentInfo optional description of the instrument's role
+     * @param listener a minimal listener for event generated by the instrument.
+     * @param 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(TruffleEventListener listener, String instrumentInfo) {
-        return new TruffleEventInstrument(listener, instrumentInfo);
+    public static Instrument create(InstrumentListener listener, String instrumentInfo) {
+        return new BasicInstrument(listener, instrumentInfo);
     }
 
     /**
-     * Creates an instrument that will route execution events to a listener.
+     * Creates an instrument that will route execution events to a listener, along with access to
+     * internal execution state.
+     *
+     * @param astListener a listener for event generated by the instrument that provides access to
+     *            internal execution state
+     * @param 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(TruffleEventListener listener) {
-        return new TruffleEventInstrument(listener, null);
+    public static Instrument create(ASTInstrumentListener astListener, String instrumentInfo) {
+        return new ASTInstrument(astListener, instrumentInfo);
     }
 
     // TODO (mlvdv) experimental
@@ -177,7 +207,7 @@
      */
     private boolean isDisposed = false;
 
-    private Probe probe = null;
+    protected Probe probe = null;
 
     /**
      * Optional documentation, mainly for debugging.
@@ -220,32 +250,30 @@
         return isDisposed;
     }
 
-    abstract InstrumentNode addToChain(InstrumentNode nextNode);
+    abstract AbstractInstrumentNode addToChain(AbstractInstrumentNode nextNode);
 
     /**
-     * Removes this instrument from an instrument chain.
+     * An instrument that propagates events to an instance of {@link InstrumentListener}.
      */
-    abstract InstrumentNode removeFromChain(InstrumentNode instrumentNode);
-
-    private static final class TruffleEventInstrument extends Instrument {
+    private static final class BasicInstrument extends Instrument {
 
         /**
          * Tool-supplied listener for events.
          */
-        private final TruffleEventListener toolEventListener;
+        private final InstrumentListener instrumentListener;
 
-        private TruffleEventInstrument(TruffleEventListener listener, String instrumentInfo) {
+        private BasicInstrument(InstrumentListener basicListener, String instrumentInfo) {
             super(instrumentInfo);
-            this.toolEventListener = listener;
+            this.instrumentListener = basicListener;
         }
 
         @Override
-        InstrumentNode addToChain(InstrumentNode nextNode) {
-            return new TruffleEventInstrumentNode(nextNode);
+        AbstractInstrumentNode addToChain(AbstractInstrumentNode nextNode) {
+            return new BasicInstrumentNode(nextNode);
         }
 
         @Override
-        InstrumentNode removeFromChain(InstrumentNode instrumentNode) {
+        AbstractInstrumentNode removeFromChain(AbstractInstrumentNode instrumentNode) {
             boolean found = false;
             if (instrumentNode != null) {
                 if (instrumentNode.getInstrument() == this) {
@@ -253,7 +281,7 @@
                     return instrumentNode.nextInstrument;
                 }
                 // Match not at the head of the chain; remove it.
-                found = instrumentNode.removeFromChain(TruffleEventInstrument.this);
+                found = instrumentNode.removeFromChain(BasicInstrument.this);
             }
             if (!found) {
                 throw new IllegalStateException("Couldn't find instrument node to remove: " + this);
@@ -262,35 +290,35 @@
         }
 
         @NodeInfo(cost = NodeCost.NONE)
-        private final class TruffleEventInstrumentNode extends InstrumentNode {
+        private final class BasicInstrumentNode extends AbstractInstrumentNode {
 
-            private TruffleEventInstrumentNode(InstrumentNode nextNode) {
+            private BasicInstrumentNode(AbstractInstrumentNode nextNode) {
                 super(nextNode);
             }
 
             public void enter(Node node, VirtualFrame vFrame) {
-                TruffleEventInstrument.this.toolEventListener.enter(node, vFrame);
+                BasicInstrument.this.instrumentListener.enter(BasicInstrument.this.probe);
                 if (nextInstrument != null) {
                     nextInstrument.enter(node, vFrame);
                 }
             }
 
             public void returnVoid(Node node, VirtualFrame vFrame) {
-                TruffleEventInstrument.this.toolEventListener.returnVoid(node, vFrame);
+                BasicInstrument.this.instrumentListener.returnVoid(BasicInstrument.this.probe);
                 if (nextInstrument != null) {
                     nextInstrument.returnVoid(node, vFrame);
                 }
             }
 
             public void returnValue(Node node, VirtualFrame vFrame, Object result) {
-                TruffleEventInstrument.this.toolEventListener.returnValue(node, vFrame, result);
+                BasicInstrument.this.instrumentListener.returnValue(BasicInstrument.this.probe, result);
                 if (nextInstrument != null) {
                     nextInstrument.returnValue(node, vFrame, result);
                 }
             }
 
             public void returnExceptional(Node node, VirtualFrame vFrame, Exception exception) {
-                TruffleEventInstrument.this.toolEventListener.returnExceptional(node, vFrame, exception);
+                BasicInstrument.this.instrumentListener.returnExceptional(BasicInstrument.this.probe, exception);
                 if (nextInstrument != null) {
                     nextInstrument.returnExceptional(node, vFrame, exception);
                 }
@@ -298,7 +326,91 @@
 
             public String instrumentationInfo() {
                 final String info = getInstrumentInfo();
-                return info != null ? info : toolEventListener.getClass().getSimpleName();
+                return info != null ? info : instrumentListener.getClass().getSimpleName();
+            }
+        }
+    }
+
+    /**
+     * Removes this instrument from an instrument chain.
+     */
+    abstract AbstractInstrumentNode removeFromChain(AbstractInstrumentNode instrumentNode);
+
+    /**
+     * An instrument that propagates events to an instance of {@link ASTInstrumentListener}.
+     */
+    private static final class ASTInstrument extends Instrument {
+
+        /**
+         * Tool-supplied listener for AST events.
+         */
+        private final ASTInstrumentListener astListener;
+
+        private ASTInstrument(ASTInstrumentListener astListener, String instrumentInfo) {
+            super(instrumentInfo);
+            this.astListener = astListener;
+        }
+
+        @Override
+        AbstractInstrumentNode addToChain(AbstractInstrumentNode nextNode) {
+            return new ASTInstrumentNode(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.nextInstrument;
+                }
+                // Match not at the head of the chain; remove it.
+                found = instrumentNode.removeFromChain(ASTInstrument.this);
+            }
+            if (!found) {
+                throw new IllegalStateException("Couldn't find instrument node to remove: " + this);
+            }
+            return instrumentNode;
+        }
+
+        @NodeInfo(cost = NodeCost.NONE)
+        private final class ASTInstrumentNode extends AbstractInstrumentNode {
+
+            private ASTInstrumentNode(AbstractInstrumentNode nextNode) {
+                super(nextNode);
+            }
+
+            public void enter(Node node, VirtualFrame vFrame) {
+                ASTInstrument.this.astListener.enter(ASTInstrument.this.probe, node, vFrame);
+                if (nextInstrument != null) {
+                    nextInstrument.enter(node, vFrame);
+                }
+            }
+
+            public void returnVoid(Node node, VirtualFrame vFrame) {
+                ASTInstrument.this.astListener.returnVoid(ASTInstrument.this.probe, node, vFrame);
+                if (nextInstrument != null) {
+                    nextInstrument.returnVoid(node, vFrame);
+                }
+            }
+
+            public void returnValue(Node node, VirtualFrame vFrame, Object result) {
+                ASTInstrument.this.astListener.returnValue(ASTInstrument.this.probe, node, vFrame, result);
+                if (nextInstrument != null) {
+                    nextInstrument.returnValue(node, vFrame, result);
+                }
+            }
+
+            public void returnExceptional(Node node, VirtualFrame vFrame, Exception exception) {
+                ASTInstrument.this.astListener.returnExceptional(ASTInstrument.this.probe, node, vFrame, exception);
+                if (nextInstrument != null) {
+                    nextInstrument.returnExceptional(node, vFrame, exception);
+                }
+            }
+
+            public String instrumentationInfo() {
+                final String info = getInstrumentInfo();
+                return info != null ? info : astListener.getClass().getSimpleName();
             }
         }
 
@@ -318,12 +430,12 @@
         }
 
         @Override
-        InstrumentNode addToChain(InstrumentNode nextNode) {
+        AbstractInstrumentNode addToChain(AbstractInstrumentNode nextNode) {
             return new TruffleOptInstrumentNode(nextNode);
         }
 
         @Override
-        InstrumentNode removeFromChain(InstrumentNode instrumentNode) {
+        AbstractInstrumentNode removeFromChain(AbstractInstrumentNode instrumentNode) {
             boolean found = false;
             if (instrumentNode != null) {
                 if (instrumentNode.getInstrument() == this) {
@@ -340,11 +452,11 @@
         }
 
         @NodeInfo(cost = NodeCost.NONE)
-        private final class TruffleOptInstrumentNode extends InstrumentNode {
+        private final class TruffleOptInstrumentNode extends AbstractInstrumentNode {
 
             private boolean isCompiled;
 
-            private TruffleOptInstrumentNode(InstrumentNode nextNode) {
+            private TruffleOptInstrumentNode(AbstractInstrumentNode nextNode) {
                 super(nextNode);
                 this.isCompiled = CompilerDirectives.inCompiledCode();
             }
@@ -386,10 +498,11 @@
     }
 
     @NodeInfo(cost = NodeCost.NONE)
-    abstract class InstrumentNode extends Node implements TruffleEventListener, InstrumentationNode {
-        @Child protected InstrumentNode nextInstrument;
+    abstract class AbstractInstrumentNode extends Node implements TruffleEvents, InstrumentationNode {
 
-        protected InstrumentNode(InstrumentNode nextNode) {
+        @Child protected AbstractInstrumentNode nextInstrument;
+
+        protected AbstractInstrumentNode(AbstractInstrumentNode nextNode) {
             this.nextInstrument = nextNode;
         }
 
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/InstrumentationNode.java	Thu Mar 12 15:02:01 2015 -0700
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/InstrumentationNode.java	Thu Mar 12 18:03:05 2015 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 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
@@ -24,6 +24,7 @@
  */
 package com.oracle.truffle.api.instrument;
 
+import com.oracle.truffle.api.frame.*;
 import com.oracle.truffle.api.nodes.*;
 
 /**
@@ -36,4 +37,31 @@
      * A short description of the particular role played by the node, intended to support debugging.
      */
     String instrumentationInfo();
+
+    /**
+     * Events at a Truffle node that get propagated through the Instrumentation Framework.
+     */
+    interface TruffleEvents {
+
+        /**
+         * An AST node's execute method is about to be called.
+         */
+        void enter(Node node, VirtualFrame vFrame);
+
+        /**
+         * An AST Node's {@code void}-valued execute method has just returned.
+         */
+        void returnVoid(Node node, VirtualFrame vFrame);
+
+        /**
+         * An AST Node's execute method has just returned a value (boxed if primitive).
+         */
+        void returnValue(Node node, VirtualFrame vFrame, Object result);
+
+        /**
+         * An AST Node's execute method has just thrown an exception.
+         */
+        void returnExceptional(Node node, VirtualFrame vFrame, Exception exception);
+
+    }
 }
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/Probe.java	Thu Mar 12 15:02:01 2015 -0700
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/Probe.java	Thu Mar 12 18:03:05 2015 -0700
@@ -29,6 +29,7 @@
 
 import com.oracle.truffle.api.*;
 import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
+import com.oracle.truffle.api.instrument.InstrumentationNode.TruffleEvents;
 import com.oracle.truffle.api.nodes.*;
 import com.oracle.truffle.api.source.*;
 import com.oracle.truffle.api.utilities.*;
@@ -41,9 +42,9 @@
  * is intended to persist at the location, even if the specific node instance is
  * {@linkplain Node#replace(Node) replaced}.
  * <p>
- * The effect of a binding is to intercept {@linkplain TruffleEventListener execution events}
- * arriving at the node and notify each attached {@link Instrument} before execution is allowed to
- * proceed to the child.
+ * 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.
  * <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.
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/ProbeNode.java	Thu Mar 12 15:02:01 2015 -0700
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/ProbeNode.java	Thu Mar 12 18:03:05 2015 -0700
@@ -27,14 +27,15 @@
 import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.api.frame.*;
-import com.oracle.truffle.api.instrument.Instrument.InstrumentNode;
+import com.oracle.truffle.api.instrument.Instrument.AbstractInstrumentNode;
+import com.oracle.truffle.api.instrument.InstrumentationNode.TruffleEvents;
 import com.oracle.truffle.api.nodes.*;
 import com.oracle.truffle.api.source.*;
 
 /**
  * Implementation interfaces and classes for attaching {@link Probe}s to {@link WrapperNode}s.
  */
-public abstract class ProbeNode extends Node implements TruffleEventListener, InstrumentationNode {
+public abstract class ProbeNode extends Node implements TruffleEvents, InstrumentationNode {
 
     /**
      * A node that can be inserted into a Truffle AST, and which enables {@linkplain Instrument
@@ -84,14 +85,14 @@
 
         /**
          * Gets the node being "wrapped", i.e. the AST node for which
-         * {@linkplain TruffleEventListener execution events} will be reported through the
-         * Instrumentation Framework.
+         * {@linkplain InstrumentationNode.TruffleEvents execution events} will be reported through
+         * the Instrumentation Framework.
          */
         Node getChild();
 
         /**
          * Gets the {@link Probe} responsible for installing this wrapper; none if the wrapper
-         * installed via {@linkplain Node#probeLite(TruffleEventListener) "lite-Probing"}.
+         * installed via {@linkplain Node#probeLite(ASTInstrumentListener) "lite-Probing"}.
          */
         Probe getProbe();
 
@@ -119,8 +120,8 @@
      * Creates a new {@link ProbeLiteNode} associated with, and attached to, a Guest Language
      * specific instance of {@link WrapperNode}.
      */
-    public static void insertProbeLite(WrapperNode wrapper, TruffleEventListener eventListener) {
-        final ProbeLiteNode probeLiteNode = new ProbeLiteNode(eventListener);
+    public static void insertProbeLite(WrapperNode wrapper, ASTInstrumentListener instrumentListener) {
+        final ProbeLiteNode probeLiteNode = new ProbeLiteNode(instrumentListener);
         wrapper.insertProbe(probeLiteNode);
     }
 
@@ -137,7 +138,7 @@
     public abstract Probe getProbe() throws IllegalStateException;
 
     /**
-     * Adds an {@link InstrumentNode} to this chain.
+     * Adds an {@link AbstractInstrumentNode} to this chain.
      *
      * @throws IllegalStateException if at a "lite-Probed" location.
      */
@@ -168,9 +169,10 @@
     private static final class ProbeFullNode extends ProbeNode {
 
         /**
-         * First {@link InstrumentNode} node in chain; {@code null} of no instruments in chain.
+         * First {@link AbstractInstrumentNode} node in chain; {@code null} of no instruments in
+         * chain.
          */
-        @Child protected InstrumentNode firstInstrument;
+        @Child protected AbstractInstrumentNode firstInstrument;
 
         // Never changed once set.
         @CompilationFinal private Probe probe = null;
@@ -208,7 +210,7 @@
         @TruffleBoundary
         void removeInstrument(Instrument instrument) {
             assert instrument.getProbe() == probe;
-            final InstrumentNode modifiedChain = instrument.removeFromChain(firstInstrument);
+            final AbstractInstrumentNode modifiedChain = instrument.removeFromChain(firstInstrument);
             if (modifiedChain == null) {
                 firstInstrument = null;
             } else {
@@ -256,15 +258,15 @@
     /**
      * Implementation of a probe that only ever has a single "instrument" associated with it. No
      * {@link Instrument} is ever created; instead this method simply delegates the various enter
-     * and return events to a {@link TruffleEventListener} passed in during construction.
+     * and return events to a {@link TruffleEvents} passed in during construction.
      */
     @NodeInfo(cost = NodeCost.NONE)
     private static final class ProbeLiteNode extends ProbeNode {
 
-        private final TruffleEventListener eventListener;
+        private final ASTInstrumentListener instrumentListener;
 
-        private ProbeLiteNode(TruffleEventListener eventListener) {
-            this.eventListener = eventListener;
+        private ProbeLiteNode(ASTInstrumentListener eventListener) {
+            this.instrumentListener = eventListener;
         }
 
         @Override
@@ -285,19 +287,19 @@
         }
 
         public void enter(Node node, VirtualFrame vFrame) {
-            eventListener.enter(node, vFrame);
+            instrumentListener.enter(getProbe(), node, vFrame);
         }
 
         public void returnVoid(Node node, VirtualFrame vFrame) {
-            eventListener.returnVoid(node, vFrame);
+            instrumentListener.returnVoid(getProbe(), node, vFrame);
         }
 
         public void returnValue(Node node, VirtualFrame vFrame, Object result) {
-            eventListener.returnValue(node, vFrame, result);
+            instrumentListener.returnValue(getProbe(), node, vFrame, result);
         }
 
         public void returnExceptional(Node node, VirtualFrame vFrame, Exception exception) {
-            eventListener.returnExceptional(node, vFrame, exception);
+            instrumentListener.returnExceptional(getProbe(), node, vFrame, exception);
         }
 
         public String instrumentationInfo() {
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/Node.java	Thu Mar 12 15:02:01 2015 -0700
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/Node.java	Thu Mar 12 18:03:05 2015 -0700
@@ -504,16 +504,16 @@
      * its parent; the wrapper node must be provided by implementations of
      * {@link #createWrapperNode()}.
      * <p>
-     * Unlike {@link #probe()}, once {@link #probeLite(TruffleEventListener)} is called at a node,
+     * Unlike {@link #probe()}, once {@link #probeLite(ASTInstrumentListener)} is called at a node,
      * no additional probing can be added and no additional instrumentation can be attached.
      * <p>
      * This restricted form of instrumentation is intended for special cases where only one kind of
      * instrumentation is desired, and for which performance is a concern
      *
-     * @param eventListener
+     * @param instrumentListener
      * @throws ProbeException (unchecked) when a probe cannot be created, leaving the AST unchanged
      */
-    public final void probeLite(TruffleEventListener eventListener) {
+    public final void probeLite(ASTInstrumentListener instrumentListener) {
 
         if (this instanceof WrapperNode) {
             throw new ProbeException(ProbeFailure.Reason.WRAPPER_NODE, null, this, null);
@@ -545,7 +545,7 @@
         }
 
         // Connect it to a Probe
-        ProbeNode.insertProbeLite(wrapper, eventListener);
+        ProbeNode.insertProbeLite(wrapper, instrumentListener);
 
         // Replace this node in the AST with the wrapper
         this.replace(wrapperNode);
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/tools/CoverageTracker.java	Thu Mar 12 15:02:01 2015 -0700
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/tools/CoverageTracker.java	Thu Mar 12 18:03:05 2015 -0700
@@ -28,7 +28,6 @@
 import java.util.*;
 import java.util.Map.Entry;
 
-import com.oracle.truffle.api.frame.*;
 import com.oracle.truffle.api.instrument.*;
 import com.oracle.truffle.api.instrument.impl.*;
 import com.oracle.truffle.api.nodes.*;
@@ -49,7 +48,7 @@
  * <p>
  * <ul>
  * <li>"Execution call" on a node is is defined as invocation of a node method that is instrumented
- * to produce the event {@link TruffleEventListener#enter(Node, VirtualFrame)};</li>
+ * to produce the event {@link InstrumentListener#enter(Probe)};</li>
  * <li>Execution calls are tabulated only at <em>instrumented</em> nodes, i.e. those for which
  * {@linkplain Node#isInstrumentable() isInstrumentable() == true};</li>
  * <li>Execution calls are tabulated only at nodes present in the AST when originally created;
@@ -227,7 +226,7 @@
      * A listener for events at each instrumented AST location. This listener counts
      * "execution calls" to the instrumented node.
      */
-    private final class CoverageRecord extends DefaultEventListener {
+    private final class CoverageRecord extends DefaultInstrumentListener {
 
         private final SourceSection srcSection; // The text of the code being counted
         private Instrument instrument;  // The attached Instrument, in case need to remove.
@@ -238,7 +237,7 @@
         }
 
         @Override
-        public void enter(Node node, VirtualFrame vFrame) {
+        public void enter(Probe probe) {
             if (isEnabled()) {
                 count++;
             }
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/tools/NodeExecCounter.java	Thu Mar 12 15:02:01 2015 -0700
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/tools/NodeExecCounter.java	Thu Mar 12 18:03:05 2015 -0700
@@ -49,7 +49,7 @@
  * <p>
  * <ul>
  * <li>"Execution call" on a node is is defined as invocation of a node method that is instrumented
- * to produce the event {@link TruffleEventListener#enter(Node, VirtualFrame)};</li>
+ * to produce the event {@link ASTInstrumentListener#enter(Probe, Node, VirtualFrame)};</li>
  * <li>Execution calls are tabulated only at <em>instrumented</em> nodes, i.e. those for which
  * {@linkplain Node#isInstrumentable() isInstrumentable() == true};</li>
  * <li>Execution calls are tabulated only at nodes present in the AST when originally created;
@@ -95,15 +95,15 @@
      * 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}.
      */
-    private final TruffleEventListener eventListener = new DefaultEventListener() {
+    private final ASTInstrumentListener instrumentListener = new DefaultASTInstrumentListener() {
         @Override
-        public void enter(Node node, VirtualFrame vFrame) {
+        public void enter(Probe probe, Node node, VirtualFrame vFrame) {
             if (isEnabled()) {
                 final Class<?> nodeClass = node.getClass();
                 /*
                  * 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.
                  */
@@ -280,7 +280,7 @@
 
             if (node.isInstrumentable()) {
                 try {
-                    final Instrument instrument = Instrument.create(eventListener, "NodeExecCounter");
+                    final Instrument instrument = Instrument.create(instrumentListener, "NodeExecCounter");
                     instruments.add(instrument);
                     node.probe().attach(instrument);
                 } catch (ProbeException ex) {
@@ -304,7 +304,7 @@
         @Override
         public void probeTaggedAs(Probe probe, SyntaxTag tag, Object tagValue) {
             if (countingTag == tag) {
-                final Instrument instrument = Instrument.create(eventListener, NodeExecCounter.class.getSimpleName());
+                final Instrument instrument = Instrument.create(instrumentListener, NodeExecCounter.class.getSimpleName());
                 instruments.add(instrument);
                 probe.attach(instrument);
             }
--- a/graal/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/instrument/SLInstrumentTestRunner.java	Thu Mar 12 15:02:01 2015 -0700
+++ b/graal/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/instrument/SLInstrumentTestRunner.java	Thu Mar 12 18:03:05 2015 -0700
@@ -36,10 +36,8 @@
 import org.junit.runners.*;
 import org.junit.runners.model.*;
 
-import com.oracle.truffle.api.frame.*;
 import com.oracle.truffle.api.instrument.*;
 import com.oracle.truffle.api.instrument.impl.*;
-import com.oracle.truffle.api.nodes.*;
 import com.oracle.truffle.api.source.*;
 import com.oracle.truffle.sl.factory.*;
 import com.oracle.truffle.sl.nodes.instrument.*;
@@ -271,12 +269,12 @@
     }
 
     /**
-     * This sample instrument listener provides prints the value of an assignment (after the
-     * assignment is complete) to the {@link PrintStream} specified in the constructor. This
-     * instrument can only be attached to a wrapped {@link SLWriteLocalVariableNode}, but provides
-     * no guards to protect it from being attached elsewhere.
+     * This sample listener provides prints the value of an assignment (after the assignment is
+     * complete) to the {@link PrintStream} specified in the constructor. This listener can only be
+     * attached at {@link SLWriteLocalVariableNode}, but provides no guards to protect it from being
+     * attached elsewhere.
      */
-    public final class SLPrintAssigmentValueListener extends DefaultEventListener {
+    public final class SLPrintAssigmentValueListener extends DefaultInstrumentListener {
 
         private PrintStream output;
 
@@ -285,7 +283,7 @@
         }
 
         @Override
-        public void returnValue(Node node, VirtualFrame frame, Object result) {
+        public void returnValue(Probe probe, Object result) {
             output.println(result);
         }
     }