changeset 19872:7d74d3ad09f4

Merge
author Stefan Anzinger <stefan.anzinger@oracle.com>
date Fri, 13 Mar 2015 11:28:01 +0100
parents 9f1404a45a6f (current diff) a5b09092003a (diff)
children 8e316bc46018
files graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/TruffleEventListener.java graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/DefaultEventListener.java graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/SimpleEventListener.java
diffstat 33 files changed, 1019 insertions(+), 600 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/GraalOptions.java	Thu Mar 12 17:08:19 2015 +0100
+++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/GraalOptions.java	Fri Mar 13 11:28:01 2015 +0100
@@ -134,9 +134,6 @@
     @Option(help = "", type = OptionType.Debug)
     public static final OptionValue<String> PrintFilter = new OptionValue<>(null);
 
-    @Option(help = "", type = OptionType.Debug)
-    public static final StableOptionValue<Boolean> DumpDuringGraphBuilding = new StableOptionValue<>(false);
-
     // Debug settings:
     @Option(help = "", type = OptionType.Debug)
     public static final OptionValue<Boolean> BootstrapReplacements = new OptionValue<>(false);
@@ -324,13 +321,6 @@
     @Option(help = "Mark well-known stable fields as such.", type = OptionType.Debug)
     public static final OptionValue<Boolean> ImplicitStableValues = new OptionValue<>(true);
 
-
-    @Option(help = "Max number of loop explosions per method.", type = OptionType.Debug)
-    public static final OptionValue<Integer> MaximumLoopExplosionCount = new OptionValue<>(10000);
-
-    @Option(help = "Do not bail out but throw an exception on failed loop explosion.", type = OptionType.Debug)
-    public static final OptionValue<Boolean> FailedLoopExplosionIsFatal = new OptionValue<>(false);
-
     /**
      * Counts the various paths taken through snippets.
      */
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeClass.java	Thu Mar 12 17:08:19 2015 +0100
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeClass.java	Fri Mar 13 11:28:01 2015 +0100
@@ -182,9 +182,7 @@
 
                 NodeClass<?> snc = superNodeClass;
                 while (snc != null && IterableNodeType.class.isAssignableFrom(snc.getClazz())) {
-                    assert !containsId(this.iterableId, snc.iterableIds);
-                    snc.iterableIds = Arrays.copyOf(snc.iterableIds, snc.iterableIds.length + 1);
-                    snc.iterableIds[snc.iterableIds.length - 1] = this.iterableId;
+                    snc.addIterableId(iterableId);
                     snc = snc.superNodeClass;
                 }
 
@@ -195,6 +193,23 @@
             this.iterableIds = null;
         }
         nodeIterableCount = Debug.metric("NodeIterable_%s", clazz);
+        assert verifyIterableIds();
+    }
+
+    private synchronized void addIterableId(int newIterableId) {
+        assert !containsId(newIterableId, iterableIds);
+        int[] copy = Arrays.copyOf(iterableIds, iterableIds.length + 1);
+        copy[iterableIds.length] = newIterableId;
+        iterableIds = copy;
+    }
+
+    private boolean verifyIterableIds() {
+        NodeClass<?> snc = superNodeClass;
+        while (snc != null && IterableNodeType.class.isAssignableFrom(snc.getClazz())) {
+            assert containsId(iterableId, snc.iterableIds);
+            snc = snc.superNodeClass;
+        }
+        return true;
     }
 
     private static boolean containsId(int iterableId, int[] iterableIds) {
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java	Thu Mar 12 17:08:19 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java	Fri Mar 13 11:28:01 2015 +0100
@@ -1444,6 +1444,7 @@
     @HotSpotVMValue(expression = "SharedRuntime::dsin", get = HotSpotVMValue.Type.ADDRESS) @Stable public long arithmeticSinAddress;
     @HotSpotVMValue(expression = "SharedRuntime::dcos", get = HotSpotVMValue.Type.ADDRESS) @Stable public long arithmeticCosAddress;
     @HotSpotVMValue(expression = "SharedRuntime::dtan", get = HotSpotVMValue.Type.ADDRESS) @Stable public long arithmeticTanAddress;
+    @HotSpotVMValue(expression = "SharedRuntime::dpow", get = HotSpotVMValue.Type.ADDRESS) @Stable public long arithmeticPowAddress;
 
     @HotSpotVMValue(expression = "(jint) GraalCounterSize") @Stable public int graalCountersSize;
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotHostForeignCallsProvider.java	Thu Mar 12 17:08:19 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotHostForeignCallsProvider.java	Fri Mar 13 11:28:01 2015 +0100
@@ -150,6 +150,7 @@
         registerForeignCall(ARITHMETIC_SIN, c.arithmeticSinAddress, NativeCall, DESTROYS_REGISTERS, LEAF, REEXECUTABLE, NO_LOCATIONS);
         registerForeignCall(ARITHMETIC_COS, c.arithmeticCosAddress, NativeCall, DESTROYS_REGISTERS, LEAF, REEXECUTABLE, NO_LOCATIONS);
         registerForeignCall(ARITHMETIC_TAN, c.arithmeticTanAddress, NativeCall, DESTROYS_REGISTERS, LEAF, REEXECUTABLE, NO_LOCATIONS);
+        registerForeignCall(ARITHMETIC_POW, c.arithmeticPowAddress, NativeCall, DESTROYS_REGISTERS, LEAF, REEXECUTABLE, NO_LOCATIONS);
         registerForeignCall(LOAD_AND_CLEAR_EXCEPTION, c.loadAndClearExceptionAddress, NativeCall, DESTROYS_REGISTERS, LEAF_NOFP, NOT_REEXECUTABLE, ANY_LOCATION);
 
         registerForeignCall(EXCEPTION_HANDLER_FOR_PC, c.exceptionHandlerForPcAddress, NativeCall, DESTROYS_REGISTERS, NOT_LEAF, REEXECUTABLE, ANY_LOCATION);
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotInlineInvokePlugin.java	Thu Mar 12 17:08:19 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotInlineInvokePlugin.java	Fri Mar 13 11:28:01 2015 +0100
@@ -27,10 +27,10 @@
 import static java.lang.String.*;
 
 import com.oracle.graal.api.meta.*;
-import com.oracle.graal.api.replacements.*;
 import com.oracle.graal.graph.Node.NodeIntrinsic;
 import com.oracle.graal.hotspot.word.*;
 import com.oracle.graal.java.*;
+import com.oracle.graal.java.GraphBuilderContext.Replacement;
 import com.oracle.graal.java.GraphBuilderPlugin.InlineInvokePlugin;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.replacements.*;
@@ -69,8 +69,10 @@
 
     public void notifyOfNoninlinedInvoke(GraphBuilderContext b, ResolvedJavaMethod method, Invoke invoke) {
         if (b.parsingReplacement()) {
-            boolean compilingSnippet = b.getRootMethod().getAnnotation(MethodSubstitution.class) == null;
-            assert compilingSnippet : format("All calls in the replacement %s must be inlined or intrinsified: found call to %s", b.getRootMethod().format("%H.%n(%p)"), method.format("%h.%n(%p)"));
+            boolean compilingSnippet = b.getRootMethod().getAnnotation(Snippet.class) != null;
+            Replacement replacement = b.getReplacement();
+            assert compilingSnippet : format("All calls in the replacement %s must be inlined or intrinsified: found call to %s", replacement.getReplacementMethod().format("%H.%n(%p)"),
+                            method.format("%h.%n(%p)"));
         }
     }
 }
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/AbstractBytecodeParser.java	Thu Mar 12 17:08:19 2015 +0100
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/AbstractBytecodeParser.java	Fri Mar 13 11:28:01 2015 +0100
@@ -27,6 +27,7 @@
 import static com.oracle.graal.api.meta.DeoptimizationReason.*;
 import static com.oracle.graal.bytecode.Bytecodes.*;
 import static com.oracle.graal.java.AbstractBytecodeParser.Options.*;
+
 import java.util.*;
 
 import com.oracle.graal.api.code.*;
@@ -37,6 +38,7 @@
 import com.oracle.graal.compiler.common.calc.*;
 import com.oracle.graal.debug.*;
 import com.oracle.graal.java.BciBlockMapping.BciBlock;
+import com.oracle.graal.java.GraphBuilderContext.Replacement;
 import com.oracle.graal.java.GraphBuilderPhase.Instance.BytecodeParser;
 import com.oracle.graal.java.GraphBuilderPlugin.LoadFieldPlugin;
 import com.oracle.graal.java.GraphBuilderPlugin.LoadIndexedPlugin;
@@ -51,18 +53,27 @@
         @Option(help = "The trace level for the bytecode parser used when building a graph from bytecode", type = OptionType.Debug)
         public static final OptionValue<Integer> TraceBytecodeParserLevel = new OptionValue<>(0);
 
-        @Option(help = "Inlines trivial methods during parsing of the bytecodes.", type = OptionType.Expert)
+        @Option(help = "Inlines trivial methods during bytecode parsing.", type = OptionType.Expert)
         public static final StableOptionValue<Boolean> InlineDuringParsing = new StableOptionValue<>(false);
 
-        @Option(help = "Traces inlining eagerly performed during bytecode parsing", type = OptionType.Debug)
+        @Option(help = "Traces inlining performed during bytecode parsing.", type = OptionType.Debug)
         public static final StableOptionValue<Boolean> TraceInlineDuringParsing = new StableOptionValue<>(false);
 
-        @Option(help = "Traces use of bytecode parser plugins", type = OptionType.Debug)
+        @Option(help = "Traces use of plugins during bytecode parsing.", type = OptionType.Debug)
         public static final StableOptionValue<Boolean> TraceParserPlugins = new StableOptionValue<>(false);
 
-        @Option(help = "Maximum depth when inlining during parsing.", type = OptionType.Debug)
+        @Option(help = "Maximum depth when inlining during bytecode parsing.", type = OptionType.Debug)
         public static final StableOptionValue<Integer> InlineDuringParsingMaxDepth = new StableOptionValue<>(10);
 
+        @Option(help = "Dump graphs after non-trivial changes during bytecode parsing.", type = OptionType.Debug)
+        public static final StableOptionValue<Boolean> DumpDuringGraphBuilding = new StableOptionValue<>(false);
+
+        @Option(help = "Max number of loop explosions per method.", type = OptionType.Debug)
+        public static final OptionValue<Integer> MaximumLoopExplosionCount = new OptionValue<>(10000);
+
+        @Option(help = "Do not bail out but throw an exception on failed loop explosion.", type = OptionType.Debug)
+        public static final OptionValue<Boolean> FailedLoopExplosionIsFatal = new OptionValue<>(false);
+
         // @formatter:on
     }
 
@@ -71,7 +82,7 @@
      * happen when a call to a {@link MethodSubstitution} is encountered or the root of compilation
      * is a {@link MethodSubstitution} or a snippet.
      */
-    static class ReplacementContext {
+    static class ReplacementContext implements Replacement {
         /**
          * The method being replaced.
          */
@@ -87,6 +98,18 @@
             this.replacement = substitute;
         }
 
+        public ResolvedJavaMethod getOriginalMethod() {
+            return method;
+        }
+
+        public ResolvedJavaMethod getReplacementMethod() {
+            return replacement;
+        }
+
+        public boolean isIntrinsic() {
+            return false;
+        }
+
         /**
          * Determines if a call within the compilation scope of a replacement represents a call to
          * the original method.
@@ -102,7 +125,7 @@
 
     /**
      * Context for a replacement being inlined as a compiler intrinsic. Deoptimization within a
-     * compiler intrinic must replay the intrinsified call. This context object retains the
+     * compiler intrinsic must replay the intrinsified call. This context object retains the
      * information required to build a frame state denoting the JVM state just before the
      * intrinsified call.
      */
@@ -127,6 +150,11 @@
             this.invokeBci = invokeBci;
         }
 
+        @Override
+        public boolean isIntrinsic() {
+            return true;
+        }
+
         /**
          * Gets the frame state that will restart the interpreter just before the intrinsified
          * invocation.
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderContext.java	Thu Mar 12 17:08:19 2015 +0100
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderContext.java	Fri Mar 13 11:28:01 2015 +0100
@@ -34,6 +34,30 @@
  */
 public interface GraphBuilderContext {
 
+    /**
+     * Information about a snippet or method substitution currently being processed by the graph
+     * builder.
+     */
+    public interface Replacement {
+
+        /**
+         * Gets the method being replaced.
+         */
+        ResolvedJavaMethod getOriginalMethod();
+
+        /**
+         * Gets the replacement method.
+         */
+        ResolvedJavaMethod getReplacementMethod();
+
+        /**
+         * Determines if this replacement is being inlined as a compiler intrinsic. A compiler
+         * intrinsic is atomic with respect to deoptimization. Deoptimization within a compiler
+         * intrinsic will restart the interpreter at the intrinsified call.
+         */
+        boolean isIntrinsic();
+    }
+
     <T extends ControlSinkNode> T append(T fixed);
 
     <T extends ControlSplitNode> T append(T fixed);
@@ -87,7 +111,15 @@
     /**
      * Determines if the current parsing context is a snippet or method substitution.
      */
-    boolean parsingReplacement();
+    default boolean parsingReplacement() {
+        return getReplacement() == null;
+    }
+
+    /**
+     * Gets the replacement of the current parsing context or {@code null} if not
+     * {@link #parsingReplacement() parsing a replacement}.
+     */
+    Replacement getReplacement();
 
     /**
      * @see GuardingPiNode#nullCheckedValue(ValueNode)
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java	Thu Mar 12 17:08:19 2015 +0100
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java	Fri Mar 13 11:28:01 2015 +0100
@@ -461,7 +461,7 @@
                 for (int i = loopBegins.size() - 1; i >= 0; --i) {
                     LoopBeginNode loopBegin = loopBegins.get(i);
                     insertLoopExits(loopBegin, innerLoopsMap);
-                    if (GraalOptions.DumpDuringGraphBuilding.getValue()) {
+                    if (DumpDuringGraphBuilding.getValue()) {
                         Debug.dump(currentGraph, "After building loop exits for %s.", loopBegin);
                     }
                 }
@@ -527,7 +527,7 @@
 
                 for (LoopBeginNode inner : innerLoopBegins) {
                     addLoopExits(loopBegin, inner, innerLoopsMap, visited);
-                    if (GraalOptions.DumpDuringGraphBuilding.getValue()) {
+                    if (DumpDuringGraphBuilding.getValue()) {
                         Debug.dump(currentGraph, "After adding loop exits for %s.", inner);
                     }
                 }
@@ -1210,9 +1210,10 @@
                 }
                 ReplacementContext context = this.replacementContext;
                 if (context != null && context.isCallToOriginal(targetMethod)) {
+                    assert context.asIntrinsic() == null : "intrinsic cannot call the method it is intrinsifying";
                     // Self recursive replacement means the original
                     // method should be called.
-                    if (targetMethod.hasBytecodes()) {
+                    if (context.method.hasBytecodes()) {
                         parseAndInlineCallee(context.method, args, null);
                     } else {
                         return false;
@@ -1225,9 +1226,13 @@
                             context = new ReplacementContext(targetMethod, inlinedMethod);
                         }
                     }
-                    parseAndInlineCallee(inlinedMethod, args, context);
-                    if (plugin != null) {
-                        plugin.postInline(inlinedMethod);
+                    if (inlinedMethod.hasBytecodes()) {
+                        parseAndInlineCallee(inlinedMethod, args, context);
+                        if (plugin != null) {
+                            plugin.postInline(inlinedMethod);
+                        }
+                    } else {
+                        return false;
                     }
                 }
                 return true;
@@ -2350,6 +2355,10 @@
                 return parent == null ? 0 : 1 + parent.getDepth();
             }
 
+            public Replacement getReplacement() {
+                return replacementContext;
+            }
+
             public ResolvedJavaMethod getRootMethod() {
                 return rootMethod;
             }
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPlugin.java	Thu Mar 12 17:08:19 2015 +0100
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPlugin.java	Fri Mar 13 11:28:01 2015 +0100
@@ -77,7 +77,7 @@
             /**
              * The method to be inlined. If this is not equal to the {@code method} argument passed
              * to {@link InlineInvokePlugin#getClass()}, the graph builder context interprets it as
-             * a {@linkplain GraphBuilderContext#parsingReplacement() replacement}.
+             * a {@linkplain GraphBuilderContext.Replacement replacement}.
              */
             public final ResolvedJavaMethod methodToInline;
 
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/InliningUtil.java	Thu Mar 12 17:08:19 2015 +0100
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/InliningUtil.java	Fri Mar 13 11:28:01 2015 +0100
@@ -438,10 +438,11 @@
                 } else {
                     // only handle the outermost frame states
                     if (frameState.outerFrameState() == null) {
+                        assert frameState.bci != BytecodeFrame.AFTER_EXCEPTION_BCI : frameState;
                         assert frameState.bci != BytecodeFrame.BEFORE_BCI : frameState;
-                        assert frameState.bci == BytecodeFrame.INVALID_FRAMESTATE_BCI || frameState.method().equals(inlineGraph.method());
-                        assert frameState.bci != BytecodeFrame.AFTER_EXCEPTION_BCI && frameState.bci != BytecodeFrame.BEFORE_BCI && frameState.bci != BytecodeFrame.AFTER_EXCEPTION_BCI &&
-                                        frameState.bci != BytecodeFrame.UNWIND_BCI : frameState.bci;
+                        assert frameState.bci != BytecodeFrame.UNKNOWN_BCI : frameState;
+                        assert frameState.bci != BytecodeFrame.UNWIND_BCI : frameState;
+                        assert frameState.bci == BytecodeFrame.INVALID_FRAMESTATE_BCI || frameState.method().equals(inlineGraph.method()) : frameState;
                         if (outerFrameState == null) {
                             outerFrameState = stateAtReturn.duplicateModifiedDuringCall(invoke.bci(), invokeReturnKind);
                         }
--- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/ReplacementsParseTest.java	Thu Mar 12 17:08:19 2015 +0100
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/ReplacementsParseTest.java	Fri Mar 13 11:28:01 2015 +0100
@@ -51,16 +51,6 @@
     static class TestMethodsSubstitutions {
 
         @MethodSubstitution(isStatic = true)
-        static double next(double v) {
-            return TestMethods.next(v);
-        }
-
-        @MethodSubstitution(isStatic = true)
-        static double next2(double v) {
-            return next2(v);
-        }
-
-        @MethodSubstitution(isStatic = true)
         static double nextAfter(double x, double d) {
             double xx = (x == -0.0 ? 0.0 : x);
             return Math.nextAfter(xx, d);
--- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/StandardMethodSubstitutionsTest.java	Thu Mar 12 17:08:19 2015 +0100
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/StandardMethodSubstitutionsTest.java	Fri Mar 13 11:28:01 2015 +0100
@@ -57,42 +57,68 @@
         test("mathAll", value);
     }
 
-    @SuppressWarnings("all")
+    @Test
+    public void testMathPow() {
+        double a = 34567.891D;
+        double b = 4.6D;
+        test("mathPow", a, b);
+
+        // Test the values directly handled by the substitution
+
+        // If the second argument is positive or negative zero, then the result is 1.0.
+        test("mathPow", a, 0.0D);
+        test("mathPow", a, -0.0D);
+        // If the second argument is 1.0, then the result is the same as the first argument.
+        test("mathPow", a, 1.0D);
+        // If the second argument is NaN, then the result is NaN.
+        test("mathPow", a, Double.NaN);
+        // If the first argument is NaN and the second argument is nonzero, then the result is NaN.
+        test("mathPow", Double.NaN, b);
+        test("mathPow", Double.NaN, 0.0D);
+        // x**-1 = 1/x
+        test("mathPow", a, -1.0D);
+        // x**2 = x*x
+        test("mathPow", a, 2.0D);
+        // x**0.5 = sqrt(x)
+        test("mathPow", a, 0.5D);
+    }
+
+    public static double mathPow(double a, double b) {
+        return mathPow0(a, b);
+    }
+
+    public static double mathPow0(double a, double b) {
+        return Math.pow(a, b);
+    }
+
     public static double mathAbs(double value) {
         return Math.abs(value);
     }
 
-    @SuppressWarnings("all")
     public static double mathSqrt(double value) {
         return Math.sqrt(value);
     }
 
-    @SuppressWarnings("all")
     public static double mathLog(double value) {
         return Math.log(value);
     }
 
-    @SuppressWarnings("all")
     public static double mathLog10(double value) {
         return Math.log10(value);
     }
 
-    @SuppressWarnings("all")
     public static double mathSin(double value) {
         return Math.sin(value);
     }
 
-    @SuppressWarnings("all")
     public static double mathCos(double value) {
         return Math.cos(value);
     }
 
-    @SuppressWarnings("all")
     public static double mathTan(double value) {
         return Math.tan(value);
     }
 
-    @SuppressWarnings("all")
     public static double mathAll(double value) {
         return Math.sqrt(value) + Math.log(value) + Math.log10(value) + Math.sin(value) + Math.cos(value) + Math.tan(value);
     }
@@ -130,22 +156,18 @@
         testSubstitution("integerBitCount", BitCountNode.class, Integer.class, "bitCount", true, args);
     }
 
-    @SuppressWarnings("all")
     public static int integerReverseBytes(int value) {
         return Integer.reverseBytes(value);
     }
 
-    @SuppressWarnings("all")
     public static int integerNumberOfLeadingZeros(int value) {
         return Integer.numberOfLeadingZeros(value);
     }
 
-    @SuppressWarnings("all")
     public static int integerNumberOfTrailingZeros(int value) {
         return Integer.numberOfTrailingZeros(value);
     }
 
-    @SuppressWarnings("all")
     public static int integerBitCount(int value) {
         return Integer.bitCount(value);
     }
@@ -160,22 +182,18 @@
         testSubstitution("longBitCount", BitCountNode.class, Long.class, "bitCount", true, args);
     }
 
-    @SuppressWarnings("all")
     public static long longReverseBytes(long value) {
         return Long.reverseBytes(value);
     }
 
-    @SuppressWarnings("all")
     public static int longNumberOfLeadingZeros(long value) {
         return Long.numberOfLeadingZeros(value);
     }
 
-    @SuppressWarnings("all")
     public static int longNumberOfTrailingZeros(long value) {
         return Long.numberOfTrailingZeros(value);
     }
 
-    @SuppressWarnings("all")
     public static int longBitCount(long value) {
         return Long.bitCount(value);
     }
@@ -186,12 +204,10 @@
         testGraph("intBitsToFloat");
     }
 
-    @SuppressWarnings("all")
     public static int floatToIntBits(float value) {
         return Float.floatToIntBits(value);
     }
 
-    @SuppressWarnings("all")
     public static float intBitsToFloat(int value) {
         return Float.intBitsToFloat(value);
     }
@@ -202,22 +218,18 @@
         testGraph("longBitsToDouble");
     }
 
-    @SuppressWarnings("all")
     public static long doubleToLongBits(double value) {
         return Double.doubleToLongBits(value);
     }
 
-    @SuppressWarnings("all")
     public static double longBitsToDouble(long value) {
         return Double.longBitsToDouble(value);
     }
 
-    @SuppressWarnings("all")
     public static boolean isInstance(Class<?> clazz, Object object) {
         return clazz.isInstance(object);
     }
 
-    @SuppressWarnings("all")
     public static boolean isAssignableFrom(Class<?> clazz, Class<?> other) {
         return clazz.isAssignableFrom(other);
     }
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/MathSubstitutionsX86.java	Thu Mar 12 17:08:19 2015 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/MathSubstitutionsX86.java	Fri Mar 13 11:28:01 2015 +0100
@@ -46,12 +46,12 @@
     @MethodSubstitution(guard = MathGuard.class)
     public static double pow(double x, double y) {
         // If the second argument is positive or negative zero, then the result is 1.0.
-        if (y == 0) {
+        if (y == 0.0D) {
             return 1;
         }
 
         // If the second argument is 1.0, then the result is the same as the first argument.
-        if (y == 1) {
+        if (y == 1.0D) {
             return x;
         }
 
@@ -61,26 +61,25 @@
         }
 
         // If the first argument is NaN and the second argument is nonzero, then the result is NaN.
-        if (Double.isNaN(x) && y != 0) {
+        if (Double.isNaN(x) && y != 0.0D) {
             return Double.NaN;
         }
 
         // x**-1 = 1/x
-        if (y == -1) {
+        if (y == -1.0D) {
             return 1 / x;
         }
 
         // x**2 = x*x
-        if (y == 2) {
+        if (y == 2.0D) {
             return x * x;
         }
 
         // x**0.5 = sqrt(x)
-        if (y == 0.5 && x >= 0) {
+        if (y == 0.5D && x >= 0.0D) {
             return Math.sqrt(x);
         }
-
-        return pow(x, y);
+        return callDouble2(ARITHMETIC_POW, x, y);
     }
 
     // NOTE on snippets below:
@@ -94,7 +93,7 @@
         if (Math.abs(x) < PI_4) {
             return MathIntrinsicNode.compute(x, Operation.SIN);
         } else {
-            return callDouble(ARITHMETIC_SIN, x);
+            return callDouble1(ARITHMETIC_SIN, x);
         }
     }
 
@@ -103,7 +102,7 @@
         if (Math.abs(x) < PI_4) {
             return MathIntrinsicNode.compute(x, Operation.COS);
         } else {
-            return callDouble(ARITHMETIC_COS, x);
+            return callDouble1(ARITHMETIC_COS, x);
         }
     }
 
@@ -112,7 +111,7 @@
         if (Math.abs(x) < PI_4) {
             return MathIntrinsicNode.compute(x, Operation.TAN);
         } else {
-            return callDouble(ARITHMETIC_TAN, x);
+            return callDouble1(ARITHMETIC_TAN, x);
         }
     }
 
@@ -127,7 +126,11 @@
     public static final ForeignCallDescriptor ARITHMETIC_SIN = new ForeignCallDescriptor("arithmeticSin", double.class, double.class);
     public static final ForeignCallDescriptor ARITHMETIC_COS = new ForeignCallDescriptor("arithmeticCos", double.class, double.class);
     public static final ForeignCallDescriptor ARITHMETIC_TAN = new ForeignCallDescriptor("arithmeticTan", double.class, double.class);
+    public static final ForeignCallDescriptor ARITHMETIC_POW = new ForeignCallDescriptor("arithmeticPow", double.class, double.class, double.class);
 
     @NodeIntrinsic(value = ForeignCallNode.class, setStampFromReturnType = true)
-    public static native double callDouble(@ConstantNodeParameter ForeignCallDescriptor descriptor, double value);
+    private static native double callDouble1(@ConstantNodeParameter ForeignCallDescriptor descriptor, double value);
+
+    @NodeIntrinsic(value = ForeignCallNode.class, setStampFromReturnType = true)
+    private static native double callDouble2(@ConstantNodeParameter ForeignCallDescriptor descriptor, double a, double b);
 }
--- a/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/InstrumentationPartialEvaluationTest.java	Thu Mar 12 17:08:19 2015 +0100
+++ b/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/InstrumentationPartialEvaluationTest.java	Fri Mar 13 11:28:01 2015 +0100
@@ -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 17:08:19 2015 +0100
+++ b/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/instrument/InstrumentationTest.java	Fri Mar 13 11:28:01 2015 +0100
@@ -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"));
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/ASTInstrumentListener.java	Fri Mar 13 11:28:01 2015 +0100
@@ -0,0 +1,57 @@
+/*
+ * 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.*;
+
+/**
+ * A listener of Truffle AST runtime execution events that can collect information, examine the
+ * execution state at a particular node, and possibly intervene on behalf of an external tool.
+ */
+public interface ASTInstrumentListener {
+
+    /**
+     * Receive notification that an AST node's execute method is about to be called.
+     */
+    void enter(Probe probe, Node node, VirtualFrame vFrame);
+
+    /**
+     * Receive notification that an AST Node's {@code void}-valued execute method has just returned.
+     */
+    void returnVoid(Probe probe, Node node, VirtualFrame vFrame);
+
+    /**
+     * Receive notification that an AST Node's execute method has just returned a value (boxed if
+     * primitive).
+     */
+    void returnValue(Probe probe, Node node, VirtualFrame vFrame, Object result);
+
+    /**
+     * Receive notification that an AST Node's execute method has just thrown an exception.
+     */
+    void returnExceptional(Probe probe, Node node, VirtualFrame vFrame, Exception exception);
+
+}
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/Instrument.java	Thu Mar 12 17:08:19 2015 +0100
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/Instrument.java	Fri Mar 13 11:28:01 2015 +0100
@@ -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;
         }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/InstrumentListener.java	Fri Mar 13 11:28:01 2015 +0100
@@ -0,0 +1,54 @@
+/*
+ * 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;
+
+/**
+ * A listener of Truffle execution events that can collect information on behalf of an external
+ * tool. Contextual information about the source of the event, if not stored in the implementation
+ * of the listener, can be obtained via access to the {@link Probe} that generates the event.
+ */
+public interface InstrumentListener {
+
+    /**
+     * Receive notification that an AST node's execute method is about to be called.
+     */
+    void enter(Probe probe);
+
+    /**
+     * Receive notification that an AST Node's {@code void}-valued execute method has just returned.
+     */
+    void returnVoid(Probe probe);
+
+    /**
+     * Receive notification that an AST Node's execute method has just returned a value (boxed if
+     * primitive).
+     */
+    void returnValue(Probe probe, Object result);
+
+    /**
+     * Receive notification that an AST Node's execute method has just thrown an exception.
+     */
+    void returnExceptional(Probe probe, Exception exception);
+}
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/InstrumentationNode.java	Thu Mar 12 17:08:19 2015 +0100
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/InstrumentationNode.java	Fri Mar 13 11:28:01 2015 +0100
@@ -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 17:08:19 2015 +0100
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/Probe.java	Fri Mar 13 11:28:01 2015 +0100
@@ -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 17:08:19 2015 +0100
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/ProbeNode.java	Fri Mar 13 11:28:01 2015 +0100
@@ -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/instrument/TruffleEventListener.java	Thu Mar 12 17:08:19 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,57 +0,0 @@
-/*
- * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.truffle.api.instrument;
-
-import com.oracle.truffle.api.frame.*;
-import com.oracle.truffle.api.nodes.*;
-
-/**
- * A listener of Truffle AST runtime execution events that can collect information and possibly
- * intervene on behalf of an external tool.
- */
-public interface TruffleEventListener {
-
-    /**
-     * Receive notification that an AST node's execute method is about to be called.
-     */
-    void enter(Node node, VirtualFrame vFrame);
-
-    /**
-     * Receive notification that an AST Node's {@code void}-valued execute method has just returned.
-     */
-    void returnVoid(Node node, VirtualFrame vFrame);
-
-    /**
-     * Receive notification that an AST Node'sexecute method has just returned a value (boxed if
-     * primitive).
-     */
-    void returnValue(Node node, VirtualFrame vFrame, Object result);
-
-    /**
-     * Receive notification that an AST Node's execute method has just thrown an exception.
-     */
-    void returnExceptional(Node node, VirtualFrame vFrame, Exception exception);
-
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/DefaultASTInstrumentListener.java	Fri Mar 13 11:28:01 2015 +0100
@@ -0,0 +1,49 @@
+/*
+ * 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.impl;
+
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.instrument.*;
+import com.oracle.truffle.api.nodes.*;
+
+/**
+ * A listener for AST {@linkplain ASTInstrumentListener execution events} that provides a no-op
+ * implementation of every event.
+ */
+public class DefaultASTInstrumentListener implements ASTInstrumentListener {
+
+    public void enter(Probe probe, Node node, VirtualFrame vFrame) {
+    }
+
+    public void returnVoid(Probe probe, Node node, VirtualFrame vFrame) {
+    }
+
+    public void returnValue(Probe probe, Node node, VirtualFrame vFrame, Object result) {
+    }
+
+    public void returnExceptional(Probe probe, Node node, VirtualFrame vFrame, Exception exception) {
+    }
+
+}
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/DefaultEventListener.java	Thu Mar 12 17:08:19 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,49 +0,0 @@
-/*
- * 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
- * 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.impl;
-
-import com.oracle.truffle.api.frame.*;
-import com.oracle.truffle.api.instrument.*;
-import com.oracle.truffle.api.nodes.*;
-
-/**
- * A listener for AST {@linkplain TruffleEventListener execution events} that provides a no-op
- * implementation of every event.
- */
-public class DefaultEventListener implements TruffleEventListener {
-
-    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) {
-    }
-
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/DefaultInstrumentListener.java	Fri Mar 13 11:28:01 2015 +0100
@@ -0,0 +1,45 @@
+/*
+ * 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.impl;
+
+import com.oracle.truffle.api.instrument.*;
+
+/**
+ * A listener for Truffle execution events that provides a no-op implementation of every event.
+ */
+public class DefaultInstrumentListener implements InstrumentListener {
+
+    public void enter(Probe probe) {
+    }
+
+    public void returnVoid(Probe probe) {
+    }
+
+    public void returnValue(Probe probe, Object result) {
+    }
+
+    public void returnExceptional(Probe probe, Exception exception) {
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/SimpleASTInstrumentListener.java	Fri Mar 13 11:28:01 2015 +0100
@@ -0,0 +1,67 @@
+/*
+ * 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.impl;
+
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.instrument.*;
+import com.oracle.truffle.api.nodes.*;
+
+/**
+ * An abstract listener for AST {@linkplain ASTInstrumentListener execution events} that ignores
+ * return values and supports handling all events by overriding only two methods:
+ * <ul>
+ * <li>{@link #enter(Probe, Node, VirtualFrame)}, and</li>
+ * <li>{@link #returnAny(Probe, Node, VirtualFrame)}.</li>
+ * </ul>
+ */
+public abstract class SimpleASTInstrumentListener implements ASTInstrumentListener {
+
+    public void enter(Probe probe, Node node, VirtualFrame vFrame) {
+    }
+
+    /**
+     * Receive notification that one of an AST Node's execute methods has just returned by any
+     * means: with or without a return value (ignored) or via exception (ignored).
+     *
+     * @param probe where the event originated
+     * @param node specific node of the event
+     * @param vFrame
+     */
+    protected void returnAny(Probe probe, Node node, VirtualFrame vFrame) {
+    }
+
+    public final void returnVoid(Probe probe, Node node, VirtualFrame vFrame) {
+        returnAny(probe, node, vFrame);
+    }
+
+    public final void returnValue(Probe probe, Node node, VirtualFrame vFrame, Object result) {
+        returnAny(probe, node, vFrame);
+    }
+
+    public final void returnExceptional(Probe probe, Node node, VirtualFrame vFrame, Exception e) {
+        returnAny(probe, node, vFrame);
+    }
+
+}
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/SimpleEventListener.java	Thu Mar 12 17:08:19 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,66 +0,0 @@
-/*
- * 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
- * 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.impl;
-
-import com.oracle.truffle.api.frame.*;
-import com.oracle.truffle.api.instrument.*;
-import com.oracle.truffle.api.nodes.*;
-
-/**
- * An abstract listener for AST {@linkplain TruffleEventListener execution events} that ignores
- * return values and supports handling all events by overriding only two methods:
- * <ul>
- * <li>{@link #enter(Node, VirtualFrame)}, and</li>
- * <li>{@link #returnAny(Node, VirtualFrame)}.</li>
- * </ul>
- */
-public abstract class SimpleEventListener implements TruffleEventListener {
-
-    public void enter(Node node, VirtualFrame vFrame) {
-    }
-
-    /**
-     * Receive notification that one of an AST Node's execute methods has just returned by any
-     * means: with or without a return value (ignored) or via exception (ignored).
-     *
-     * @param node
-     * @param vFrame
-     */
-    public void returnAny(Node node, VirtualFrame vFrame) {
-    }
-
-    public final void returnVoid(Node node, VirtualFrame vFrame) {
-        returnAny(node, vFrame);
-    }
-
-    public final void returnValue(Node node, VirtualFrame vFrame, Object result) {
-        returnAny(node, vFrame);
-    }
-
-    public final void returnExceptional(Node node, VirtualFrame vFrame, Exception e) {
-        returnAny(node, vFrame);
-    }
-
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/SimpleInstrumentListener.java	Fri Mar 13 11:28:01 2015 +0100
@@ -0,0 +1,63 @@
+/*
+ * 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
+ * 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.impl;
+
+import com.oracle.truffle.api.instrument.*;
+
+/**
+ * An abstract listener for Truffle {@linkplain InstrumentListener execution events} that ignores
+ * return values and supports handling all events by overriding only two methods:
+ * <ul>
+ * <li>{@link #enter(Probe)}, and</li>
+ * <li>{@link #returnAny(Probe)}.</li>
+ * </ul>
+ */
+public abstract class SimpleInstrumentListener implements InstrumentListener {
+
+    public void enter(Probe probe) {
+    }
+
+    /**
+     * Receive notification that an execute method has just returned by any means: with or without a
+     * return value (ignored) or via exception (ignored).
+     *
+     * @param probe
+     */
+    protected void returnAny(Probe probe) {
+    }
+
+    public final void returnVoid(Probe probe) {
+        returnAny(probe);
+    }
+
+    public final void returnValue(Probe probe, Object result) {
+        returnAny(probe);
+    }
+
+    public final void returnExceptional(Probe probe, Exception e) {
+        returnAny(probe);
+    }
+
+}
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/Node.java	Thu Mar 12 17:08:19 2015 +0100
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/Node.java	Fri Mar 13 11:28:01 2015 +0100
@@ -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 17:08:19 2015 +0100
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/tools/CoverageTracker.java	Fri Mar 13 11:28:01 2015 +0100
@@ -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 17:08:19 2015 +0100
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/tools/NodeExecCounter.java	Fri Mar 13 11:28:01 2015 +0100
@@ -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 17:08:19 2015 +0100
+++ b/graal/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/instrument/SLInstrumentTestRunner.java	Fri Mar 13 11:28:01 2015 +0100
@@ -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);
         }
     }
--- a/src/share/vm/opto/compile.cpp	Thu Mar 12 17:08:19 2015 +0100
+++ b/src/share/vm/opto/compile.cpp	Fri Mar 13 11:28:01 2015 +0100
@@ -2184,6 +2184,8 @@
       if (failing())  return;
     }
   }
+  // Ensure that major progress is now clear
+  C->clear_major_progress();
 
   {
     // Verify that all previous optimizations produced a valid graph