changeset 22003:5bc7f7b867ab

Making debugger always on for each TruffleVM execution. Introducing EventConsumer to process such debugger events. Requesting each RootNode to be associated with a TruffleLanguage, so debugger can find out proper context for each Node where executions gets suspended.
author Jaroslav Tulach <jaroslav.tulach@oracle.com>
date Sat, 18 Jul 2015 18:03:36 +0200
parents 324997830dc9
children 11e0412c5b0e
files mx.truffle/suite.py truffle/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/ArrayTest.java truffle/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/TestHelper.java truffle/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/TestingLanguage.java truffle/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/TypeSystemTest.java truffle/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/examples/ExampleNode.java truffle/com.oracle.truffle.api.dsl/src/com/oracle/truffle/api/dsl/Specialization.java truffle/com.oracle.truffle.api.dsl/src/com/oracle/truffle/api/dsl/TypeSystem.java truffle/com.oracle.truffle.api.interop/src/com/oracle/truffle/api/interop/impl/SymbolInvokerImpl.java truffle/com.oracle.truffle.api.interop/src/com/oracle/truffle/api/interop/package-info.java truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/ArgumentsTest.java truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/CallTest.java truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/ChildNodeTest.java truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/ChildrenNodesTest.java truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/FinalFieldTest.java truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/FrameSlotTypeSpecializationTest.java truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/FrameTest.java truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/InterfaceChildFieldTest.java truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/ReplaceTest.java truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/ReturnTypeSpecializationTest.java truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/RootNodeTest.java truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/TestingLanguage.java truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/ThreadSafetyTest.java truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/TruffleRuntimeTest.java truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/instrument/InstrumentationTestNodes.java truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/nodes/NodeUtilTest.java truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/nodes/SafeReplaceTest.java truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/package-info.java truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/debug/Breakpoint.java truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/debug/DebugSupportProvider.java truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/debug/Debugger.java truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/debug/ExecutionEvent.java truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/debug/LineBreakpoint.java truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/debug/LineBreakpointFactory.java truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/debug/LineToProbesMap.java truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/debug/SuspendedEvent.java truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/debug/TagBreakpoint.java truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/debug/TagBreakpointFactory.java truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/package-info.java truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/Accessor.java truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/SymbolInvoker.java truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/Instrument.java truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/Probe.java truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/ProbeNode.java truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/package-info.java truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/GraphPrintVisitor.java truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/Node.java truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/RootNode.java truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/package-info.java truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/package-info.java truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/source/package-info.java truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/vm/EventConsumer.java truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/vm/TruffleVM.java truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/vm/package-info.java truffle/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/expression/DSLExpressionResolver.java truffle/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/NodeGenFactory.java truffle/com.oracle.truffle.object/src/com/oracle/truffle/object/debug/ShapeProfiler.java truffle/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/instrument/SLInstrumentTestRunner.java truffle/com.oracle.truffle.sl.tools/src/com/oracle/truffle/sl/tools/debug/SLREPLHandler.java truffle/com.oracle.truffle.sl.tools/src/com/oracle/truffle/sl/tools/debug/SLREPLServer.java truffle/com.oracle.truffle.sl/src/com/oracle/truffle/sl/SLLanguage.java truffle/com.oracle.truffle.sl/src/com/oracle/truffle/sl/factory/SLContextFactory.java truffle/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/SLRootNode.java truffle/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/access/SLReadPropertyCacheNode.java truffle/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/access/SLWritePropertyCacheNode.java truffle/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/call/SLDispatchNode.java truffle/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLReturnNode.java truffle/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/instrument/SLDefaultVisualizer.java truffle/com.oracle.truffle.sl/src/com/oracle/truffle/sl/parser/SLNodeFactory.java truffle/com.oracle.truffle.sl/src/com/oracle/truffle/sl/runtime/SLContext.java truffle/com.oracle.truffle.sl/src/com/oracle/truffle/sl/runtime/SLFunctionForeignAccess.java truffle/com.oracle.truffle.tck/src/com/oracle/truffle/tck/MaxMinObject.java truffle/com.oracle.truffle.tools.debug.engine/src/com/oracle/truffle/tools/debug/engine/Breakpoint.java truffle/com.oracle.truffle.tools.debug.engine/src/com/oracle/truffle/tools/debug/engine/DebugClient.java truffle/com.oracle.truffle.tools.debug.engine/src/com/oracle/truffle/tools/debug/engine/DebugEngine.java truffle/com.oracle.truffle.tools.debug.engine/src/com/oracle/truffle/tools/debug/engine/DebugException.java truffle/com.oracle.truffle.tools.debug.engine/src/com/oracle/truffle/tools/debug/engine/DebugExecutionSupport.java truffle/com.oracle.truffle.tools.debug.engine/src/com/oracle/truffle/tools/debug/engine/FrameDebugDescription.java truffle/com.oracle.truffle.tools.debug.engine/src/com/oracle/truffle/tools/debug/engine/LineBreakpoint.java truffle/com.oracle.truffle.tools.debug.engine/src/com/oracle/truffle/tools/debug/engine/LineBreakpointFactory.java truffle/com.oracle.truffle.tools.debug.engine/src/com/oracle/truffle/tools/debug/engine/TagBreakpoint.java truffle/com.oracle.truffle.tools.debug.engine/src/com/oracle/truffle/tools/debug/engine/TagBreakpointFactory.java truffle/com.oracle.truffle.tools.debug.engine/src/com/oracle/truffle/tools/debug/engine/package-info.java truffle/com.oracle.truffle.tools.debug.shell/src/com/oracle/truffle/tools/debug/shell/REPLMessage.java truffle/com.oracle.truffle.tools.debug.shell/src/com/oracle/truffle/tools/debug/shell/REPLServer.java truffle/com.oracle.truffle.tools.debug.shell/src/com/oracle/truffle/tools/debug/shell/client/SimpleREPLClient.java truffle/com.oracle.truffle.tools.debug.shell/src/com/oracle/truffle/tools/debug/shell/package-info.java truffle/com.oracle.truffle.tools.debug.shell/src/com/oracle/truffle/tools/debug/shell/server/FrameDebugDescription.java truffle/com.oracle.truffle.tools.debug.shell/src/com/oracle/truffle/tools/debug/shell/server/REPLHandler.java truffle/com.oracle.truffle.tools.debug.shell/src/com/oracle/truffle/tools/debug/shell/server/REPLServerContext.java truffle/com.oracle.truffle.tools.test/src/com/oracle/truffle/tools/test/TestNodes.java
diffstat 91 files changed, 3496 insertions(+), 2953 deletions(-) [+]
line wrap: on
line diff
--- a/mx.truffle/suite.py	Thu Jul 16 19:11:31 2015 +0200
+++ b/mx.truffle/suite.py	Sat Jul 18 18:03:36 2015 +0200
@@ -269,19 +269,10 @@
       "workingSets" : "Truffle,Tools",
     },
 
-    "com.oracle.truffle.tools.debug.engine" : {
-      "subDir" : "truffle",
-      "sourceDirs" : ["src"],
-      "dependencies" : ["com.oracle.truffle.tools"],
-      "checkstyle" : "com.oracle.truffle.api",
-      "javaCompliance" : "1.7",
-      "workingSets" : "Truffle,Tools",
-    },
-
     "com.oracle.truffle.tools.debug.shell" : {
       "subDir" : "truffle",
       "sourceDirs" : ["src"],
-      "dependencies" : ["com.oracle.truffle.tools.debug.engine",
+      "dependencies" : ["com.oracle.truffle.tools",
                         "JLINE"],
       "checkstyle" : "com.oracle.truffle.api",
       "javaCompliance" : "1.7",
@@ -306,7 +297,7 @@
       "sourceDirs" : ["src"],
       "dependencies" : [
         "com.oracle.truffle.tck",
-        "com.oracle.truffle.sl"
+        "com.oracle.truffle.sl",
       ],
       "checkstyle" : "com.oracle.truffle.sl",
       "javaCompliance" : "1.7",
--- a/truffle/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/ArrayTest.java	Thu Jul 16 19:11:31 2015 +0200
+++ b/truffle/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/ArrayTest.java	Sat Jul 18 18:03:36 2015 +0200
@@ -35,7 +35,7 @@
     @Test
     public void testNode1() {
         final TestNode1 node = TestNode1NodeGen.create(null);
-        RootNode root = new RootNode() {
+        RootNode root = new RootNode(TestingLanguage.class, null, null) {
             @Child TestNode1 test = node;
 
             @Override
--- a/truffle/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/TestHelper.java	Thu Jul 16 19:11:31 2015 +0200
+++ b/truffle/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/TestHelper.java	Sat Jul 18 18:03:36 2015 +0200
@@ -42,7 +42,7 @@
 
     // make nodes replacable
     public static <T extends Node> T createRoot(final T node) {
-        new RootNode() {
+        new RootNode(TestingLanguage.class, null, null) {
             @Child T child = node;
 
             @Override
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/truffle/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/TestingLanguage.java	Sat Jul 18 18:03:36 2015 +0200
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.api.dsl.test;
+
+import com.oracle.truffle.api.TruffleLanguage;
+import com.oracle.truffle.api.debug.DebugSupportProvider;
+import com.oracle.truffle.api.instrument.ToolSupportProvider;
+import com.oracle.truffle.api.source.Source;
+import java.io.IOException;
+
+public final class TestingLanguage extends TruffleLanguage {
+    public static final TruffleLanguage INSTANCE = new TestingLanguage();
+
+    private TestingLanguage() {
+        super(null);
+    }
+
+    @Override
+    protected Object eval(Source code) throws IOException {
+        throw new IOException();
+    }
+
+    @Override
+    protected Object findExportedSymbol(String globalName, boolean onlyExplicit) {
+        return null;
+    }
+
+    @Override
+    protected Object getLanguageGlobal() {
+        return null;
+    }
+
+    @Override
+    protected boolean isObjectOfLanguage(Object object) {
+        return false;
+    }
+
+    @Override
+    protected ToolSupportProvider getToolSupport() {
+        return null;
+    }
+
+    @Override
+    protected DebugSupportProvider getDebugSupport() {
+        return null;
+    }
+
+}
--- a/truffle/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/TypeSystemTest.java	Thu Jul 16 19:11:31 2015 +0200
+++ b/truffle/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/TypeSystemTest.java	Sat Jul 18 18:03:36 2015 +0200
@@ -148,7 +148,7 @@
         @Child private E node;
 
         public TestRootNode(E node) {
-            super(null);
+            super(TestingLanguage.class, null, null);
             this.node = node;
         }
 
--- a/truffle/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/examples/ExampleNode.java	Thu Jul 16 19:11:31 2015 +0200
+++ b/truffle/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/examples/ExampleNode.java	Sat Jul 18 18:03:36 2015 +0200
@@ -25,6 +25,7 @@
 import com.oracle.truffle.api.*;
 import com.oracle.truffle.api.dsl.*;
 import com.oracle.truffle.api.dsl.internal.*;
+import com.oracle.truffle.api.dsl.test.TestingLanguage;
 import com.oracle.truffle.api.frame.*;
 import com.oracle.truffle.api.nodes.*;
 
@@ -68,6 +69,7 @@
         @Child ExampleNode child;
 
         public ExampleRootNode(ExampleNode child) {
+            super(TestingLanguage.class, null, null);
             this.child = child;
         }
 
@@ -105,6 +107,7 @@
         private final int argumentIndex;
 
         public DummyCallRootNode(int argumentIndex) {
+            super(TestingLanguage.class, null, null);
             this.argumentIndex = argumentIndex;
         }
 
--- a/truffle/com.oracle.truffle.api.dsl/src/com/oracle/truffle/api/dsl/Specialization.java	Thu Jul 16 19:11:31 2015 +0200
+++ b/truffle/com.oracle.truffle.api.dsl/src/com/oracle/truffle/api/dsl/Specialization.java	Sat Jul 18 18:03:36 2015 +0200
@@ -244,12 +244,9 @@
      * <b>Example usage:</b>
      *
      * <pre>
-     * static boolean acceptOperand(int operand) {
-     *     assert operand <= 42;
-     *     return operand & 1 == 1;
-     * }
-     * &#064;Specialization(guards = {"operand <= 42", "acceptOperand(operand)"})
-     * void doSpecialization(int operand) {...}
+     * static boolean acceptOperand(int operand) { assert operand <= 42; return operand & 1 ==
+     * 1; } &#064;Specialization(guards = {"operand <= 42", "acceptOperand(operand)"}) void
+     * doSpecialization(int operand) {...}
      * </pre>
      *
      * </p>
@@ -287,16 +284,11 @@
      * <b>Example usage:</b>
      *
      * <pre>
-     * static abstract class DynamicObject() {
-     *      abstract Shape getShape();
-     *      ...
-     * }
-     * static abstract class Shape() {
-     *      abstract Assumption getUnmodifiedAssuption();
-     *      ...
-     * }
-     * &#064;Specialization(guards = "operand.getShape() == cachedShape", assumptions = "cachedShape.getUnmodifiedAssumption()")
-     * void doAssumeUnmodifiedShape(DynamicObject operand, @Cached("operand.getShape()") Shape cachedShape) {...}
+     * static abstract class DynamicObject() { abstract Shape getShape(); ... } static
+     * abstract class Shape() { abstract Assumption getUnmodifiedAssuption(); ... }
+     * &#064;Specialization(guards = "operand.getShape() == cachedShape", assumptions =
+     * "cachedShape.getUnmodifiedAssumption()") void doAssumeUnmodifiedShape(DynamicObject
+     * operand, @Cached("operand.getShape()") Shape cachedShape) {...}
      * </pre>
      *
      * </p>
@@ -335,11 +327,10 @@
      * <b>Example usage:</b>
      *
      * <pre>
-     * static int getCacheLimit() {
-     *     return Integer.parseInt(System.getProperty("language.cacheLimit"));
-     * }
-     * &#064;Specialization(guards = "operand == cachedOperand", limit = "getCacheLimit()")
-     * void doCached(Object operand, @Cached("operand") Object cachedOperand) {...}
+     * static int getCacheLimit() { return
+     * Integer.parseInt(System.getProperty("language.cacheLimit")); } &#064;Specialization(guards =
+     * "operand == cachedOperand", limit = "getCacheLimit()") void doCached(Object
+     * operand, @Cached("operand") Object cachedOperand) {...}
      * </pre>
      *
      * </p>
--- a/truffle/com.oracle.truffle.api.dsl/src/com/oracle/truffle/api/dsl/TypeSystem.java	Thu Jul 16 19:11:31 2015 +0200
+++ b/truffle/com.oracle.truffle.api.dsl/src/com/oracle/truffle/api/dsl/TypeSystem.java	Sat Jul 18 18:03:36 2015 +0200
@@ -61,12 +61,12 @@
  *
  * {@literal @}TypeSystem(types = {boolean.class, int.class, double.class})
  * public abstract class ExampleTypeSystem {
- *
+ * 
  *     {@literal @}TypeCheck
  *     public boolean isInteger(Object value) {
  *         return value instanceof Integer || value instanceof Double;
  *     }
- *
+ * 
  *     {@literal @}TypeCast
  *     public double asInteger(Object value) {
  *         return ((Number)value).doubleValue();
--- a/truffle/com.oracle.truffle.api.interop/src/com/oracle/truffle/api/interop/impl/SymbolInvokerImpl.java	Thu Jul 16 19:11:31 2015 +0200
+++ b/truffle/com.oracle.truffle.api.interop/src/com/oracle/truffle/api/interop/impl/SymbolInvokerImpl.java	Sat Jul 18 18:03:36 2015 +0200
@@ -38,7 +38,7 @@
     static final FrameDescriptor UNUSED_FRAMEDESCRIPTOR = new FrameDescriptor();
 
     @Override
-    protected Object invoke(Object symbol, Object... arr) throws IOException {
+    protected Object invoke(TruffleLanguage lang, Object symbol, Object... arr) throws IOException {
         if (symbol instanceof String) {
             return symbol;
         }
@@ -49,7 +49,7 @@
             return symbol;
         }
         Node executeMain = Message.createExecute(arr.length).createNode();
-        CallTarget callTarget = Truffle.getRuntime().createCallTarget(new TemporaryRoot(executeMain, (TruffleObject) symbol, arr));
+        CallTarget callTarget = Truffle.getRuntime().createCallTarget(new TemporaryRoot(lang, executeMain, (TruffleObject) symbol, arr));
         VirtualFrame frame = Truffle.getRuntime().createVirtualFrame(arr, UNUSED_FRAMEDESCRIPTOR);
         Object ret = callTarget.call(frame);
         if (ret instanceof TruffleObject) {
@@ -57,20 +57,20 @@
             Object isBoxedResult;
             try {
                 Node isBoxed = Message.IS_BOXED.createNode();
-                CallTarget isBoxedTarget = Truffle.getRuntime().createCallTarget(new TemporaryRoot(isBoxed, tret));
+                CallTarget isBoxedTarget = Truffle.getRuntime().createCallTarget(new TemporaryRoot(lang, isBoxed, tret));
                 isBoxedResult = isBoxedTarget.call(frame);
             } catch (IllegalArgumentException ex) {
                 isBoxedResult = false;
             }
             if (Boolean.TRUE.equals(isBoxedResult)) {
                 Node unbox = Message.UNBOX.createNode();
-                CallTarget unboxTarget = Truffle.getRuntime().createCallTarget(new TemporaryRoot(unbox, tret));
+                CallTarget unboxTarget = Truffle.getRuntime().createCallTarget(new TemporaryRoot(lang, unbox, tret));
                 Object unboxResult = unboxTarget.call(frame);
                 return unboxResult;
             } else {
                 try {
                     Node isNull = Message.IS_NULL.createNode();
-                    CallTarget isNullTarget = Truffle.getRuntime().createCallTarget(new TemporaryRoot(isNull, tret));
+                    CallTarget isNullTarget = Truffle.getRuntime().createCallTarget(new TemporaryRoot(lang, isNull, tret));
                     Object isNullResult = isNullTarget.call(frame);
                     if (Boolean.TRUE.equals(isNullResult)) {
                         return null;
@@ -88,7 +88,8 @@
         private final TruffleObject function;
         private final Object[] args;
 
-        public TemporaryRoot(Node foreignAccess, TruffleObject function, Object... args) {
+        public TemporaryRoot(TruffleLanguage lang, Node foreignAccess, TruffleObject function, Object... args) {
+            super(lang.getClass(), null, null);
             this.foreignAccess = foreignAccess;
             this.function = function;
             this.args = args;
--- a/truffle/com.oracle.truffle.api.interop/src/com/oracle/truffle/api/interop/package-info.java	Thu Jul 16 19:11:31 2015 +0200
+++ b/truffle/com.oracle.truffle.api.interop/src/com/oracle/truffle/api/interop/package-info.java	Sat Jul 18 18:03:36 2015 +0200
@@ -1,26 +1,23 @@
 /*
- * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ * Copyright (c) 2014, 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 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
+ * 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.
+ * 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.
+ * 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.
  */
 
 /**
@@ -28,15 +25,15 @@
  * {@link com.oracle.truffle.api.TruffleLanguage Truffle languages}.
  * <p>
  * Languages can exchange primitive Java type wrapper objects (e.g., {@link java.lang.Integer},
- * {@link java.lang.Double}, {@link java.lang.String}, etc) as well as any type
- * implementing {@link com.oracle.truffle.api.interop.TruffleObject}. Foreign objects are
- * precisely those implementing {@link com.oracle.truffle.api.interop.TruffleObject}.
+ * {@link java.lang.Double}, {@link java.lang.String}, etc) as well as any type implementing
+ * {@link com.oracle.truffle.api.interop.TruffleObject}. Foreign objects are precisely those
+ * implementing {@link com.oracle.truffle.api.interop.TruffleObject}.
  * <p>
- * To use a {@link com.oracle.truffle.api.interop.TruffleObject} from a different language,
- * you need to ask the language to build appropriate AST for a given
+ * To use a {@link com.oracle.truffle.api.interop.TruffleObject} from a different language, you need
+ * to ask the language to build appropriate AST for a given
  * {@link com.oracle.truffle.api.interop.Message} with
- * {@link com.oracle.truffle.api.interop.Message#createNode}. The message can then
- * be executed with {@link com.oracle.truffle.api.interop.ForeignAccess#execute}.
+ * {@link com.oracle.truffle.api.interop.Message#createNode}. The message can then be executed with
+ * {@link com.oracle.truffle.api.interop.ForeignAccess#execute}.
  */
 package com.oracle.truffle.api.interop;
 
--- a/truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/ArgumentsTest.java	Thu Jul 16 19:11:31 2015 +0200
+++ b/truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/ArgumentsTest.java	Sat Jul 18 18:03:36 2015 +0200
@@ -65,7 +65,7 @@
         @Children private final TestArgumentNode[] children;
 
         TestRootNode(TestArgumentNode[] children) {
-            super(null);
+            super(TestingLanguage.class, null, null);
             this.children = children;
         }
 
--- a/truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/CallTest.java	Thu Jul 16 19:11:31 2015 +0200
+++ b/truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/CallTest.java	Sat Jul 18 18:03:36 2015 +0200
@@ -60,7 +60,7 @@
         private final CallTarget secondTarget;
 
         DualCallNode(CallTarget firstTarget, CallTarget secondTarget) {
-            super(null);
+            super(TestingLanguage.class, null, null);
             this.firstTarget = firstTarget;
             this.secondTarget = secondTarget;
         }
@@ -76,7 +76,7 @@
         private final int value;
 
         public ConstantRootNode(int value) {
-            super(null);
+            super(TestingLanguage.class, null, null);
             this.value = value;
         }
 
--- a/truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/ChildNodeTest.java	Thu Jul 16 19:11:31 2015 +0200
+++ b/truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/ChildNodeTest.java	Sat Jul 18 18:03:36 2015 +0200
@@ -76,7 +76,7 @@
         @Child private TestChildNode right;
 
         public TestRootNode(TestChildNode left, TestChildNode right) {
-            super(null);
+            super(TestingLanguage.class, null, null);
             this.left = left;
             this.right = right;
         }
--- a/truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/ChildrenNodesTest.java	Thu Jul 16 19:11:31 2015 +0200
+++ b/truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/ChildrenNodesTest.java	Sat Jul 18 18:03:36 2015 +0200
@@ -71,7 +71,7 @@
         @Children private final TestChildNode[] children;
 
         public TestRootNode(TestChildNode[] children) {
-            super(null);
+            super(TestingLanguage.class, null, null);
             this.children = children;
         }
 
--- a/truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/FinalFieldTest.java	Thu Jul 16 19:11:31 2015 +0200
+++ b/truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/FinalFieldTest.java	Sat Jul 18 18:03:36 2015 +0200
@@ -65,7 +65,7 @@
         @Children private final TestChildNode[] children;
 
         public TestRootNode(TestChildNode[] children) {
-            super(null);
+            super(TestingLanguage.class, null, null);
             this.children = children;
         }
 
--- a/truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/FrameSlotTypeSpecializationTest.java	Thu Jul 16 19:11:31 2015 +0200
+++ b/truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/FrameSlotTypeSpecializationTest.java	Sat Jul 18 18:03:36 2015 +0200
@@ -63,7 +63,7 @@
         @Child TestChildNode right;
 
         public TestRootNode(FrameDescriptor descriptor, TestChildNode left, TestChildNode right) {
-            super(null, descriptor);
+            super(TestingLanguage.class, null, descriptor);
             this.left = left;
             this.right = right;
         }
--- a/truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/FrameTest.java	Thu Jul 16 19:11:31 2015 +0200
+++ b/truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/FrameTest.java	Sat Jul 18 18:03:36 2015 +0200
@@ -87,7 +87,7 @@
         @Child TestChildNode right;
 
         public TestRootNode(FrameDescriptor descriptor, TestChildNode left, TestChildNode right) {
-            super(null, descriptor);
+            super(TestingLanguage.class, null, descriptor);
             this.left = left;
             this.right = right;
         }
--- a/truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/InterfaceChildFieldTest.java	Thu Jul 16 19:11:31 2015 +0200
+++ b/truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/InterfaceChildFieldTest.java	Sat Jul 18 18:03:36 2015 +0200
@@ -81,7 +81,7 @@
         @Child private TestChildInterface child;
 
         public TestRootNode(TestChildInterface child) {
-            super(null);
+            super(TestingLanguage.class, null, null);
             this.child = child;
         }
 
--- a/truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/ReplaceTest.java	Thu Jul 16 19:11:31 2015 +0200
+++ b/truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/ReplaceTest.java	Sat Jul 18 18:03:36 2015 +0200
@@ -84,7 +84,7 @@
         @Children private final ValueNode[] children;
 
         public TestRootNode(ValueNode[] children) {
-            super(null);
+            super(TestingLanguage.class, null, null);
             this.children = children;
         }
 
--- a/truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/ReturnTypeSpecializationTest.java	Thu Jul 16 19:11:31 2015 +0200
+++ b/truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/ReturnTypeSpecializationTest.java	Sat Jul 18 18:03:36 2015 +0200
@@ -62,7 +62,7 @@
         @Child TestChildNode right;
 
         public TestRootNode(FrameDescriptor descriptor, TestChildNode left, TestChildNode right) {
-            super(null, descriptor);
+            super(TestingLanguage.class, null, descriptor);
             this.left = left;
             this.right = right;
         }
--- a/truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/RootNodeTest.java	Thu Jul 16 19:11:31 2015 +0200
+++ b/truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/RootNodeTest.java	Sat Jul 18 18:03:36 2015 +0200
@@ -60,7 +60,7 @@
     class TestRootNode extends RootNode {
 
         public TestRootNode() {
-            super(null);
+            super(TestingLanguage.class, null, null);
         }
 
         @Override
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/TestingLanguage.java	Sat Jul 18 18:03:36 2015 +0200
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.api.test;
+
+import com.oracle.truffle.api.TruffleLanguage;
+import com.oracle.truffle.api.debug.DebugSupportProvider;
+import com.oracle.truffle.api.instrument.ToolSupportProvider;
+import com.oracle.truffle.api.source.Source;
+import java.io.IOException;
+
+public final class TestingLanguage extends TruffleLanguage {
+    public static final TruffleLanguage INSTANCE = new TestingLanguage();
+
+    private TestingLanguage() {
+        super(null);
+    }
+
+    @Override
+    protected Object eval(Source code) throws IOException {
+        throw new IOException();
+    }
+
+    @Override
+    protected Object findExportedSymbol(String globalName, boolean onlyExplicit) {
+        return null;
+    }
+
+    @Override
+    protected Object getLanguageGlobal() {
+        return null;
+    }
+
+    @Override
+    protected boolean isObjectOfLanguage(Object object) {
+        return false;
+    }
+
+    @Override
+    protected ToolSupportProvider getToolSupport() {
+        return null;
+    }
+
+    @Override
+    protected DebugSupportProvider getDebugSupport() {
+        return null;
+    }
+
+}
--- a/truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/ThreadSafetyTest.java	Thu Jul 16 19:11:31 2015 +0200
+++ b/truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/ThreadSafetyTest.java	Sat Jul 18 18:03:36 2015 +0200
@@ -84,7 +84,7 @@
         @Child private ValueNode child;
 
         public TestRootNode(ValueNode child) {
-            super(null);
+            super(TestingLanguage.class, null, null);
             this.child = child;
         }
 
--- a/truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/TruffleRuntimeTest.java	Thu Jul 16 19:11:31 2015 +0200
+++ b/truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/TruffleRuntimeTest.java	Sat Jul 18 18:03:36 2015 +0200
@@ -59,7 +59,7 @@
     }
 
     private static RootNode createTestRootNode() {
-        return new RootNode() {
+        return new RootNode(TestingLanguage.class, null, null) {
             @Override
             public Object execute(VirtualFrame frame) {
                 return 42;
--- a/truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/instrument/InstrumentationTestNodes.java	Thu Jul 16 19:11:31 2015 +0200
+++ b/truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/instrument/InstrumentationTestNodes.java	Sat Jul 18 18:03:36 2015 +0200
@@ -27,6 +27,7 @@
 import com.oracle.truffle.api.instrument.*;
 import com.oracle.truffle.api.instrument.ProbeNode.WrapperNode;
 import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.api.test.TestingLanguage;
 
 /**
  * Tests instrumentation where a client can attach a node that gets attached into the AST.
@@ -147,7 +148,7 @@
          * tests run in the same environment.
          */
         public TestRootNode(TestLanguageNode body) {
-            super(null);
+            super(TestingLanguage.class, null, null);
             this.body = body;
         }
 
--- a/truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/nodes/NodeUtilTest.java	Thu Jul 16 19:11:31 2015 +0200
+++ b/truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/nodes/NodeUtilTest.java	Sat Jul 18 18:03:36 2015 +0200
@@ -31,6 +31,7 @@
 
 import com.oracle.truffle.api.frame.*;
 import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.api.test.TestingLanguage;
 
 public class NodeUtilTest {
 
@@ -84,6 +85,10 @@
 
         private int visited;
 
+        public TestRootNode() {
+            super(TestingLanguage.class, null, null);
+        }
+
         @Override
         public Object execute(VirtualFrame frame) {
             return null;
--- a/truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/nodes/SafeReplaceTest.java	Thu Jul 16 19:11:31 2015 +0200
+++ b/truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/nodes/SafeReplaceTest.java	Sat Jul 18 18:03:36 2015 +0200
@@ -28,6 +28,7 @@
 
 import com.oracle.truffle.api.frame.*;
 import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.api.test.TestingLanguage;
 
 /**
  * Tests optional method for ensuring that a node replacement is type safe. Ordinary node
@@ -81,6 +82,10 @@
 
         private int executed;
 
+        public TestRootNode() {
+            super(TestingLanguage.class, null, null);
+        }
+
         @Override
         public Object execute(VirtualFrame frame) {
             executed++;
--- a/truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/package-info.java	Thu Jul 16 19:11:31 2015 +0200
+++ b/truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/package-info.java	Sat Jul 18 18:03:36 2015 +0200
@@ -1,50 +1,62 @@
 /*
- * Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ * Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved. DO NOT ALTER OR
+ * REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
+ * This code is free software; you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License version 2 only, as published by the Free Software Foundation.
  *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
+ * 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.
+ * 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.
+ * 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.
  */
 /**
- * <p>This package contains basic tests of the Truffle API and serves at the same
- * time as an introduction to the Truffle API for language implementors. Every test gives an example on how to use the construct explained in the class description.</p>
+ * <p>
+ * This package contains basic tests of the Truffle API and serves at the same time as an
+ * introduction to the Truffle API for language implementors. Every test gives an example on how to
+ * use the construct explained in the class description.
+ * </p>
  *
  * <p>
- * Truffle is a language implementation framework. A guest language method is represented as a tree of executable nodes.
- * The framework provides mechanisms for those trees to call each other. Additionally it contains dedicated data structures for storing data local to a tree invocation.
+ * Truffle is a language implementation framework. A guest language method is represented as a tree
+ * of executable nodes. The framework provides mechanisms for those trees to call each other.
+ * Additionally it contains dedicated data structures for storing data local to a tree invocation.
  * </p>
  *
  * <p>
  * This introduction to Truffle contains items in the following recommended order:
  *
  * <ul>
- * <li>How to get access to the Truffle runtime? {@link com.oracle.truffle.api.test.TruffleRuntimeTest}</li>
+ * <li>How to get access to the Truffle runtime?
+ * {@link com.oracle.truffle.api.test.TruffleRuntimeTest}</li>
  * <li>How to create a root node? {@link com.oracle.truffle.api.test.RootNodeTest}</li>
- * <li>How to create a child node and link it with its parent? {@link com.oracle.truffle.api.test.ChildNodeTest}</li>
- * <li>How to create an array of child nodes? {@link com.oracle.truffle.api.test.ChildrenNodesTest}</li>
- * <li>Why are final fields in node classes important? {@link com.oracle.truffle.api.test.FinalFieldTest}</li>
- * <li>How to replace one node with another node and what for? {@link com.oracle.truffle.api.test.ReplaceTest}</li>
- * <li>How to let one Truffle tree invoke another one? {@link com.oracle.truffle.api.test.CallTest}</li>
- * <li>How to pass arguments when executing a tree? {@link com.oracle.truffle.api.test.ArgumentsTest}</li>
- * <li>How to use frames and frame slots to store values local to an activation? {@link com.oracle.truffle.api.test.FrameTest}</li>
- * <li>How to use type specialization and speculation for frame slots? {@link com.oracle.truffle.api.test.FrameSlotTypeSpecializationTest}</li>
- * <li>How to use type specialization and speculation for node return values? {@link com.oracle.truffle.api.test.ReturnTypeSpecializationTest}</li>
- * <li>How to "instrument" an AST with nodes that can provide access to runtime state from external tools {@code com.oracle.truffle.api.test.instrument.InstrumentationTest}</li>
+ * <li>How to create a child node and link it with its parent?
+ * {@link com.oracle.truffle.api.test.ChildNodeTest}</li>
+ * <li>How to create an array of child nodes? {@link com.oracle.truffle.api.test.ChildrenNodesTest}
+ * </li>
+ * <li>Why are final fields in node classes important?
+ * {@link com.oracle.truffle.api.test.FinalFieldTest}</li>
+ * <li>How to replace one node with another node and what for?
+ * {@link com.oracle.truffle.api.test.ReplaceTest}</li>
+ * <li>How to let one Truffle tree invoke another one? {@link com.oracle.truffle.api.test.CallTest}
+ * </li>
+ * <li>How to pass arguments when executing a tree?
+ * {@link com.oracle.truffle.api.test.ArgumentsTest}</li>
+ * <li>How to use frames and frame slots to store values local to an activation?
+ * {@link com.oracle.truffle.api.test.FrameTest}</li>
+ * <li>How to use type specialization and speculation for frame slots?
+ * {@link com.oracle.truffle.api.test.FrameSlotTypeSpecializationTest}</li>
+ * <li>How to use type specialization and speculation for node return values?
+ * {@link com.oracle.truffle.api.test.ReturnTypeSpecializationTest}</li>
+ * <li>How to "instrument" an AST with nodes that can provide access to runtime state from external
+ * tools {@code com.oracle.truffle.api.test.instrument.InstrumentationTest}</li>
  * </ul>
  *
  *
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/debug/Breakpoint.java	Sat Jul 18 18:03:36 2015 +0200
@@ -0,0 +1,219 @@
+/*
+ * 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.debug;
+
+import com.oracle.truffle.api.instrument.*;
+import com.oracle.truffle.api.source.*;
+import java.io.IOException;
+
+public abstract class Breakpoint {
+
+    /**
+     * A general model of the states occupied by a breakpoint during its lifetime.
+     */
+    public enum State {
+
+        /**
+         * Not attached, enabled.
+         * <p>
+         * Created for a source location but not yet attached: perhaps just created and the source
+         * hasn't been loaded yet; perhaps source has been loaded, but the line location isn't
+         * probed so a breakpoint cannot be attached. Can be either enabled or disabled.
+         */
+        ENABLED_UNRESOLVED("Enabled/Unresolved"),
+
+        /**
+         * Not attached, disabled.
+         * <p>
+         * Created for a source location but not yet attached: perhaps just created and the source
+         * hasn't been loaded yet; perhaps source has been loaded, but the line location isn't
+         * probed so a breakpoint cannot be attached.
+         */
+        DISABLED_UNRESOLVED("Disabled/Unresolved"),
+
+        /**
+         * Attached, instrument enabled.
+         * <p>
+         * Is currently implemented by some {@link Instrument}, which is attached to a {@link Probe}
+         * at a specific node in the AST, and the breakpoint is enabled.
+         */
+        ENABLED("Enabled"),
+
+        /**
+         * Attached, instrument disabled.
+         * <p>
+         * Is currently implemented by some {@link Instrument}, which is attached to a {@link Probe}
+         * at a specific node in the AST, and the breakpoint is disabled.
+         */
+        DISABLED("Disabled"),
+
+        /**
+         * Not attached, instrument is permanently disabled.
+         */
+        DISPOSED("Disposed");
+
+        private final String name;
+
+        State(String name) {
+            this.name = name;
+        }
+
+        public String getName() {
+            return name;
+        }
+
+        @Override
+        public String toString() {
+            return name;
+        }
+
+    }
+
+    private final boolean isOneShot;
+
+    private int ignoreCount;
+
+    private int hitCount;
+
+    private State state;
+
+    Breakpoint(State state, int ignoreCount, boolean isOneShot) {
+        this.state = state;
+        this.isOneShot = isOneShot;
+        this.ignoreCount = ignoreCount;
+    }
+
+    /**
+     * Enables or disables this breakpoint's AST instrumentation. The breakpoint is enabled by
+     * default.
+     *
+     * @param enabled <code>true</code> to activate the instrumentation, <code>false</code> to
+     *            deactivate the instrumentation so that it has no effect.
+     */
+    public abstract void setEnabled(boolean enabled);
+
+    /**
+     * Is this breakpoint active?
+     */
+    public abstract boolean isEnabled();
+
+    /**
+     * Sets the condition on this breakpoint, {@code null} to make it unconditional.
+     *
+     * @param expr if non{@code -null}, a boolean expression, expressed in the guest language, to be
+     *            evaluated in the lexical context at the breakpoint location.
+     * @throws IOException if condition is invalid
+     * @throws UnsupportedOperationException if the breakpoint does not support conditions
+     */
+    public abstract void setCondition(String expr) throws IOException;
+
+    /**
+     * Gets the string, expressed in the Guest Language, that defines the current condition on this
+     * breakpoint; {@code null} if this breakpoint is currently unconditional.
+     */
+    public String getCondition() {
+        return null;
+    }
+
+    /**
+     * Does this breakpoint remove itself after first activation?
+     */
+    public final boolean isOneShot() {
+        return isOneShot;
+    }
+
+    /**
+     * Gets the number of hits left to be ignored before halting.
+     */
+    public final int getIgnoreCount() {
+        return ignoreCount;
+    }
+
+    /**
+     * Change the threshold for when this breakpoint should start causing a break. When both an
+     * ignore count and a {@linkplain #setCondition(String) condition} are specified, the condition
+     * is evaluated first: if {@code false} it is not considered to be a hit. In other words, the
+     * ignore count is for successful conditions only.
+     */
+    public final void setIgnoreCount(int ignoreCount) {
+        this.ignoreCount = ignoreCount;
+    }
+
+    /**
+     * Number of times this breakpoint has reached, with one exception; if the breakpoint has a
+     * condition that evaluates to {@code false}, it does not count as a hit.
+     */
+    public final int getHitCount() {
+        return hitCount;
+    }
+
+    /**
+     * Disables this breakpoint and removes any associated instrumentation; it becomes permanently
+     * inert.
+     */
+    public abstract void dispose();
+
+    /**
+     * Gets a human-sensible description of this breakpoint's location in a {@link Source}.
+     */
+    public abstract String getLocationDescription();
+
+    public final State getState() {
+        return state;
+    }
+
+    final void assertState(State s) {
+        assert state == s;
+    }
+
+    final void setState(State state) {
+        this.state = state;
+    }
+
+    /**
+     * Assumes that all conditions for causing the break have been satisfied, so increments the
+     * <em>hit count</em>. Then checks if the <em>ignore count</em> has been exceeded, and if so
+     * returns {@code true}. If not, it still counts as a <em>hit</em> but should be ignored.
+     *
+     * @return whether to proceed
+     */
+    final boolean incrHitCountCheckIgnore() {
+        return ++hitCount > ignoreCount;
+    }
+
+    @Override
+    public String toString() {
+        final StringBuilder sb = new StringBuilder(getClass().getSimpleName());
+        sb.append(" state=");
+        sb.append(getState() == null ? "<none>" : getState().getName());
+        if (isOneShot()) {
+            sb.append(", " + "One-Shot");
+        }
+        if (getCondition() != null) {
+            sb.append(", condition=\"" + getCondition() + "\"");
+        }
+        return sb.toString();
+    }
+}
--- a/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/debug/DebugSupportProvider.java	Thu Jul 16 19:11:31 2015 +0200
+++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/debug/DebugSupportProvider.java	Sat Jul 18 18:03:36 2015 +0200
@@ -33,15 +33,6 @@
  * Access to language-specific information and execution services to enable debugging.
  */
 public interface DebugSupportProvider extends ToolSupportProvider {
-
-    /**
-     * Runs source code.
-     *
-     * @param source code
-     * @throws DebugSupportException if unable to run successfully
-     */
-    void run(Source source) throws DebugSupportException;
-
     /**
      * Runs source code in a halted execution context, or at top level.
      *
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/debug/Debugger.java	Sat Jul 18 18:03:36 2015 +0200
@@ -0,0 +1,831 @@
+/*
+ * 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.debug;
+
+import java.io.*;
+import java.util.*;
+
+import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.impl.Accessor;
+import com.oracle.truffle.api.instrument.*;
+import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.api.source.*;
+import com.oracle.truffle.api.vm.TruffleVM;
+
+/**
+ * Language-agnostic engine for running Truffle languages under debugging control.
+ */
+public final class Debugger {
+
+    private static final boolean TRACE = false;
+    private static final String TRACE_PREFIX = "DEBUG ENGINE: ";
+
+    private static final PrintStream OUT = System.out;
+
+    private static final SyntaxTag STEPPING_TAG = StandardSyntaxTag.STATEMENT;
+    private static final SyntaxTag CALL_TAG = StandardSyntaxTag.CALL;
+
+    private static void trace(String format, Object... args) {
+        if (TRACE) {
+            OUT.println(TRACE_PREFIX + String.format(format, args));
+        }
+    }
+
+    private final TruffleVM vm;
+    private Source lastSource;
+
+    interface BreakpointCallback {
+
+        /**
+         * Passes control to the debugger with execution suspended.
+         */
+        void haltedAt(Node astNode, MaterializedFrame mFrame, String haltReason);
+    }
+
+    interface WarningLog {
+
+        /**
+         * Logs a warning that is kept until the start of the next execution.
+         */
+        void addWarning(String warning);
+    }
+
+    /**
+     * Implementation of line-oriented breakpoints.
+     */
+    private final LineBreakpointFactory lineBreaks;
+
+    /**
+     * Implementation of tag-oriented breakpoints.
+     */
+    private final TagBreakpointFactory tagBreaks;
+
+    /**
+     * Head of the stack of executions.
+     */
+    private DebugExecutionContext debugContext;
+
+    Debugger(TruffleVM vm) {
+        this.vm = vm;
+
+        Source.setFileCaching(true);
+
+        // Initialize execution context stack
+        debugContext = new DebugExecutionContext(null, null);
+        prepareContinue();
+        debugContext.contextTrace("START EXEC DEFAULT");
+
+        final BreakpointCallback breakpointCallback = new BreakpointCallback() {
+
+            @TruffleBoundary
+            public void haltedAt(Node astNode, MaterializedFrame mFrame, String haltReason) {
+                debugContext.halt(astNode, mFrame, true, haltReason);
+            }
+        };
+
+        final WarningLog warningLog = new WarningLog() {
+
+            public void addWarning(String warning) {
+                assert debugContext != null;
+                debugContext.logWarning(warning);
+            }
+        };
+
+        this.lineBreaks = new LineBreakpointFactory(this, breakpointCallback, warningLog);
+        this.tagBreaks = new TagBreakpointFactory(this, breakpointCallback, warningLog);
+    }
+
+    TruffleVM vm() {
+        return vm;
+    }
+
+    /**
+     * Sets a breakpoint to halt at a source line.
+     *
+     * @param ignoreCount number of hits to ignore before halting
+     * @param lineLocation where to set the breakpoint (source, line number)
+     * @param oneShot breakpoint disposes itself after fist hit, if {@code true}
+     * @return a new breakpoint, initially enabled
+     * @throws IOException if the breakpoint can not be set.
+     */
+    @TruffleBoundary
+    public Breakpoint setLineBreakpoint(int ignoreCount, LineLocation lineLocation, boolean oneShot) throws IOException {
+        return lineBreaks.create(ignoreCount, lineLocation, oneShot);
+    }
+
+    /**
+     * Sets a breakpoint to halt at any node holding a specified {@link SyntaxTag}.
+     *
+     * @param ignoreCount number of hits to ignore before halting
+     * @param oneShot if {@code true} breakpoint removes it self after a hit
+     * @return a new breakpoint, initially enabled
+     * @throws IOException if the breakpoint already set
+     */
+    @TruffleBoundary
+    public Breakpoint setTagBreakpoint(int ignoreCount, SyntaxTag tag, boolean oneShot) throws IOException {
+        return tagBreaks.create(ignoreCount, tag, oneShot);
+    }
+
+    /**
+     * Gets all existing breakpoints, whatever their status, in natural sorted order. Modification
+     * save.
+     */
+    @TruffleBoundary
+    public Collection<Breakpoint> getBreakpoints() {
+        final Collection<Breakpoint> result = new ArrayList<>();
+        result.addAll(lineBreaks.getAll());
+        result.addAll(tagBreaks.getAll());
+        return result;
+    }
+
+    /**
+     * Prepare to execute in Continue mode when guest language program execution resumes. In this
+     * mode:
+     * <ul>
+     * <li>Execution will continue until either:
+     * <ol>
+     * <li>execution arrives at a node to which an enabled breakpoint is attached,
+     * <strong>or:</strong></li>
+     * <li>execution completes.</li>
+     * </ol>
+     * </ul>
+     */
+    @TruffleBoundary
+    void prepareContinue() {
+        debugContext.setStrategy(new Continue());
+    }
+
+    /**
+     * Prepare to execute in StepInto mode when guest language program execution resumes. In this
+     * mode:
+     * <ul>
+     * <li>User breakpoints are disabled.</li>
+     * <li>Execution will continue until either:
+     * <ol>
+     * <li>execution arrives at a node with the tag {@linkplain StandardSyntaxTag#STATEMENT
+     * STATMENT}, <strong>or:</strong></li>
+     * <li>execution completes.</li>
+     * </ol>
+     * <li>StepInto mode persists only through one resumption (i.e. {@code stepIntoCount} steps),
+     * and reverts by default to Continue mode.</li>
+     * </ul>
+     *
+     * @param stepCount the number of times to perform StepInto before halting
+     * @throws IllegalArgumentException if the specified number is {@code <= 0}
+     */
+    @TruffleBoundary
+    void prepareStepInto(int stepCount) {
+        if (stepCount <= 0) {
+            throw new IllegalArgumentException();
+        }
+        debugContext.setStrategy(new StepInto(stepCount));
+    }
+
+    /**
+     * Prepare to execute in StepOut mode when guest language program execution resumes. In this
+     * mode:
+     * <ul>
+     * <li>User breakpoints are enabled.</li>
+     * <li>Execution will continue until either:
+     * <ol>
+     * <li>execution arrives at the nearest enclosing call site on the stack, <strong>or</strong></li>
+     * <li>execution completes.</li>
+     * </ol>
+     * <li>StepOut mode persists only through one resumption, and reverts by default to Continue
+     * mode.</li>
+     * </ul>
+     */
+    @TruffleBoundary
+    void prepareStepOut() {
+        debugContext.setStrategy(new StepOut());
+    }
+
+    /**
+     * Prepare to execute in StepOver mode when guest language program execution resumes. In this
+     * mode:
+     * <ul>
+     * <li>Execution will continue until either:
+     * <ol>
+     * <li>execution arrives at a node with the tag {@linkplain StandardSyntaxTag#STATEMENT
+     * STATEMENT} when not nested in one or more function/method calls, <strong>or:</strong></li>
+     * <li>execution arrives at a node to which a breakpoint is attached and when nested in one or
+     * more function/method calls, <strong>or:</strong></li>
+     * <li>execution completes.</li>
+     * </ol>
+     * <li>StepOver mode persists only through one resumption (i.e. {@code stepOverCount} steps),
+     * and reverts by default to Continue mode.</li>
+     * </ul>
+     *
+     * @param stepCount the number of times to perform StepInto before halting
+     * @throws IllegalArgumentException if the specified number is {@code <= 0}
+     */
+    @TruffleBoundary
+    void prepareStepOver(int stepCount) {
+        if (stepCount <= 0) {
+            throw new IllegalArgumentException();
+        }
+        debugContext.setStrategy(new StepOver(stepCount));
+    }
+
+    /**
+     * Creates a language-specific factory to produce instances of {@link AdvancedInstrumentRoot}
+     * that, when executed, computes the result of a textual expression in the language; used to
+     * create an
+     * {@linkplain Instrument#create(AdvancedInstrumentResultListener, AdvancedInstrumentRootFactory, Class, String)
+     * Advanced Instrument}.
+     *
+     * @param expr a guest language expression
+     * @param resultListener optional listener for the result of each evaluation.
+     * @return a new factory
+     * @throws IOException if the factory cannot be created, for example if the expression is badly
+     *             formed.
+     */
+    AdvancedInstrumentRootFactory createAdvancedInstrumentRootFactory(Probe probe, String expr, AdvancedInstrumentResultListener resultListener) throws IOException {
+        try {
+            Class<? extends TruffleLanguage> langugageClass = ACCESSOR.findLanguage(probe);
+            TruffleLanguage l = ACCESSOR.findLanguage(vm, langugageClass);
+            DebugSupportProvider dsp = ACCESSOR.getDebugSupport(l);
+            return dsp.createAdvancedInstrumentRootFactory(expr, resultListener);
+        } catch (DebugSupportException ex) {
+            throw new IOException(ex);
+        }
+    }
+
+    /**
+     * A mode of user navigation from a current code location to another, e.g "step in" vs.
+     * "step over".
+     */
+    private abstract class StepStrategy {
+
+        private DebugExecutionContext context;
+        protected final String strategyName;
+
+        protected StepStrategy() {
+            this.strategyName = getClass().getSimpleName();
+        }
+
+        final String getName() {
+            return strategyName;
+        }
+
+        /**
+         * Reconfigure the debugger so that when execution continues the program will halt at the
+         * location specified by this strategy.
+         */
+        final void enable(DebugExecutionContext c, int stackDepth) {
+            this.context = c;
+            setStrategy(stackDepth);
+        }
+
+        /**
+         * Return the debugger to the default navigation mode.
+         */
+        final void disable() {
+            unsetStrategy();
+        }
+
+        @TruffleBoundary
+        final void halt(Node astNode, MaterializedFrame mFrame, boolean before) {
+            context.halt(astNode, mFrame, before, this.getClass().getSimpleName());
+        }
+
+        @TruffleBoundary
+        final void replaceStrategy(StepStrategy newStrategy) {
+            context.setStrategy(newStrategy);
+        }
+
+        @TruffleBoundary
+        protected final void strategyTrace(String action, String format, Object... args) {
+            if (TRACE) {
+                context.contextTrace("%s (%s) %s", action, strategyName, String.format(format, args));
+            }
+        }
+
+        @TruffleBoundary
+        protected final void suspendUserBreakpoints() {
+            lineBreaks.setActive(false);
+            tagBreaks.setActive(false);
+        }
+
+        @SuppressWarnings("unused")
+        protected final void restoreUserBreakpoints() {
+            lineBreaks.setActive(true);
+            tagBreaks.setActive(true);
+        }
+
+        /**
+         * Reconfigure the debugger so that when execution continues, it will do so using this mode
+         * of navigation.
+         */
+        protected abstract void setStrategy(int stackDepth);
+
+        /**
+         * Return to the debugger to the default mode of navigation.
+         */
+        protected abstract void unsetStrategy();
+    }
+
+    /**
+     * Strategy: the null stepping strategy.
+     * <ul>
+     * <li>User breakpoints are enabled.</li>
+     * <li>Execution continues until either:
+     * <ol>
+     * <li>execution arrives at a node with attached user breakpoint, <strong>or:</strong></li>
+     * <li>execution completes.</li>
+     * </ol>
+     * </ul>
+     */
+    private final class Continue extends StepStrategy {
+
+        @Override
+        protected void setStrategy(int stackDepth) {
+        }
+
+        @Override
+        protected void unsetStrategy() {
+        }
+    }
+
+    /**
+     * Strategy: per-statement stepping.
+     * <ul>
+     * <li>User breakpoints are enabled.</li>
+     * <li>Execution continues until either:
+     * <ol>
+     * <li>execution <em>arrives</em> at a STATEMENT node, <strong>or:</strong></li>
+     * <li>execution <em>returns</em> to a CALL node and the call stack is smaller then when
+     * execution started, <strong>or:</strong></li>
+     * <li>execution completes.</li>
+     * </ol>
+     * </ul>
+     *
+     * @see Debugger#prepareStepInto(int)
+     */
+    private final class StepInto extends StepStrategy {
+        private int unfinishedStepCount;
+
+        StepInto(int stepCount) {
+            super();
+            this.unfinishedStepCount = stepCount;
+        }
+
+        @Override
+        protected void setStrategy(final int stackDepth) {
+            Probe.setBeforeTagTrap(new SyntaxTagTrap(STEPPING_TAG) {
+
+                @Override
+                public void tagTrappedAt(Node node, MaterializedFrame mFrame) {
+                    // HALT: just before statement
+                    --unfinishedStepCount;
+                    strategyTrace("TRAP BEFORE", "unfinished steps=%d", unfinishedStepCount);
+                    // Should run in fast path
+                    if (unfinishedStepCount <= 0) {
+                        halt(node, mFrame, true);
+                    }
+                    strategyTrace("RESUME BEFORE", "");
+                }
+            });
+            Probe.setAfterTagTrap(new SyntaxTagTrap(CALL_TAG) {
+
+                @Override
+                public void tagTrappedAt(Node node, MaterializedFrame mFrame) {
+                    --unfinishedStepCount;
+                    strategyTrace(null, "TRAP AFTER unfinished steps=%d", unfinishedStepCount);
+                    if (currentStackDepth() < stackDepth) {
+                        // HALT: just "stepped out"
+                        if (unfinishedStepCount <= 0) {
+                            halt(node, mFrame, false);
+                        }
+                    }
+                    strategyTrace("RESUME AFTER", "");
+                }
+            });
+        }
+
+        @Override
+        protected void unsetStrategy() {
+            Probe.setBeforeTagTrap(null);
+            Probe.setAfterTagTrap(null);
+        }
+    }
+
+    /**
+     * Strategy: execution to nearest enclosing call site.
+     * <ul>
+     * <li>User breakpoints are enabled.</li>
+     * <li>Execution continues until either:
+     * <ol>
+     * <li>execution arrives at a node with attached user breakpoint, <strong>or:</strong></li>
+     * <li>execution <em>returns</em> to a CALL node and the call stack is smaller than when
+     * execution started, <strong>or:</strong></li>
+     * <li>execution completes.</li>
+     * </ol>
+     * </ul>
+     *
+     * @see Debugger#prepareStepOut()
+     */
+    private final class StepOut extends StepStrategy {
+
+        @Override
+        protected void setStrategy(final int stackDepth) {
+            Probe.setAfterTagTrap(new SyntaxTagTrap(CALL_TAG) {
+
+                @TruffleBoundary
+                @Override
+                public void tagTrappedAt(Node node, MaterializedFrame mFrame) {
+                    // HALT:
+                    final int currentStackDepth = currentStackDepth();
+                    strategyTrace("TRAP AFTER", "stackDepth: start=%d current=%d", stackDepth, currentStackDepth);
+                    if (currentStackDepth < stackDepth) {
+                        halt(node, mFrame, false);
+                    }
+                    strategyTrace("RESUME AFTER", "");
+                }
+            });
+        }
+
+        @Override
+        protected void unsetStrategy() {
+            Probe.setAfterTagTrap(null);
+        }
+    }
+
+    /**
+     * Strategy: per-statement stepping, so long as not nested in method calls (i.e. at original
+     * stack depth).
+     * <ul>
+     * <li>User breakpoints are enabled.</li>
+     * <li>Execution continues until either:
+     * <ol>
+     * <li>execution arrives at a STATEMENT node with stack depth no more than when started
+     * <strong>or:</strong></li>
+     * <li>the program completes.</li>
+     * </ol>
+     * </ul>
+     */
+    private final class StepOver extends StepStrategy {
+        private int unfinishedStepCount;
+
+        StepOver(int stepCount) {
+            this.unfinishedStepCount = stepCount;
+        }
+
+        @Override
+        protected void setStrategy(final int stackDepth) {
+            Probe.setBeforeTagTrap(new SyntaxTagTrap(STEPPING_TAG) {
+
+                @Override
+                public void tagTrappedAt(Node node, MaterializedFrame mFrame) {
+                    final int currentStackDepth = currentStackDepth();
+                    if (currentStackDepth <= stackDepth) {
+                        // HALT: stack depth unchanged or smaller; treat like StepInto
+                        --unfinishedStepCount;
+                        if (TRACE) {
+                            strategyTrace("TRAP BEFORE", "unfinished steps=%d stackDepth start=%d current=%d", unfinishedStepCount, stackDepth, currentStackDepth);
+                        }
+                        // Test should run in fast path
+                        if (unfinishedStepCount <= 0) {
+                            halt(node, mFrame, true);
+                        }
+                    } else {
+                        // CONTINUE: Stack depth increased; don't count as a step
+                        strategyTrace("STEP INTO", "unfinished steps=%d stackDepth start=%d current=%d", unfinishedStepCount, stackDepth, currentStackDepth);
+                        // Stop treating like StepInto, start treating like StepOut
+                        replaceStrategy(new StepOverNested(unfinishedStepCount, stackDepth));
+                    }
+                    strategyTrace("RESUME BEFORE", "");
+                }
+            });
+
+            Probe.setAfterTagTrap(new SyntaxTagTrap(CALL_TAG) {
+
+                @Override
+                public void tagTrappedAt(Node node, MaterializedFrame mFrame) {
+                    final int currentStackDepth = currentStackDepth();
+                    if (currentStackDepth < stackDepth) {
+                        // HALT: just "stepped out"
+                        --unfinishedStepCount;
+                        strategyTrace("TRAP AFTER", "unfinished steps=%d stackDepth: start=%d current=%d", unfinishedStepCount, stackDepth, currentStackDepth);
+                        // Should run in fast path
+                        if (unfinishedStepCount <= 0) {
+                            halt(node, mFrame, false);
+                        }
+                        strategyTrace("RESUME AFTER", "");
+                    }
+                }
+            });
+        }
+
+        @Override
+        protected void unsetStrategy() {
+            Probe.setBeforeTagTrap(null);
+            Probe.setAfterTagTrap(null);
+        }
+    }
+
+    /**
+     * Strategy: per-statement stepping, not into method calls, in effect while at increased stack
+     * depth
+     * <ul>
+     * <li>User breakpoints are enabled.</li>
+     * <li>Execution continues until either:
+     * <ol>
+     * <li>execution arrives at a STATEMENT node with stack depth no more than when started
+     * <strong>or:</strong></li>
+     * <li>the program completes <strong>or:</strong></li>
+     * </ol>
+     * </ul>
+     */
+    private final class StepOverNested extends StepStrategy {
+        private int unfinishedStepCount;
+        private final int startStackDepth;
+
+        StepOverNested(int stepCount, int startStackDepth) {
+            this.unfinishedStepCount = stepCount;
+            this.startStackDepth = startStackDepth;
+        }
+
+        @Override
+        protected void setStrategy(final int stackDepth) {
+            Probe.setBeforeTagTrap(new SyntaxTagTrap(STEPPING_TAG) {
+
+                @Override
+                public void tagTrappedAt(Node node, MaterializedFrame mFrame) {
+                    final int currentStackDepth = currentStackDepth();
+                    if (currentStackDepth <= startStackDepth) {
+                        // At original step depth (or smaller) after being nested
+                        --unfinishedStepCount;
+                        strategyTrace("TRAP AFTER", "unfinished steps=%d stackDepth start=%d current=%d", unfinishedStepCount, stackDepth, currentStackDepth);
+                        if (unfinishedStepCount <= 0) {
+                            halt(node, mFrame, false);
+                        }
+                        // TODO (mlvdv) fixme for multiple steps
+                        strategyTrace("RESUME BEFORE", "");
+                    }
+                }
+            });
+        }
+
+        @Override
+        protected void unsetStrategy() {
+            Probe.setBeforeTagTrap(null);
+        }
+    }
+
+    /**
+     * Information and debugging state for a single Truffle execution (which make take place over
+     * one or more suspended executions). This holds interaction state, for example what is
+     * executing (e.g. some {@link Source}), what the execution mode is ("stepping" or
+     * "continuing"). When not running, this holds a cache of the Truffle stack for this particular
+     * execution, effectively hiding the Truffle stack for any currently suspended executions (down
+     * the stack).
+     */
+    private final class DebugExecutionContext {
+
+        // Previous halted context in stack
+        private final DebugExecutionContext predecessor;
+
+        // The current execution level; first is 0.
+        private final int level;  // Number of contexts suspended below
+        private final Source source;
+        private final int contextStackBase;  // Where the stack for this execution starts
+        private final List<String> warnings = new ArrayList<>();
+
+        private boolean running;
+
+        /**
+         * The stepping strategy currently configured in the debugger.
+         */
+        private StepStrategy strategy;
+
+        /**
+         * Where halted; null if running.
+         */
+        private Node haltedNode;
+
+        /**
+         * Where halted; null if running.
+         */
+        private MaterializedFrame haltedFrame;
+
+        private DebugExecutionContext(Source executionSource, DebugExecutionContext previousContext) {
+            this.source = executionSource;
+            this.predecessor = previousContext;
+            this.level = previousContext == null ? 0 : previousContext.level + 1;
+
+            // "Base" is the number of stack frames for all nested (halted) executions.
+            this.contextStackBase = currentStackDepth();
+            this.running = true;
+            contextTrace("NEW CONTEXT");
+        }
+
+        /**
+         * Sets up a strategy for the next resumption of execution.
+         *
+         * @param stepStrategy
+         */
+        void setStrategy(StepStrategy stepStrategy) {
+            if (this.strategy == null) {
+                this.strategy = stepStrategy;
+                this.strategy.enable(this, currentStackDepth());
+                if (TRACE) {
+                    contextTrace("SET MODE <none>-->" + stepStrategy.getName());
+                }
+            } else {
+                strategy.disable();
+                strategy = stepStrategy;
+                strategy.enable(this, currentStackDepth());
+                contextTrace("SWITCH MODE %s-->%s", strategy.getName(), stepStrategy.getName());
+            }
+        }
+
+        void clearStrategy() {
+            if (strategy != null) {
+                final StepStrategy oldStrategy = strategy;
+                strategy.disable();
+                strategy = null;
+                contextTrace("CLEAR MODE %s--><none>", oldStrategy.getName());
+            }
+        }
+
+        /**
+         * Handle a program halt, caused by a breakpoint, stepping strategy, or other cause.
+         *
+         * @param astNode the guest language node at which execution is halted
+         * @param mFrame the current execution frame where execution is halted
+         * @param before {@code true} if halted <em>before</em> the node, else <em>after</em>.
+         */
+        @TruffleBoundary
+        void halt(Node astNode, MaterializedFrame mFrame, boolean before, String haltReason) {
+            assert running;
+            assert haltedNode == null;
+            assert haltedFrame == null;
+
+            haltedNode = astNode;
+            haltedFrame = mFrame;
+            running = false;
+
+            clearStrategy();
+
+            // Clean up, just in cased the one-shot breakpoints got confused
+            lineBreaks.disposeOneShots();
+
+            final int contextStackDepth = currentStackDepth() - contextStackBase;
+            if (TRACE) {
+                final String reason = haltReason == null ? "" : haltReason + "";
+                final String where = before ? "BEFORE" : "AFTER";
+                contextTrace("HALT %s : (%s) stack base=%d", where, reason, contextStackBase);
+                contextTrace("CURRENT STACK:");
+                // printStack(OUT);
+            }
+
+            final List<String> recentWarnings = new ArrayList<>(warnings);
+            warnings.clear();
+
+            try {
+                // Pass control to the debug client with current execution suspended
+                ACCESSOR.dispatchEvent(vm, new SuspendedEvent(Debugger.this, astNode, mFrame, recentWarnings, contextStackDepth));
+                // Debug client finished normally, execution resumes
+                // Presume that the client has set a new strategy (or default to Continue)
+                running = true;
+            } catch (KillException e) {
+                contextTrace("KILL");
+                throw e;
+            } finally {
+                haltedNode = null;
+                haltedFrame = null;
+            }
+
+        }
+
+        void logWarning(String warning) {
+            warnings.add(warning);
+        }
+
+        /*
+         * private void printStack(PrintStream stream) { getFrames(); if (frames == null) {
+         * stream.println("<empty stack>"); } else { final Visualizer visualizer =
+         * provider.getVisualizer(); for (FrameDebugDescription frameDesc : frames) { final
+         * StringBuilder sb = new StringBuilder("    frame " + Integer.toString(frameDesc.index()));
+         * sb.append(":at " + visualizer.displaySourceLocation(frameDesc.node())); sb.append(":in '"
+         * + visualizer.displayMethodName(frameDesc.node()) + "'"); stream.println(sb.toString()); }
+         * } }
+         */
+
+        void contextTrace(String format, Object... args) {
+            if (TRACE) {
+                final String srcName = (source != null) ? source.getName() : "no source";
+                Debugger.trace("<%d> %s (%s)", level, String.format(format, args), srcName);
+            }
+        }
+    }
+
+    // TODO (mlvdv) wish there were fast-path access to stack depth
+    /**
+     * Depth of current Truffle stack, including nested executions. Includes the top/current frame,
+     * which the standard iterator does not count: {@code 0} if no executions.
+     */
+    @TruffleBoundary
+    private static int currentStackDepth() {
+        final int[] count = {0};
+        Truffle.getRuntime().iterateFrames(new FrameInstanceVisitor<Void>() {
+            @Override
+            public Void visitFrame(FrameInstance frameInstance) {
+                count[0] = count[0] + 1;
+                return null;
+            }
+        });
+        return count[0] == 0 ? 0 : count[0] + 1;
+
+    }
+
+    void executionStarted(Source source) {
+        Source execSource = source;
+        if (execSource == null) {
+            execSource = lastSource;
+        } else {
+            lastSource = execSource;
+        }
+        // Push a new execution context onto stack
+        debugContext = new DebugExecutionContext(execSource, debugContext);
+        prepareContinue();
+        debugContext.contextTrace("START EXEC ");
+        ACCESSOR.dispatchEvent(vm, new ExecutionEvent(this));
+    }
+
+    void executionEnded() {
+        lineBreaks.disposeOneShots();
+        tagBreaks.disposeOneShots();
+        debugContext.clearStrategy();
+        debugContext.contextTrace("END EXEC ");
+        // Pop the stack of execution contexts.
+        debugContext = debugContext.predecessor;
+    }
+
+    private static final class AccessorDebug extends Accessor {
+        @Override
+        protected Closeable executionStart(TruffleVM vm, Debugger[] fillIn, Source s) {
+            final Debugger d;
+            if (fillIn[0] == null) {
+                d = fillIn[0] = new Debugger(vm);
+            } else {
+                d = fillIn[0];
+            }
+            d.executionStarted(s);
+            return new Closeable() {
+                @Override
+                public void close() throws IOException {
+                    d.executionEnded();
+                }
+            };
+        }
+
+        @Override
+        protected Class<? extends TruffleLanguage> findLanguage(Probe probe) {
+            return super.findLanguage(probe);
+        }
+
+        @Override
+        protected TruffleLanguage findLanguage(TruffleVM vm, Class<? extends TruffleLanguage> languageClass) {
+            return super.findLanguage(vm, languageClass);
+        }
+
+        @Override
+        protected DebugSupportProvider getDebugSupport(TruffleLanguage l) {
+            return super.getDebugSupport(l);
+        }
+
+        @Override
+        protected void dispatchEvent(TruffleVM vm, Object event) {
+            super.dispatchEvent(vm, event);
+        }
+    }
+
+    // registers into Accessor.DEBUG
+    private static final AccessorDebug ACCESSOR = new AccessorDebug();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/debug/ExecutionEvent.java	Sat Jul 18 18:03:36 2015 +0200
@@ -0,0 +1,98 @@
+/*
+ * 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.debug;
+
+import com.oracle.truffle.api.instrument.*;
+import com.oracle.truffle.api.vm.TruffleVM;
+import com.oracle.truffle.api.vm.TruffleVM.Builder;
+
+/**
+ * This event is delivered to all {@link Builder#onEvent(com.oracle.truffle.api.vm.EventConsumer)
+ * registered event handlers} when an execution is about to be started. The event is the intended
+ * place to initialize debugger - e.g. set
+ * {@link Debugger#setLineBreakpoint(int, com.oracle.truffle.api.source.LineLocation, boolean)
+ * breakpoints} or specify to execution should halt on the {@link #prepareStepInto() first possible
+ * occurence}. Methods in this event can only be used while the handlers process the event. Then the
+ * state of the event becomes invalid and subsequent calls to the event methods yield
+ * {@link IllegalStateException}. One can however obtain reference to {@link Debugger} instance and
+ * keep it to further manipulate with debugging capabilities of the {@link TruffleVM} when it is
+ * running.
+ */
+public final class ExecutionEvent {
+    private final Debugger debugger;
+
+    ExecutionEvent(Debugger prepares) {
+        this.debugger = prepares;
+    }
+
+    /**
+     * Debugger associated with the execution. This debuger remains valid after the event is
+     * processed, it is possible and suggested to keep a reference to it and use it any time later
+     * when evaluating sources in the {@link TruffleVM}.
+     *
+     * @return instance of debugger associated with the just starting execution and any subsequent
+     *         ones in the same {@link TruffleVM}.
+     */
+    public Debugger getDebugger() {
+        return debugger;
+    }
+
+    /**
+     * Prepare to execute in Continue mode when guest language program execution resumes. In this
+     * mode:
+     * <ul>
+     * <li>Execution will continue until either:
+     * <ol>
+     * <li>execution arrives at a node to which an enabled breakpoint is attached,
+     * <strong>or:</strong></li>
+     * <li>execution completes.</li>
+     * </ol>
+     * </ul>
+     */
+    public void prepareContinue() {
+        debugger.prepareContinue();
+    }
+
+    /**
+     * Prepare to execute in StepInto mode when guest language program execution resumes. In this
+     * mode:
+     * <ul>
+     * <li>User breakpoints are disabled.</li>
+     * <li>Execution will continue until either:
+     * <ol>
+     * <li>execution arrives at a node with the tag {@linkplain StandardSyntaxTag#STATEMENT
+     * STATMENT}, <strong>or:</strong></li>
+     * <li>execution completes.</li>
+     * </ol>
+     * <li>StepInto mode persists only through one resumption (i.e. {@code stepIntoCount} steps),
+     * and reverts by default to Continue mode.</li>
+     * </ul>
+     *
+     * @throws IllegalArgumentException if the specified number is {@code <= 0}
+     */
+    public void prepareStepInto() {
+        debugger.prepareStepInto(1);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/debug/LineBreakpoint.java	Sat Jul 18 18:03:36 2015 +0200
@@ -0,0 +1,47 @@
+/*
+ * 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.debug;
+
+import com.oracle.truffle.api.source.*;
+
+// TODO (mlvdv) generic?
+/**
+ * A breakpoint associated with a {@linkplain LineLocation source line location}.
+ *
+ * @see Debugger
+ */
+abstract class LineBreakpoint extends Breakpoint {
+
+    LineBreakpoint(State state, int ignoreCount, boolean isOneShot) {
+        super(state, ignoreCount, isOneShot);
+    }
+
+    /**
+     * Gets the {@linkplain LineLocation source line location} that specifies where this breakpoint
+     * will trigger.
+     */
+    public abstract LineLocation getLineLocation();
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/debug/LineBreakpointFactory.java	Sat Jul 18 18:03:36 2015 +0200
@@ -0,0 +1,465 @@
+/*
+ * 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.debug;
+
+import static com.oracle.truffle.api.debug.Breakpoint.State.*;
+
+import java.io.*;
+import java.util.*;
+import java.util.Map.Entry;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
+import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
+import com.oracle.truffle.api.debug.Debugger.BreakpointCallback;
+import com.oracle.truffle.api.debug.Debugger.WarningLog;
+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.api.utilities.*;
+
+//TODO (mlvdv) some common functionality could be factored out of this and TagBreakpointSupport
+
+/**
+ * Support class for creating and managing all existing ordinary (user visible) line breakpoints.
+ * <p>
+ * Notes:
+ * <ol>
+ * <li>Line breakpoints can only be set at nodes tagged as {@link StandardSyntaxTag#STATEMENT}.</li>
+ * <li>A newly created breakpoint looks for probes matching the location, attaches to them if found
+ * by installing an {@link Instrument} that calls back to the breakpoint.</li>
+ * <li>When Truffle "splits" or otherwise copies an AST, any attached {@link Instrument} will be
+ * copied along with the rest of the AST and will call back to the same breakpoint.</li>
+ * <li>When notification is received of a new Node being tagged as a statement, and if a
+ * breakpoint's line location matches the Probe's line location, then the breakpoint will attach a
+ * new Instrument at the probe to activate the breakpoint at that location.</li>
+ * <li>A breakpoint may have multiple Instruments deployed, one attached to each Probe that matches
+ * the breakpoint's line location; this might happen when a source is reloaded.</li>
+ * </ol>
+ *
+ */
+final class LineBreakpointFactory {
+
+    private static final boolean TRACE = false;
+    private static final PrintStream OUT = System.out;
+
+    private static final String BREAKPOINT_NAME = "LINE BREAKPOINT";
+
+    private static void trace(String format, Object... args) {
+        if (TRACE) {
+            OUT.println(String.format("%s: %s", BREAKPOINT_NAME, String.format(format, args)));
+        }
+    }
+
+    private static final Comparator<Entry<LineLocation, LineBreakpointImpl>> BREAKPOINT_COMPARATOR = new Comparator<Entry<LineLocation, LineBreakpointImpl>>() {
+
+        @Override
+        public int compare(Entry<LineLocation, LineBreakpointImpl> entry1, Entry<LineLocation, LineBreakpointImpl> entry2) {
+            final LineLocation line1 = entry1.getKey();
+            final LineLocation line2 = entry2.getKey();
+            final int nameOrder = line1.getSource().getShortName().compareTo(line2.getSource().getShortName());
+            if (nameOrder != 0) {
+                return nameOrder;
+            }
+            return Integer.compare(line1.getLineNumber(), line2.getLineNumber());
+        }
+    };
+
+    private final Debugger executionSupport;
+    private final BreakpointCallback breakpointCallback;
+    private final WarningLog warningLog;
+
+    /**
+     * Map: Source lines ==> attached breakpoints. There may be no more than one line breakpoint
+     * associated with a line.
+     */
+    private final Map<LineLocation, LineBreakpointImpl> lineToBreakpoint = new HashMap<>();
+
+    /**
+     * A map of {@link LineLocation} to a collection of {@link Probe}s. This list must be
+     * initialized and filled prior to being used by this class.
+     */
+    private final LineToProbesMap lineToProbesMap;
+
+    /**
+     * Globally suspends all line breakpoint activity when {@code false}, ignoring whether
+     * individual breakpoints are enabled.
+     */
+    @CompilationFinal private boolean breakpointsActive = true;
+    private final CyclicAssumption breakpointsActiveUnchanged = new CyclicAssumption(BREAKPOINT_NAME + " globally active");
+
+    LineBreakpointFactory(Debugger executionSupport, BreakpointCallback breakpointCallback, final WarningLog warningLog) {
+        this.executionSupport = executionSupport;
+        this.breakpointCallback = breakpointCallback;
+        this.warningLog = warningLog;
+
+        lineToProbesMap = new LineToProbesMap();
+        lineToProbesMap.install();
+
+        Probe.addProbeListener(new DefaultProbeListener() {
+
+            @Override
+            public void probeTaggedAs(Probe probe, SyntaxTag tag, Object tagValue) {
+                if (tag == StandardSyntaxTag.STATEMENT) {
+                    final SourceSection sourceSection = probe.getProbedSourceSection();
+                    if (sourceSection != null) {
+                        final LineLocation lineLocation = sourceSection.getLineLocation();
+                        if (lineLocation != null) {
+                            // A Probe with line location tagged STATEMENT we haven't seen before.
+                            final LineBreakpointImpl breakpoint = lineToBreakpoint.get(lineLocation);
+                            if (breakpoint != null) {
+                                try {
+                                    breakpoint.attach(probe);
+                                } catch (IOException e) {
+                                    warningLog.addWarning(BREAKPOINT_NAME + " failure attaching to newly tagged Probe: " + e.getMessage());
+                                    if (TRACE) {
+                                        OUT.println(BREAKPOINT_NAME + " failure: " + e.getMessage());
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        });
+    }
+
+    /**
+     * Globally enables line breakpoint activity; all breakpoints are ignored when set to
+     * {@code false}. When set to {@code true}, the enabled/disabled status of each breakpoint
+     * determines whether it will trigger when flow of execution reaches it.
+     *
+     * @param breakpointsActive
+     */
+    void setActive(boolean breakpointsActive) {
+        if (this.breakpointsActive != breakpointsActive) {
+            breakpointsActiveUnchanged.invalidate();
+            this.breakpointsActive = breakpointsActive;
+        }
+    }
+
+    /**
+     * Gets all current line breakpoints,regardless of status; sorted and modification safe.
+     */
+    List<LineBreakpoint> getAll() {
+        ArrayList<Entry<LineLocation, LineBreakpointImpl>> entries = new ArrayList<>(lineToBreakpoint.entrySet());
+        Collections.sort(entries, BREAKPOINT_COMPARATOR);
+
+        final ArrayList<LineBreakpoint> breakpoints = new ArrayList<>(entries.size());
+        for (Entry<LineLocation, LineBreakpointImpl> entry : entries) {
+            breakpoints.add(entry.getValue());
+        }
+        return breakpoints;
+    }
+
+    /**
+     * Creates a new line breakpoint if one doesn't already exist. If one does exist, then resets
+     * the <em>ignore count</em>.
+     *
+     * @param lineLocation where to set the breakpoint
+     * @param ignoreCount number of initial hits before the breakpoint starts causing breaks.
+     * @param oneShot whether the breakpoint should dispose itself after one hit
+     * @return a possibly new breakpoint
+     * @throws IOException if a breakpoint already exists at the location and the ignore count is
+     *             the same
+     */
+    LineBreakpoint create(int ignoreCount, LineLocation lineLocation, boolean oneShot) throws IOException {
+
+        LineBreakpointImpl breakpoint = lineToBreakpoint.get(lineLocation);
+
+        if (breakpoint == null) {
+            breakpoint = new LineBreakpointImpl(ignoreCount, lineLocation, oneShot);
+
+            if (TRACE) {
+                trace("NEW " + breakpoint.getShortDescription());
+            }
+
+            lineToBreakpoint.put(lineLocation, breakpoint);
+
+            for (Probe probe : lineToProbesMap.findProbes(lineLocation)) {
+                if (probe.isTaggedAs(StandardSyntaxTag.STATEMENT)) {
+                    breakpoint.attach(probe);
+                    break;
+                }
+            }
+        } else {
+            if (ignoreCount == breakpoint.getIgnoreCount()) {
+                throw new IOException(BREAKPOINT_NAME + " already set at line " + lineLocation);
+            }
+            breakpoint.setIgnoreCount(ignoreCount);
+            if (TRACE) {
+                trace("CHANGED ignoreCount %s", breakpoint.getShortDescription());
+            }
+        }
+        return breakpoint;
+    }
+
+    /**
+     * Returns the {@link LineBreakpoint} for a given line. There should only ever be one breakpoint
+     * per line.
+     *
+     * @param lineLocation The {@link LineLocation} to get the breakpoint for.
+     * @return The breakpoint for the given line.
+     */
+    LineBreakpoint get(LineLocation lineLocation) {
+        return lineToBreakpoint.get(lineLocation);
+    }
+
+    /**
+     * Removes the associated instrumentation for all one-shot breakpoints only.
+     */
+    void disposeOneShots() {
+        List<LineBreakpointImpl> breakpoints = new ArrayList<>(lineToBreakpoint.values());
+        for (LineBreakpointImpl breakpoint : breakpoints) {
+            if (breakpoint.isOneShot()) {
+                breakpoint.dispose();
+            }
+        }
+    }
+
+    /**
+     * Removes all knowledge of a breakpoint, presumed disposed.
+     */
+    private void forget(LineBreakpointImpl breakpoint) {
+        lineToBreakpoint.remove(breakpoint.getLineLocation());
+    }
+
+    /**
+     * Concrete representation of a line breakpoint, implemented by attaching an instrument to a
+     * probe at the designated source location.
+     */
+    private final class LineBreakpointImpl extends LineBreakpoint implements AdvancedInstrumentResultListener {
+
+        private static final String SHOULD_NOT_HAPPEN = "LineBreakpointImpl:  should not happen";
+
+        private final LineLocation lineLocation;
+
+        // Cached assumption that the global status of line breakpoint activity has not changed.
+        private Assumption breakpointsActiveAssumption;
+
+        // Whether this breakpoint is enable/disabled
+        @CompilationFinal private boolean isEnabled;
+        private Assumption enabledUnchangedAssumption;
+
+        private String conditionExpr;
+
+        /**
+         * The instrument(s) that this breakpoint currently has attached to a {@link Probe}:
+         * {@code null} if not attached.
+         */
+        private List<Instrument> instruments = new ArrayList<>();
+
+        public LineBreakpointImpl(int ignoreCount, LineLocation lineLocation, boolean oneShot) {
+            super(ENABLED_UNRESOLVED, ignoreCount, oneShot);
+            this.lineLocation = lineLocation;
+
+            this.breakpointsActiveAssumption = LineBreakpointFactory.this.breakpointsActiveUnchanged.getAssumption();
+            this.isEnabled = true;
+            this.enabledUnchangedAssumption = Truffle.getRuntime().createAssumption(BREAKPOINT_NAME + " enabled state unchanged");
+        }
+
+        @Override
+        public boolean isEnabled() {
+            return isEnabled;
+        }
+
+        @Override
+        public void setEnabled(boolean enabled) {
+            if (enabled != isEnabled) {
+                switch (getState()) {
+                    case ENABLED:
+                        assert !enabled : SHOULD_NOT_HAPPEN;
+                        doSetEnabled(false);
+                        changeState(DISABLED);
+                        break;
+                    case ENABLED_UNRESOLVED:
+                        assert !enabled : SHOULD_NOT_HAPPEN;
+                        doSetEnabled(false);
+                        changeState(DISABLED_UNRESOLVED);
+                        break;
+                    case DISABLED:
+                        assert enabled : SHOULD_NOT_HAPPEN;
+                        doSetEnabled(true);
+                        changeState(ENABLED);
+                        break;
+                    case DISABLED_UNRESOLVED:
+                        assert enabled : SHOULD_NOT_HAPPEN;
+                        doSetEnabled(true);
+                        changeState(DISABLED_UNRESOLVED);
+                        break;
+                    case DISPOSED:
+                        assert false : "breakpoint disposed";
+                        break;
+                    default:
+                        assert false : SHOULD_NOT_HAPPEN;
+                        break;
+                }
+            }
+        }
+
+        @Override
+        public void setCondition(String expr) throws IOException {
+            if (this.conditionExpr != null || expr != null) {
+                // De-instrument the Probes instrumented by this breakpoint
+                final ArrayList<Probe> probes = new ArrayList<>();
+                for (Instrument instrument : instruments) {
+                    probes.add(instrument.getProbe());
+                    instrument.dispose();
+                }
+                instruments.clear();
+                this.conditionExpr = expr;
+                // Re-instrument the probes previously instrumented
+                for (Probe probe : probes) {
+                    attach(probe);
+                }
+            }
+        }
+
+        @Override
+        public String getCondition() {
+            return conditionExpr;
+        }
+
+        @Override
+        public void dispose() {
+            if (getState() != DISPOSED) {
+                for (Instrument instrument : instruments) {
+                    instrument.dispose();
+                }
+                changeState(DISPOSED);
+                LineBreakpointFactory.this.forget(this);
+            }
+        }
+
+        private void attach(Probe newProbe) throws IOException {
+            if (getState() == DISPOSED) {
+                throw new IllegalStateException("Attempt to attach a disposed " + BREAKPOINT_NAME);
+            }
+            Instrument newInstrument = null;
+            if (conditionExpr == null) {
+                newInstrument = Instrument.create(new UnconditionalLineBreakInstrumentListener(), BREAKPOINT_NAME);
+            } else {
+                newInstrument = Instrument.create(this, executionSupport.createAdvancedInstrumentRootFactory(newProbe, conditionExpr, this), Boolean.class, BREAKPOINT_NAME);
+            }
+            newProbe.attach(newInstrument);
+            instruments.add(newInstrument);
+            changeState(isEnabled ? ENABLED : DISABLED);
+        }
+
+        private void doSetEnabled(boolean enabled) {
+            if (this.isEnabled != enabled) {
+                enabledUnchangedAssumption.invalidate();
+                this.isEnabled = enabled;
+            }
+        }
+
+        private String getShortDescription() {
+            return BREAKPOINT_NAME + "@" + getLineLocation().getShortDescription();
+        }
+
+        private void changeState(State after) {
+            if (TRACE) {
+                trace("STATE %s-->%s %s", getState().getName(), after.getName(), getShortDescription());
+            }
+            setState(after);
+        }
+
+        private void doBreak(Node node, VirtualFrame vFrame) {
+            if (incrHitCountCheckIgnore()) {
+                breakpointCallback.haltedAt(node, vFrame.materialize(), BREAKPOINT_NAME);
+            }
+        }
+
+        /**
+         * Receives notification from the attached instrument that execution is about to enter node
+         * where the breakpoint is set. Designed so that when in the fast path, there is either an
+         * unconditional "halt" call to the debugger or nothing.
+         */
+        private void nodeEnter(Node astNode, VirtualFrame vFrame) {
+
+            // Deopt if the global active/inactive flag has changed
+            try {
+                this.breakpointsActiveAssumption.check();
+            } catch (InvalidAssumptionException ex) {
+                this.breakpointsActiveAssumption = LineBreakpointFactory.this.breakpointsActiveUnchanged.getAssumption();
+            }
+
+            // Deopt if the enabled/disabled state of this breakpoint has changed
+            try {
+                this.enabledUnchangedAssumption.check();
+            } catch (InvalidAssumptionException ex) {
+                this.enabledUnchangedAssumption = Truffle.getRuntime().createAssumption("LineBreakpoint enabled state unchanged");
+            }
+
+            if (LineBreakpointFactory.this.breakpointsActive && this.isEnabled) {
+                if (isOneShot()) {
+                    dispose();
+                }
+                LineBreakpointImpl.this.doBreak(astNode, vFrame);
+            }
+        }
+
+        public void notifyResult(Node node, VirtualFrame vFrame, Object result) {
+            final boolean condition = (Boolean) result;
+            if (TRACE) {
+                trace("breakpoint condition = %b  %s", condition, getShortDescription());
+            }
+            if (condition) {
+                nodeEnter(node, vFrame);
+            }
+        }
+
+        @TruffleBoundary
+        public void notifyFailure(Node node, VirtualFrame vFrame, RuntimeException ex) {
+            warningLog.addWarning(String.format("Exception in %s:  %s", getShortDescription(), ex.getMessage()));
+            if (TRACE) {
+                trace("breakpoint failure = %s  %s", ex.toString(), getShortDescription());
+            }
+            // Take the breakpoint if evaluation fails.
+            nodeEnter(node, vFrame);
+        }
+
+        @Override
+        public String getLocationDescription() {
+            return "Line: " + lineLocation.getShortDescription();
+        }
+
+        @Override
+        public LineLocation getLineLocation() {
+            return lineLocation;
+        }
+
+        private final class UnconditionalLineBreakInstrumentListener extends DefaultStandardInstrumentListener {
+
+            @Override
+            public void enter(Probe probe, Node node, VirtualFrame vFrame) {
+                LineBreakpointImpl.this.nodeEnter(node, vFrame);
+            }
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/debug/LineToProbesMap.java	Sat Jul 18 18:03:36 2015 +0200
@@ -0,0 +1,128 @@
+/*
+ * 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.debug;
+
+import java.io.*;
+import java.util.*;
+
+import com.oracle.truffle.api.instrument.*;
+import com.oracle.truffle.api.instrument.impl.DefaultProbeListener;
+import com.oracle.truffle.api.source.*;
+
+/**
+ * An {@link InstrumentationTool} that builds a map of every {@link Probe} attached to some AST,
+ * indexed by {@link Source} and line number.
+ */
+final class LineToProbesMap extends InstrumentationTool {
+
+    private static final boolean TRACE = false;
+    private static final PrintStream OUT = System.out;
+
+    private static void trace(String msg) {
+        OUT.println("LineToProbesMap: " + msg);
+    }
+
+    /**
+     * Map: Source line ==> probes associated with source sections starting on the line.
+     */
+    private final Map<LineLocation, Collection<Probe>> lineToProbesMap = new HashMap<>();
+
+    private final ProbeListener probeListener;
+
+    /**
+     * Create a map of {@link Probe}s that collects information on all probes added to subsequently
+     * created ASTs (once installed).
+     */
+    public LineToProbesMap() {
+        this.probeListener = new LineToProbesListener();
+    }
+
+    @Override
+    protected boolean internalInstall() {
+        Probe.addProbeListener(probeListener);
+        return true;
+    }
+
+    @Override
+    protected void internalReset() {
+        lineToProbesMap.clear();
+    }
+
+    @Override
+    protected void internalDispose() {
+        Probe.removeProbeListener(probeListener);
+    }
+
+    /**
+     * Returns the {@link Probe}, if any, associated with a specific line of guest language code; if
+     * more than one, return the one with the first starting character location.
+     */
+    public Probe findFirstProbe(LineLocation lineLocation) {
+        Probe probe = null;
+        final Collection<Probe> probes = findProbes(lineLocation);
+        for (Probe probesOnLine : probes) {
+            if (probe == null) {
+                probe = probesOnLine;
+            } else if (probesOnLine.getProbedSourceSection().getCharIndex() < probe.getProbedSourceSection().getCharIndex()) {
+                probe = probesOnLine;
+            }
+        }
+        return probe;
+    }
+
+    /**
+     * Returns all {@link Probe}s whose associated source begins at the given {@link LineLocation},
+     * an empty list if none.
+     */
+    public Collection<Probe> findProbes(LineLocation line) {
+        final Collection<Probe> probes = lineToProbesMap.get(line);
+        if (probes == null) {
+            return Collections.emptyList();
+        }
+        return Collections.unmodifiableCollection(probes);
+    }
+
+    private class LineToProbesListener extends DefaultProbeListener {
+
+        @Override
+        public void newProbeInserted(Probe probe) {
+            final SourceSection sourceSection = probe.getProbedSourceSection();
+            if (sourceSection != null && sourceSection.getSource() != null) {
+                final LineLocation lineLocation = sourceSection.getLineLocation();
+                if (TRACE) {
+                    trace("ADD " + lineLocation.getShortDescription() + " ==> " + probe.getShortDescription());
+                }
+                Collection<Probe> probes = lineToProbesMap.get(lineLocation);
+                if (probes == null) {
+                    probes = new ArrayList<>(2);
+                    lineToProbesMap.put(lineLocation, probes);
+                } else {
+                    assert !probes.contains(probe);
+                }
+                probes.add(probe);
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/debug/SuspendedEvent.java	Sat Jul 18 18:03:36 2015 +0200
@@ -0,0 +1,195 @@
+/*
+ * 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.debug;
+
+import com.oracle.truffle.api.CompilerDirectives;
+import com.oracle.truffle.api.Truffle;
+import com.oracle.truffle.api.frame.FrameInstance;
+import com.oracle.truffle.api.frame.FrameInstanceVisitor;
+import com.oracle.truffle.api.frame.MaterializedFrame;
+import com.oracle.truffle.api.instrument.*;
+import com.oracle.truffle.api.nodes.Node;
+import com.oracle.truffle.api.vm.TruffleVM;
+import com.oracle.truffle.api.vm.TruffleVM.Builder;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * This event is delivered to all {@link Builder#onEvent(com.oracle.truffle.api.vm.EventConsumer)
+ * registered event handlers} when an execution is suspended on a
+ * {@link Debugger#setLineBreakpoint(int, com.oracle.truffle.api.source.LineLocation, boolean)
+ * breakpoint} or during {@link #prepareStepInto(int) stepping}. Methods in this event can only be
+ * used while the handlers process the event. Then the state of the event becomes invalid and
+ * subsequent calls to the event methods yield {@link IllegalStateException}.
+ *
+ */
+public final class SuspendedEvent {
+    private final List<String> recentWarnings;
+    private final MaterializedFrame mFrame;
+    private final Node astNode;
+    private final List<FrameInstance> frames;
+    private final Debugger debugger;
+
+    SuspendedEvent(Debugger prepares, Node astNode, MaterializedFrame mFrame, List<String> recentWarnings, final int stackDepth) {
+        this.debugger = prepares;
+        this.astNode = astNode;
+        this.mFrame = mFrame;
+        this.recentWarnings = recentWarnings;
+
+        this.frames = new ArrayList<>();
+        // Map the Truffle stack for this execution, ignore nested executions
+        // The top (current) frame is not produced by the iterator.
+        frames.add(Truffle.getRuntime().getCurrentFrame());
+        Truffle.getRuntime().iterateFrames(new FrameInstanceVisitor<FrameInstance>() {
+            int frameCount = 1;
+
+            @Override
+            public FrameInstance visitFrame(FrameInstance frameInstance) {
+                if (frameCount < stackDepth) {
+                    frames.add(frameInstance);
+                    frameCount++;
+                    return null;
+                }
+                return frameInstance;
+            }
+        });
+
+    }
+
+    /**
+     * Debugger associated with the just suspended execution. This debuger remains valid after the
+     * event is processed, it is possible and suggested to keep a reference to it and use it any
+     * time later when evaluating sources in the {@link TruffleVM}.
+     *
+     * @return instance of debugger associated with the just suspended execution and any subsequent
+     *         ones in the same {@link TruffleVM}.
+     */
+    public Debugger getDebugger() {
+        return debugger;
+    }
+
+    public Node getNode() {
+        return astNode;
+    }
+
+    public MaterializedFrame getFrame() {
+        return mFrame;
+    }
+
+    public List<String> getRecentWarnings() {
+        return Collections.unmodifiableList(recentWarnings);
+    }
+
+    /**
+     * Gets the stack frames from the currently halted {@link TruffleVM} execution.
+     *
+     * @return list of stack frames
+     */
+    @CompilerDirectives.TruffleBoundary
+    public List<FrameInstance> getStack() {
+        return Collections.unmodifiableList(frames);
+    }
+
+    /**
+     * Prepare to execute in Continue mode when guest language program execution resumes. In this
+     * mode:
+     * <ul>
+     * <li>Execution will continue until either:
+     * <ol>
+     * <li>execution arrives at a node to which an enabled breakpoint is attached,
+     * <strong>or:</strong></li>
+     * <li>execution completes.</li>
+     * </ol>
+     * </ul>
+     */
+    public void prepareContinue() {
+        debugger.prepareContinue();
+    }
+
+    /**
+     * Prepare to execute in StepInto mode when guest language program execution resumes. In this
+     * mode:
+     * <ul>
+     * <li>User breakpoints are disabled.</li>
+     * <li>Execution will continue until either:
+     * <ol>
+     * <li>execution arrives at a node with the tag {@linkplain StandardSyntaxTag#STATEMENT
+     * STATMENT}, <strong>or:</strong></li>
+     * <li>execution completes.</li>
+     * </ol>
+     * <li>StepInto mode persists only through one resumption (i.e. {@code stepIntoCount} steps),
+     * and reverts by default to Continue mode.</li>
+     * </ul>
+     *
+     * @param stepCount the number of times to perform StepInto before halting
+     * @throws IllegalArgumentException if the specified number is {@code <= 0}
+     */
+    public void prepareStepInto(int stepCount) {
+        debugger.prepareStepInto(stepCount);
+    }
+
+    /**
+     * Prepare to execute in StepOut mode when guest language program execution resumes. In this
+     * mode:
+     * <ul>
+     * <li>User breakpoints are enabled.</li>
+     * <li>Execution will continue until either:
+     * <ol>
+     * <li>execution arrives at the nearest enclosing call site on the stack, <strong>or</strong></li>
+     * <li>execution completes.</li>
+     * </ol>
+     * <li>StepOut mode persists only through one resumption, and reverts by default to Continue
+     * mode.</li>
+     * </ul>
+     */
+    public void prepareStepOut() {
+        debugger.prepareStepOut();
+    }
+
+    /**
+     * Prepare to execute in StepOver mode when guest language program execution resumes. In this
+     * mode:
+     * <ul>
+     * <li>Execution will continue until either:
+     * <ol>
+     * <li>execution arrives at a node with the tag {@linkplain StandardSyntaxTag#STATEMENT
+     * STATEMENT} when not nested in one or more function/method calls, <strong>or:</strong></li>
+     * <li>execution arrives at a node to which a breakpoint is attached and when nested in one or
+     * more function/method calls, <strong>or:</strong></li>
+     * <li>execution completes.</li>
+     * </ol>
+     * <li>StepOver mode persists only through one resumption (i.e. {@code stepOverCount} steps),
+     * and reverts by default to Continue mode.</li>
+     * </ul>
+     *
+     * @param stepCount the number of times to perform StepInto before halting
+     * @throws IllegalArgumentException if the specified number is {@code <= 0}
+     */
+    public void prepareStepOver(int stepCount) {
+        debugger.prepareStepOver(stepCount);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/debug/TagBreakpoint.java	Sat Jul 18 18:03:36 2015 +0200
@@ -0,0 +1,46 @@
+/*
+ * 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.debug;
+
+import com.oracle.truffle.api.instrument.*;
+
+// TODO (mlvdv) generic?
+/**
+ * A breakpoint associated with a {@link SyntaxTag}.
+ *
+ * @see Debugger
+ */
+abstract class TagBreakpoint extends Breakpoint {
+
+    TagBreakpoint(State state, int ignoreCount, boolean isOneShot) {
+        super(state, ignoreCount, isOneShot);
+    }
+
+    /**
+     * Gets the tag that specifies where this breakpoint will trigger.
+     */
+    public abstract SyntaxTag getTag();
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/debug/TagBreakpointFactory.java	Sat Jul 18 18:03:36 2015 +0200
@@ -0,0 +1,429 @@
+/*
+ * 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.debug;
+
+import static com.oracle.truffle.api.debug.Breakpoint.State.*;
+
+import java.io.*;
+import java.util.*;
+import java.util.Map.Entry;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
+import com.oracle.truffle.api.debug.Debugger.BreakpointCallback;
+import com.oracle.truffle.api.debug.Debugger.WarningLog;
+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.utilities.*;
+
+// TODO (mlvdv) some common functionality could be factored out of this and LineBreakpointSupport
+
+/**
+ * Support class for creating and managing "Tag Breakpoints". A Tag Breakpoint halts execution just
+ * before reaching any node whose Probe carries a specified {@linkplain SyntaxTag Tag}.
+ * <p>
+ * The {@linkplain Probe#setBeforeTagTrap(SyntaxTagTrap) Tag Trap}, which is built directly into the
+ * Instrumentation Framework, does the same thing more efficiently, but there may only be one Tag
+ * Trap active at a time. Any number of tag breakpoints may coexist with the Tag Trap, but it would
+ * be confusing to have a Tag Breakpoint set for the same Tag as the current Tag Trap.
+ * <p>
+ * Notes:
+ * <ol>
+ * <li>Only one Tag Breakpoint can be active for a specific {@linkplain SyntaxTag Tag}.</li>
+ * <li>A newly created breakpoint looks for probes matching the tag, attaches to them if found by
+ * installing an {@link Instrument}.</li>
+ * <li>When Truffle "splits" or otherwise copies an AST, any attached {@link Instrument} will be
+ * copied along with the rest of the AST and will call back to the same breakpoint.</li>
+ * <li>When notification is received that the breakpoint's Tag has been newly added to a Node, then
+ * the breakpoint will attach a new Instrument at the probe to activate the breakpoint at that
+ * location.</li>
+ * <li>A breakpoint may have multiple Instruments deployed, one attached to each Probe that holds
+ * the breakpoint's tag; this might happen when a source is reloaded.</li>
+ * </ol>
+ */
+final class TagBreakpointFactory {
+
+    private static final boolean TRACE = false;
+    private static final PrintStream OUT = System.out;
+
+    private static final String BREAKPOINT_NAME = "TAG BREAKPOINT";
+
+    private static void trace(String format, Object... args) {
+        if (TRACE) {
+            OUT.println(String.format("%s: %s", BREAKPOINT_NAME, String.format(format, args)));
+        }
+    }
+
+    private static final Comparator<Entry<SyntaxTag, TagBreakpointImpl>> BREAKPOINT_COMPARATOR = new Comparator<Entry<SyntaxTag, TagBreakpointImpl>>() {
+
+        @Override
+        public int compare(Entry<SyntaxTag, TagBreakpointImpl> entry1, Entry<SyntaxTag, TagBreakpointImpl> entry2) {
+            return entry1.getKey().name().compareTo(entry2.getKey().name());
+        }
+    };
+
+    private final Debugger executionSupport;
+    private final BreakpointCallback breakpointCallback;
+    private final WarningLog warningLog;
+
+    /**
+     * Map: Tags ==> Tag Breakpoints. There may be no more than one breakpoint per Tag.
+     */
+    private final Map<SyntaxTag, TagBreakpointImpl> tagToBreakpoint = new HashMap<>();
+
+    /**
+     * Globally suspends all line breakpoint activity when {@code false}, ignoring whether
+     * individual breakpoints are enabled.
+     */
+    @CompilationFinal private boolean breakpointsActive = true;
+    private final CyclicAssumption breakpointsActiveUnchanged = new CyclicAssumption(BREAKPOINT_NAME + " globally active");
+
+    TagBreakpointFactory(Debugger executionSupport, BreakpointCallback breakpointCallback, final WarningLog warningLog) {
+        this.executionSupport = executionSupport;
+        this.breakpointCallback = breakpointCallback;
+        this.warningLog = warningLog;
+
+        Probe.addProbeListener(new DefaultProbeListener() {
+
+            @Override
+            public void probeTaggedAs(Probe probe, SyntaxTag tag, Object tagValue) {
+                final TagBreakpointImpl breakpoint = tagToBreakpoint.get(tag);
+                if (breakpoint != null) {
+                    try {
+                        breakpoint.attach(probe);
+                    } catch (IOException e) {
+                        warningLog.addWarning(BREAKPOINT_NAME + " failure attaching to newly tagged Probe: " + e.getMessage());
+                        if (TRACE) {
+                            OUT.println(BREAKPOINT_NAME + " failure: " + e.getMessage());
+                        }
+                    }
+                }
+            }
+        });
+    }
+
+    /**
+     * Globally enables tag breakpoint activity; all breakpoints are ignored when set to
+     * {@code false}. When set to {@code true}, the enabled/disabled status of each breakpoint
+     * determines whether it will trigger when flow of execution reaches it.
+     *
+     * @param breakpointsActive
+     */
+    void setActive(boolean breakpointsActive) {
+        if (this.breakpointsActive != breakpointsActive) {
+            breakpointsActiveUnchanged.invalidate();
+            this.breakpointsActive = breakpointsActive;
+        }
+    }
+
+    /**
+     * Gets all current tag breakpoints,regardless of status; sorted and modification safe.
+     */
+    List<TagBreakpoint> getAll() {
+        ArrayList<Entry<SyntaxTag, TagBreakpointImpl>> entries = new ArrayList<>(tagToBreakpoint.entrySet());
+        Collections.sort(entries, BREAKPOINT_COMPARATOR);
+
+        final ArrayList<TagBreakpoint> breakpoints = new ArrayList<>(entries.size());
+        for (Entry<SyntaxTag, TagBreakpointImpl> entry : entries) {
+            breakpoints.add(entry.getValue());
+        }
+        return breakpoints;
+    }
+
+    /**
+     * Creates a new tag breakpoint if one doesn't already exist. If one does exist, then resets the
+     * <em>ignore count</em>.
+     *
+     * @param tag where to set the breakpoint
+     * @param ignoreCount number of initial hits before the breakpoint starts causing breaks.
+     * @param oneShot whether the breakpoint should dispose itself after one hit
+     * @return a possibly new breakpoint
+     * @throws IOException if a breakpoint already exists for the tag and the ignore count is the
+     *             same
+     */
+    TagBreakpoint create(int ignoreCount, SyntaxTag tag, boolean oneShot) throws IOException {
+
+        TagBreakpointImpl breakpoint = tagToBreakpoint.get(tag);
+
+        if (breakpoint == null) {
+            breakpoint = new TagBreakpointImpl(ignoreCount, tag, oneShot);
+
+            if (TRACE) {
+                trace("NEW " + breakpoint.getShortDescription());
+            }
+
+            tagToBreakpoint.put(tag, breakpoint);
+
+            for (Probe probe : Probe.findProbesTaggedAs(tag)) {
+                breakpoint.attach(probe);
+            }
+        } else {
+            if (ignoreCount == breakpoint.getIgnoreCount()) {
+                throw new IOException(BREAKPOINT_NAME + " already set for tag " + tag.name());
+            }
+            breakpoint.setIgnoreCount(ignoreCount);
+            if (TRACE) {
+                trace("CHANGED ignoreCount %s", breakpoint.getShortDescription());
+            }
+        }
+        return breakpoint;
+    }
+
+    /**
+     * Returns the {@link TagBreakpoint} for a given tag, {@code null} if none.
+     */
+    TagBreakpoint get(SyntaxTag tag) {
+        return tagToBreakpoint.get(tag);
+    }
+
+    /**
+     * Removes the associated instrumentation for all one-shot breakpoints only.
+     */
+    void disposeOneShots() {
+        List<TagBreakpointImpl> breakpoints = new ArrayList<>(tagToBreakpoint.values());
+        for (TagBreakpointImpl breakpoint : breakpoints) {
+            if (breakpoint.isOneShot()) {
+                breakpoint.dispose();
+            }
+        }
+    }
+
+    /**
+     * Removes all knowledge of a breakpoint, presumed disposed.
+     */
+    private void forget(TagBreakpointImpl breakpoint) {
+        tagToBreakpoint.remove(breakpoint.getTag());
+    }
+
+    /**
+     * Concrete representation of a line breakpoint, implemented by attaching an instrument to a
+     * probe at the designated source location.
+     */
+    private final class TagBreakpointImpl extends TagBreakpoint implements AdvancedInstrumentResultListener {
+
+        private static final String SHOULD_NOT_HAPPEN = "TagBreakpointImpl:  should not happen";
+
+        private final SyntaxTag tag;
+
+        // Cached assumption that the global status of tag breakpoint activity has not changed.
+        private Assumption breakpointsActiveAssumption;
+
+        // Whether this breakpoint is enable/disabled
+        @CompilationFinal private boolean isEnabled;
+        private Assumption enabledUnchangedAssumption;
+
+        private String conditionExpr;
+
+        /**
+         * The instrument(s) that this breakpoint currently has attached to a {@link Probe}:
+         * {@code null} if not attached.
+         */
+        private List<Instrument> instruments = new ArrayList<>();
+
+        private TagBreakpointImpl(int ignoreCount, SyntaxTag tag, boolean oneShot) {
+            super(ENABLED, ignoreCount, oneShot);
+            this.tag = tag;
+            this.breakpointsActiveAssumption = TagBreakpointFactory.this.breakpointsActiveUnchanged.getAssumption();
+            this.isEnabled = true;
+            this.enabledUnchangedAssumption = Truffle.getRuntime().createAssumption(BREAKPOINT_NAME + " enabled state unchanged");
+        }
+
+        @Override
+        public boolean isEnabled() {
+            return isEnabled;
+        }
+
+        @Override
+        public void setEnabled(boolean enabled) {
+            // Tag Breakpoints are never unresolved
+            if (enabled != isEnabled) {
+                switch (getState()) {
+                    case ENABLED:
+                        assert !enabled : SHOULD_NOT_HAPPEN;
+                        doSetEnabled(false);
+                        changeState(DISABLED);
+                        break;
+                    case DISABLED:
+                        assert enabled : SHOULD_NOT_HAPPEN;
+                        doSetEnabled(true);
+                        changeState(ENABLED);
+                        break;
+                    case DISPOSED:
+                        assert false : "breakpoint disposed";
+                        break;
+                    case ENABLED_UNRESOLVED:
+                    case DISABLED_UNRESOLVED:
+                    default:
+                        assert false : SHOULD_NOT_HAPPEN;
+                        break;
+                }
+            }
+        }
+
+        @Override
+        public void setCondition(String expr) throws IOException {
+            if (this.conditionExpr != null || expr != null) {
+                // De-instrument the Probes instrumented by this breakpoint
+                final ArrayList<Probe> probes = new ArrayList<>();
+                for (Instrument instrument : instruments) {
+                    probes.add(instrument.getProbe());
+                    instrument.dispose();
+                }
+                instruments.clear();
+                this.conditionExpr = expr;
+                // Re-instrument the probes previously instrumented
+                for (Probe probe : probes) {
+                    attach(probe);
+                }
+            }
+        }
+
+        @Override
+        public String getCondition() {
+            return conditionExpr;
+        }
+
+        @Override
+        public void dispose() {
+            if (getState() != DISPOSED) {
+                for (Instrument instrument : instruments) {
+                    instrument.dispose();
+                }
+                changeState(DISPOSED);
+                TagBreakpointFactory.this.forget(this);
+            }
+        }
+
+        private void attach(Probe newProbe) throws IOException {
+            if (getState() == DISPOSED) {
+                throw new IllegalStateException("Attempt to attach a disposed " + BREAKPOINT_NAME);
+            }
+            Instrument newInstrument = null;
+            if (conditionExpr == null) {
+                newInstrument = Instrument.create(new UnconditionalTagBreakInstrumentListener(), BREAKPOINT_NAME);
+            } else {
+                newInstrument = Instrument.create(this, executionSupport.createAdvancedInstrumentRootFactory(newProbe, conditionExpr, this), Boolean.class, BREAKPOINT_NAME);
+            }
+            newProbe.attach(newInstrument);
+            instruments.add(newInstrument);
+            changeState(isEnabled ? ENABLED : DISABLED);
+        }
+
+        private void doSetEnabled(boolean enabled) {
+            if (this.isEnabled != enabled) {
+                enabledUnchangedAssumption.invalidate();
+                this.isEnabled = enabled;
+            }
+        }
+
+        private String getShortDescription() {
+            return BREAKPOINT_NAME + "@" + tag.name();
+        }
+
+        private void changeState(State after) {
+            if (TRACE) {
+                trace("STATE %s-->%s %s", getState().getName(), after.getName(), getShortDescription());
+            }
+            setState(after);
+        }
+
+        private void doBreak(Node node, VirtualFrame vFrame) {
+            if (incrHitCountCheckIgnore()) {
+                breakpointCallback.haltedAt(node, vFrame.materialize(), BREAKPOINT_NAME);
+            }
+        }
+
+        /**
+         * Receives notification from the attached instrument that execution is about to enter node
+         * where the breakpoint is set. Designed so that when in the fast path, there is either an
+         * unconditional "halt" call to the debugger or nothing.
+         */
+        private void nodeEnter(Node astNode, VirtualFrame vFrame) {
+
+            // Deopt if the global active/inactive flag has changed
+            try {
+                this.breakpointsActiveAssumption.check();
+            } catch (InvalidAssumptionException ex) {
+                this.breakpointsActiveAssumption = TagBreakpointFactory.this.breakpointsActiveUnchanged.getAssumption();
+            }
+
+            // Deopt if the enabled/disabled state of this breakpoint has changed
+            try {
+                this.enabledUnchangedAssumption.check();
+            } catch (InvalidAssumptionException ex) {
+                this.enabledUnchangedAssumption = Truffle.getRuntime().createAssumption("LineBreakpoint enabled state unchanged");
+            }
+
+            if (TagBreakpointFactory.this.breakpointsActive && this.isEnabled) {
+                if (isOneShot()) {
+                    dispose();
+                }
+                TagBreakpointImpl.this.doBreak(astNode, vFrame);
+            }
+
+        }
+
+        public void notifyResult(Node node, VirtualFrame vFrame, Object result) {
+            final boolean condition = (Boolean) result;
+            if (TRACE) {
+                trace("breakpoint condition = %b  %s", condition, getShortDescription());
+            }
+            if (condition) {
+                nodeEnter(node, vFrame);
+            }
+        }
+
+        public void notifyFailure(Node node, VirtualFrame vFrame, RuntimeException ex) {
+            warningLog.addWarning(String.format("Exception in %s:  %s", getShortDescription(), ex.getMessage()));
+            if (TRACE) {
+                trace("breakpoint failure = %s  %s", ex.toString(), getShortDescription());
+            }
+            // Take the breakpoint if evaluation fails.
+            nodeEnter(node, vFrame);
+        }
+
+        @Override
+        public String getLocationDescription() {
+            return "Tag " + tag.name();
+        }
+
+        @Override
+        public SyntaxTag getTag() {
+            return tag;
+        }
+
+        private final class UnconditionalTagBreakInstrumentListener extends DefaultStandardInstrumentListener {
+
+            @Override
+            public void enter(Probe probe, Node node, VirtualFrame vFrame) {
+                TagBreakpointImpl.this.nodeEnter(node, vFrame);
+            }
+        }
+
+    }
+
+}
--- a/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/package-info.java	Thu Jul 16 19:11:31 2015 +0200
+++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/package-info.java	Sat Jul 18 18:03:36 2015 +0200
@@ -1,35 +1,31 @@
 /*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ * 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 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
+ * 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.
+ * 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.
+ * 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.
  */
 
 /**
  * Representation of a {@link com.oracle.truffle.api.frame.Frame stack frame}. While
- * {@link com.oracle.truffle.api.TruffleLanguage based language}
- * is executing its stack parameters
- * and local variables are represented by {@link com.oracle.truffle.api.frame.VirtualFrame}. Such a frame
- * can be converted into {@link com.oracle.truffle.api.frame.MaterializedFrame} stored on a heap for
- * later access when the actual stack is elsewhere.
+ * {@link com.oracle.truffle.api.TruffleLanguage based language} is executing its stack parameters
+ * and local variables are represented by {@link com.oracle.truffle.api.frame.VirtualFrame}. Such a
+ * frame can be converted into {@link com.oracle.truffle.api.frame.MaterializedFrame} stored on a
+ * heap for later access when the actual stack is elsewhere.
  */
 package com.oracle.truffle.api.frame;
 
--- a/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/Accessor.java	Thu Jul 16 19:11:31 2015 +0200
+++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/Accessor.java	Sat Jul 18 18:03:36 2015 +0200
@@ -31,6 +31,8 @@
 import com.oracle.truffle.api.*;
 import com.oracle.truffle.api.debug.*;
 import com.oracle.truffle.api.instrument.*;
+import com.oracle.truffle.api.nodes.Node;
+import com.oracle.truffle.api.nodes.RootNode;
 import com.oracle.truffle.api.source.*;
 import com.oracle.truffle.api.vm.*;
 
@@ -40,6 +42,10 @@
 public abstract class Accessor {
     private static Accessor API;
     private static Accessor SPI;
+    private static Accessor NODES;
+    private static Accessor INSTRUMENT;
+    private static Accessor DEBUG;
+
     static {
         TruffleLanguage lng = new TruffleLanguage(null) {
             @Override
@@ -73,6 +79,14 @@
             }
         };
         lng.hashCode();
+        new Node(null) {
+        }.getRootNode();
+
+        try {
+            Class.forName(Debugger.class.getName(), true, Debugger.class.getClassLoader());
+        } catch (ClassNotFoundException ex) {
+            throw new IllegalStateException(ex);
+        }
     }
 
     protected Accessor() {
@@ -81,6 +95,21 @@
                 throw new IllegalStateException();
             }
             API = this;
+        } else if (this.getClass().getSimpleName().endsWith("Nodes")) {
+            if (NODES != null) {
+                throw new IllegalStateException();
+            }
+            NODES = this;
+        } else if (this.getClass().getSimpleName().endsWith("Instrument")) {
+            if (INSTRUMENT != null) {
+                throw new IllegalStateException();
+            }
+            INSTRUMENT = this;
+        } else if (this.getClass().getSimpleName().endsWith("Debug")) {
+            if (DEBUG != null) {
+                throw new IllegalStateException();
+            }
+            DEBUG = this;
         } else {
             if (SPI != null) {
                 throw new IllegalStateException();
@@ -117,16 +146,36 @@
         return API.getDebugSupport(l);
     }
 
-    protected Object invoke(Object obj, Object[] args) throws IOException {
+    protected Object invoke(TruffleLanguage lang, Object obj, Object[] args) throws IOException {
         for (SymbolInvoker si : ServiceLoader.load(SymbolInvoker.class)) {
-            return si.invoke(obj, args);
+            return si.invoke(lang, obj, args);
         }
         throw new IOException("No symbol invoker found!");
     }
 
+    protected Class<? extends TruffleLanguage> findLanguage(RootNode n) {
+        return NODES.findLanguage(n);
+    }
+
+    protected Class<? extends TruffleLanguage> findLanguage(Probe probe) {
+        return INSTRUMENT.findLanguage(probe);
+    }
+
+    protected TruffleLanguage findLanguage(TruffleVM vm, Class<? extends TruffleLanguage> languageClass) {
+        return API.findLanguage(vm, languageClass);
+    }
+
+    protected Closeable executionStart(TruffleVM vm, Debugger[] fillIn, Source s) {
+        return DEBUG.executionStart(vm, fillIn, s);
+    }
+
+    protected void dispatchEvent(TruffleVM vm, Object event) {
+        SPI.dispatchEvent(vm, event);
+    }
+
     /**
      * Don't call me. I am here only to let NetBeans debug any Truffle project.
-     * 
+     *
      * @param args
      */
     public static void main(String... args) {
--- a/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/SymbolInvoker.java	Thu Jul 16 19:11:31 2015 +0200
+++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/SymbolInvoker.java	Sat Jul 18 18:03:36 2015 +0200
@@ -24,6 +24,7 @@
  */
 package com.oracle.truffle.api.impl;
 
+import com.oracle.truffle.api.TruffleLanguage;
 import java.io.*;
 
 /**
@@ -31,5 +32,5 @@
  * associated nodes too much.
  */
 public abstract class SymbolInvoker {
-    protected abstract Object invoke(Object symbol, Object... args) throws IOException;
+    protected abstract Object invoke(TruffleLanguage lang, Object symbol, Object... args) throws IOException;
 }
--- a/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/Instrument.java	Thu Jul 16 19:11:31 2015 +0200
+++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/Instrument.java	Sat Jul 18 18:03:36 2015 +0200
@@ -42,8 +42,8 @@
  * </ol>
  * <p>
  * Client-oriented documentation for the use of Instruments is available online at <a
- * HREF="https://wiki.openjdk.java.net/display/Graal/Listening+for+Execution+Events"
- * >https://wiki.openjdk.java.net/display/Graal/Listening+for+Execution+Events</a>
+ * HREF="https://wiki.openjdk.java.net/display/Graal/Listening+for+Execution+Events" >https://
+ * wiki.openjdk.java.net/display/Graal/Listening+for+Execution+Events</a>
  * <p>
  * The implementation of Instruments is complicated by the requirement that Truffle be able to clone
  * ASTs at any time. In particular, any instrumentation-supporting Nodes that have been attached to
--- a/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/Probe.java	Thu Jul 16 19:11:31 2015 +0200
+++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/Probe.java	Sat Jul 18 18:03:36 2015 +0200
@@ -30,6 +30,7 @@
 
 import com.oracle.truffle.api.*;
 import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
+import com.oracle.truffle.api.impl.Accessor;
 import com.oracle.truffle.api.instrument.InstrumentationNode.TruffleEvents;
 import com.oracle.truffle.api.nodes.*;
 import com.oracle.truffle.api.source.*;
@@ -47,8 +48,8 @@
  * </ol>
  * <p>
  * Client-oriented documentation for the use of Probes is available online at <a
- * HREF="https://wiki.openjdk.java.net/display/Graal/Finding+Probes"
- * >https://wiki.openjdk.java.net/display/Graal/Finding+Probes</a>
+ * HREF="https://wiki.openjdk.java.net/display/Graal/Finding+Probes" >https://wiki.openjdk.java.
+ * net/display/Graal/Finding+Probes</a>
  * <p>
  * <h4>Implementation notes:</h4>
  * <p>
@@ -100,6 +101,7 @@
  * @see SyntaxTag
  */
 public final class Probe {
+    private final Class<? extends TruffleLanguage> language;
 
     private static final boolean TRACE = false;
     private static final String TRACE_PREFIX = "PROBE: ";
@@ -303,7 +305,7 @@
     /**
      * Intended for use only by {@link ProbeNode}.
      */
-    Probe(ProbeNode probeNode, SourceSection sourceSection) {
+    Probe(Class<? extends TruffleLanguage> l, ProbeNode probeNode, SourceSection sourceSection) {
         this.sourceSection = sourceSection;
         probes.add(new WeakReference<>(this));
         registerProbeNodeClone(probeNode);
@@ -314,6 +316,7 @@
         for (ProbeListener listener : probeListeners) {
             listener.newProbeInserted(this);
         }
+        this.language = l;
     }
 
     /**
@@ -483,4 +486,18 @@
         sb.append("]");
         return sb.toString();
     }
+
+    static final class AccessorInstrument extends Accessor {
+        @Override
+        protected Class<? extends TruffleLanguage> findLanguage(RootNode n) {
+            return super.findLanguage(n);
+        }
+
+        @Override
+        protected Class<? extends TruffleLanguage> findLanguage(Probe probe) {
+            return probe.language;
+        }
+    }
+
+    static final AccessorInstrument ACCESSOR = new AccessorInstrument();
 }
--- a/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/ProbeNode.java	Thu Jul 16 19:11:31 2015 +0200
+++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/ProbeNode.java	Sat Jul 18 18:03:36 2015 +0200
@@ -26,6 +26,7 @@
 
 import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
+import com.oracle.truffle.api.TruffleLanguage;
 import com.oracle.truffle.api.frame.*;
 import com.oracle.truffle.api.instrument.Instrument.AbstractInstrumentNode;
 import com.oracle.truffle.api.instrument.InstrumentationNode.TruffleEvents;
@@ -120,7 +121,8 @@
     public static Probe insertProbe(WrapperNode wrapper) {
         final SourceSection sourceSection = wrapper.getChild().getSourceSection();
         final ProbeNode probeNode = new ProbeNode(); // private constructor
-        probeNode.probe = new Probe(probeNode, sourceSection);  // package private access
+        Class<? extends TruffleLanguage> l = Probe.ACCESSOR.findLanguage(wrapper.getChild().getRootNode());
+        probeNode.probe = new Probe(l, probeNode, sourceSection);  // package private access
         wrapper.insertProbe(probeNode);
         return probeNode.probe;
     }
--- a/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/package-info.java	Thu Jul 16 19:11:31 2015 +0200
+++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/package-info.java	Sat Jul 18 18:03:36 2015 +0200
@@ -1,26 +1,23 @@
 /*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ * 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 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
+ * 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.
+ * 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.
+ * 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.
  */
 
 /**
--- a/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/GraphPrintVisitor.java	Thu Jul 16 19:11:31 2015 +0200
+++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/GraphPrintVisitor.java	Sat Jul 18 18:03:36 2015 +0200
@@ -245,7 +245,7 @@
     protected void setNodeProperty(Object node, String propertyName, Object value) {
         Element nodeElem = getElementByObject(node);
         Element propElem = getPropertyElement(node, propertyName); // if property exists, replace
-                                                                   // its value
+        // its value
         if (null == propElem) { // if property doesn't exist, create one
             propElem = dom.createElement("p");
             propElem.setAttribute("name", propertyName);
--- a/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/Node.java	Thu Jul 16 19:11:31 2015 +0200
+++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/Node.java	Sat Jul 18 18:03:36 2015 +0200
@@ -30,6 +30,7 @@
 
 import com.oracle.truffle.api.*;
 import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
+import com.oracle.truffle.api.impl.Accessor;
 import com.oracle.truffle.api.instrument.*;
 import com.oracle.truffle.api.instrument.ProbeNode.WrapperNode;
 import com.oracle.truffle.api.source.*;
@@ -39,7 +40,6 @@
  * Abstract base class for all Truffle nodes.
  */
 public abstract class Node implements NodeInterface, Cloneable {
-
     private final NodeClass nodeClass;
     @CompilationFinal private Node parent;
     @CompilationFinal private SourceSection sourceSection;
@@ -587,4 +587,14 @@
         IN_ATOMIC_BLOCK.set(IN_ATOMIC_BLOCK.get() - 1);
         return true;
     }
+
+    private static final class AccessorNodes extends Accessor {
+        @Override
+        protected Class<? extends TruffleLanguage> findLanguage(RootNode n) {
+            return n.language;
+        }
+    }
+
+    // registers into Accessor.NODES
+    @SuppressWarnings("unused") private static final AccessorNodes ACCESSOR = new AccessorNodes();
 }
--- a/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/RootNode.java	Thu Jul 16 19:11:31 2015 +0200
+++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/RootNode.java	Sat Jul 18 18:03:36 2015 +0200
@@ -37,20 +37,57 @@
  * {@link TruffleRuntime#createCallTarget(RootNode)}.
  */
 public abstract class RootNode extends Node {
-
+    final Class<? extends TruffleLanguage> language;
     private RootCallTarget callTarget;
     @CompilationFinal private FrameDescriptor frameDescriptor;
 
+    /**
+     * @deprecated each RootNode should be associated with a {@link TruffleLanguage} use constructor
+     *             that allows you to specify it. This method will be removed on Aug 15, 2015.
+     */
+    @Deprecated
     protected RootNode() {
-        this(null, null);
+        this(null, null, null, false);
+    }
+
+    /**
+     * @deprecated each RootNode should be associated with a {@link TruffleLanguage} use constructor
+     *             that allows you to specify it. This method will be removed on Aug 15, 2015.
+     */
+    @Deprecated
+    protected RootNode(SourceSection sourceSection) {
+        this(null, sourceSection, null, false);
     }
 
-    protected RootNode(SourceSection sourceSection) {
-        this(sourceSection, null);
+    /**
+     * @deprecated each RootNode should be associated with a {@link TruffleLanguage} use constructor
+     *             that allows you to specify it. This method will be removed on Aug 15, 2015.
+     */
+    @Deprecated
+    protected RootNode(SourceSection sourceSection, FrameDescriptor frameDescriptor) {
+        this(null, sourceSection, frameDescriptor, false);
     }
 
-    protected RootNode(SourceSection sourceSection, FrameDescriptor frameDescriptor) {
+    /**
+     * Creates new root node. Each {@link RootNode} is associated with a particular language - if
+     * the root node represents a method it is assumed the method is written in such language.
+     *
+     * @param language the language of the node, <b>cannot be</b> <code>null</code>
+     * @param sourceSection a part of source associated with this node, can be <code>null</code>
+     * @param frameDescriptor descriptor of slots, can be <code>null</code>
+     */
+    protected RootNode(Class<? extends TruffleLanguage> language, SourceSection sourceSection, FrameDescriptor frameDescriptor) {
+        this(language, sourceSection, frameDescriptor, true);
+    }
+
+    private RootNode(Class<? extends TruffleLanguage> language, SourceSection sourceSection, FrameDescriptor frameDescriptor, boolean checkLanguage) {
         super(sourceSection);
+        if (checkLanguage) {
+            if (!TruffleLanguage.class.isAssignableFrom(language)) {
+                throw new IllegalStateException();
+            }
+        }
+        this.language = language;
         if (frameDescriptor == null) {
             this.frameDescriptor = new FrameDescriptor();
         } else {
--- a/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/package-info.java	Thu Jul 16 19:11:31 2015 +0200
+++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/package-info.java	Sat Jul 18 18:03:36 2015 +0200
@@ -1,26 +1,23 @@
 /*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ * 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 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
+ * 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.
+ * 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.
+ * 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.
  */
 
 /**
--- a/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/package-info.java	Thu Jul 16 19:11:31 2015 +0200
+++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/package-info.java	Sat Jul 18 18:03:36 2015 +0200
@@ -1,31 +1,28 @@
 /*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ * 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 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
+ * 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.
+ * 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.
+ * 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.
  */
 
 /**
- * Do you want to implement your own {@link com.oracle.truffle.api.TruffleLanguage Truffle based language}?
- * In such case start {@link com.oracle.truffle.api.TruffleLanguage here}.
+ * Do you want to implement your own {@link com.oracle.truffle.api.TruffleLanguage Truffle based
+ * language}? In such case start {@link com.oracle.truffle.api.TruffleLanguage here}.
  */
 package com.oracle.truffle.api;
 
--- a/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/source/package-info.java	Thu Jul 16 19:11:31 2015 +0200
+++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/source/package-info.java	Sat Jul 18 18:03:36 2015 +0200
@@ -1,26 +1,23 @@
 /*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ * 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 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
+ * 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.
+ * 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.
+ * 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.
  */
 
 /**
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/vm/EventConsumer.java	Sat Jul 18 18:03:36 2015 +0200
@@ -0,0 +1,58 @@
+/*
+ * 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.vm;
+
+import com.oracle.truffle.api.TruffleLanguage;
+import com.oracle.truffle.api.debug.ExecutionEvent;
+import com.oracle.truffle.api.debug.SuspendedEvent;
+
+/**
+ * {@link TruffleVM} generates various events and delivers them to
+ * {@link TruffleVM.Builder#onEvent(com.oracle.truffle.api.vm.EventConsumer) registered} handlers.
+ * Each handler is registered for a particular type of event. Examples of events include
+ * {@link ExecutionEvent} or {@link SuspendedEvent} useful when debugging {@link TruffleLanguage
+ * Truffle language}s.
+ *
+ * @param <Event> type of event to observe and handle
+ */
+public abstract class EventConsumer<Event> {
+    final Class<Event> type;
+
+    /**
+     * Creates new handler for specified event type.
+     *
+     * @param eventType type of events to handle
+     */
+    public EventConsumer(Class<Event> eventType) {
+        this.type = eventType;
+    }
+
+    /**
+     * Called by the {@link TruffleVM} when event of requested type appears.
+     *
+     * @param event the instance of an event of the request type
+     */
+    protected abstract void on(Event event);
+}
--- a/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/vm/TruffleVM.java	Thu Jul 16 19:11:31 2015 +0200
+++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/vm/TruffleVM.java	Sat Jul 18 18:03:36 2015 +0200
@@ -63,6 +63,8 @@
     private final Reader in;
     private final Writer err;
     private final Writer out;
+    private final EventConsumer<?>[] handlers;
+    private Debugger debugger;
 
     /**
      * Private & temporary only constructor.
@@ -73,6 +75,7 @@
         this.err = null;
         this.out = null;
         this.langs = null;
+        this.handlers = null;
     }
 
     /**
@@ -82,10 +85,11 @@
      * @param err stderr
      * @param in stdin
      */
-    private TruffleVM(Writer out, Writer err, Reader in) {
+    private TruffleVM(Writer out, Writer err, Reader in, EventConsumer<?>[] handlers) {
         this.out = out;
         this.err = err;
         this.in = in;
+        this.handlers = handlers;
         this.initThread = Thread.currentThread();
         this.langs = new HashMap<>();
         Enumeration<URL> en;
@@ -169,12 +173,13 @@
         private Writer out;
         private Writer err;
         private Reader in;
+        private List<EventConsumer<?>> handlers = new ArrayList<>();
 
         Builder() {
         }
 
         /**
-         * Changes the defaut output for languages running in <em>to be created</em>
+         * Changes the default output for languages running in <em>to be created</em>
          * {@link TruffleVM virtual machine}. The default is to use {@link System#out}.
          *
          * @param w the writer to use as output
@@ -210,6 +215,19 @@
         }
 
         /**
+         * Registers another instance of {@link EventConsumer} into the to be created
+         * {@link TruffleVM}.
+         *
+         * @param handler the handler to register
+         * @return instance of this builder
+         */
+        public Builder onEvent(EventConsumer<?> handler) {
+            handler.getClass();
+            handlers.add(handler);
+            return this;
+        }
+
+        /**
          * Creates the {@link TruffleVM Truffle virtual machine}. The configuration is taken from
          * values passed into configuration methods in this class.
          *
@@ -225,7 +243,7 @@
             if (in == null) {
                 in = new InputStreamReader(System.in);
             }
-            return new TruffleVM(out, err, in);
+            return new TruffleVM(out, err, in, handlers.toArray(new EventConsumer[0]));
         }
     }
 
@@ -273,7 +291,7 @@
         if (l == null) {
             throw new IOException("No language for " + location + " with MIME type " + mimeType + " found. Supported types: " + langs.keySet());
         }
-        return SPI.eval(l, s);
+        return eval(l, s);
     }
 
     /**
@@ -291,7 +309,7 @@
         if (l == null) {
             throw new IOException("No language for MIME type " + mimeType + " found. Supported types: " + langs.keySet());
         }
-        return SPI.eval(l, Source.fromReader(reader, mimeType));
+        return eval(l, Source.fromReader(reader, mimeType));
     }
 
     /**
@@ -309,7 +327,18 @@
         if (l == null) {
             throw new IOException("No language for MIME type " + mimeType + " found. Supported types: " + langs.keySet());
         }
-        return SPI.eval(l, Source.fromText(code, mimeType));
+        return eval(l, Source.fromText(code, mimeType));
+    }
+
+    private Object eval(TruffleLanguage l, Source s) throws IOException {
+        TruffleVM.findDebuggerSupport(l);
+        Debugger[] fillIn = {debugger};
+        try (Closeable d = SPI.executionStart(this, fillIn, s)) {
+            if (debugger == null) {
+                debugger = fillIn[0];
+            }
+            return SPI.eval(l, s);
+        }
     }
 
     /**
@@ -331,12 +360,14 @@
      */
     public Symbol findGlobalSymbol(String globalName) {
         checkThread();
+        TruffleLanguage lang = null;
         Object obj = null;
         Object global = null;
         for (Language dl : langs.values()) {
             TruffleLanguage l = dl.getImpl();
             obj = SPI.findExportedSymbol(l, globalName, true);
             if (obj != null) {
+                lang = l;
                 global = SPI.languageGlobal(l);
                 break;
             }
@@ -346,12 +377,13 @@
                 TruffleLanguage l = dl.getImpl();
                 obj = SPI.findExportedSymbol(l, globalName, false);
                 if (obj != null) {
+                    lang = l;
                     global = SPI.languageGlobal(l);
                     break;
                 }
             }
         }
-        return obj == null ? null : new Symbol(obj, global);
+        return obj == null ? null : new Symbol(lang, obj, global);
     }
 
     private void checkThread() {
@@ -366,15 +398,46 @@
         return l == null ? null : l.getImpl();
     }
 
+    @SuppressWarnings("all")
+    void dispatch(Object ev) {
+        Class type = ev.getClass();
+        if (type == SuspendedEvent.class) {
+            dispatchSuspendedEvent((SuspendedEvent) ev);
+        }
+        if (type == ExecutionEvent.class) {
+            dispatchExecutionEvent((ExecutionEvent) ev);
+        }
+        dispatch(type, ev);
+    }
+
+    @SuppressWarnings("unused")
+    void dispatchSuspendedEvent(SuspendedEvent event) {
+    }
+
+    @SuppressWarnings("unused")
+    void dispatchExecutionEvent(ExecutionEvent event) {
+    }
+
+    @SuppressWarnings("all")
+    <Event> void dispatch(Class<Event> type, Event event) {
+        for (EventConsumer handler : handlers) {
+            if (handler.type == type) {
+                handler.on(event);
+            }
+        }
+    }
+
     /**
      * Represents {@link TruffleVM#findGlobalSymbol(java.lang.String) global symbol} provided by one
      * of the initialized languages in {@link TruffleVM Truffle virtual machine}.
      */
     public class Symbol {
+        private final TruffleLanguage language;
         private final Object obj;
         private final Object global;
 
-        Symbol(Object obj, Object global) {
+        Symbol(TruffleLanguage language, Object obj, Object global) {
+            this.language = language;
             this.obj = obj;
             this.global = global;
         }
@@ -392,16 +455,22 @@
          * @throws IOException signals problem during execution
          */
         public Object invoke(Object thiz, Object... args) throws IOException {
-            List<Object> arr = new ArrayList<>();
-            if (thiz == null) {
-                if (global != null) {
-                    arr.add(global);
+            Debugger[] fillIn = {debugger};
+            try (Closeable c = SPI.executionStart(TruffleVM.this, fillIn, null)) {
+                if (debugger == null) {
+                    debugger = fillIn[0];
                 }
-            } else {
-                arr.add(thiz);
+                List<Object> arr = new ArrayList<>();
+                if (thiz == null) {
+                    if (global != null) {
+                        arr.add(global);
+                    }
+                } else {
+                    arr.add(thiz);
+                }
+                arr.addAll(Arrays.asList(args));
+                return SPI.invoke(language, obj, arr.toArray());
             }
-            arr.addAll(Arrays.asList(args));
-            return SPI.invoke(obj, arr.toArray());
         }
     }
 
@@ -472,14 +541,6 @@
             return shortName;
         }
 
-        public ToolSupportProvider getToolSupport() {
-            return SPI.getToolSupport(getImpl());
-        }
-
-        public DebugSupportProvider getDebugSupport() {
-            return SPI.getDebugSupport(getImpl());
-        }
-
         TruffleLanguage getImpl() {
             if (impl == null) {
                 String n = props.getProperty(prefix + "className");
@@ -500,6 +561,25 @@
         }
     } // end of Language
 
+    //
+    // Accessor helper methods
+    //
+
+    TruffleLanguage findLanguage(Probe probe) {
+        Class<? extends TruffleLanguage> languageClazz = SPI.findLanguage(probe);
+        for (Map.Entry<String, Language> entrySet : langs.entrySet()) {
+            Language languageDescription = entrySet.getValue();
+            if (languageClazz.isInstance(languageDescription.impl)) {
+                return languageDescription.impl;
+            }
+        }
+        throw new IllegalStateException("Cannot find language " + languageClazz + " among " + langs);
+    }
+
+    static DebugSupportProvider findDebuggerSupport(TruffleLanguage l) {
+        return SPI.getDebugSupport(l);
+    }
+
     private static class SPIAccessor extends Accessor {
         @Override
         public Object importSymbol(TruffleVM vm, TruffleLanguage ownLang, String globalName) {
@@ -548,8 +628,8 @@
         }
 
         @Override
-        public Object invoke(Object obj, Object[] args) throws IOException {
-            return super.invoke(obj, args);
+        protected Object invoke(TruffleLanguage lang, Object obj, Object[] args) throws IOException {
+            return super.invoke(lang, obj, args);
         }
 
         @Override
@@ -561,5 +641,20 @@
         public DebugSupportProvider getDebugSupport(TruffleLanguage l) {
             return super.getDebugSupport(l);
         }
+
+        @Override
+        protected Class<? extends TruffleLanguage> findLanguage(Probe probe) {
+            return super.findLanguage(probe);
+        }
+
+        @Override
+        protected Closeable executionStart(TruffleVM aThis, Debugger[] fillIn, Source s) {
+            return super.executionStart(aThis, fillIn, s);
+        }
+
+        @Override
+        protected void dispatchEvent(TruffleVM vm, Object event) {
+            vm.dispatch(event);
+        }
     } // end of SPIAccessor
 }
--- a/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/vm/package-info.java	Thu Jul 16 19:11:31 2015 +0200
+++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/vm/package-info.java	Sat Jul 18 18:03:36 2015 +0200
@@ -1,31 +1,28 @@
 /*
- * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ * 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 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
+ * 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.
+ * 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.
+ * 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.
  */
 
 /**
- * Central place to create and control {@link com.oracle.truffle.api.vm.TruffleVM Truffle Virtual Machine}
- * and all languages hosted in it.
+ * Central place to create and control {@link com.oracle.truffle.api.vm.TruffleVM Truffle Virtual
+ * Machine} and all languages hosted in it.
  */
 package com.oracle.truffle.api.vm;
 
--- a/truffle/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/expression/DSLExpressionResolver.java	Thu Jul 16 19:11:31 2015 +0200
+++ b/truffle/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/expression/DSLExpressionResolver.java	Sat Jul 18 18:03:36 2015 +0200
@@ -187,8 +187,8 @@
                     sep = ", ";
                 }
                 // name mismatch
-                throw new InvalidExpressionException(String.format("The method %s in the type %s is not applicable for the arguments %s.", //
-                                ElementUtils.getReadableSignature(foundWithName), //
+                throw new InvalidExpressionException(String.format("The method %s in the type %s is not applicable for the arguments %s.",   //
+                                ElementUtils.getReadableSignature(foundWithName),   //
                                 ElementUtils.getSimpleName((TypeElement) foundWithName.getEnclosingElement()), arguments.toString()));
             }
         }
--- a/truffle/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/NodeGenFactory.java	Thu Jul 16 19:11:31 2015 +0200
+++ b/truffle/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/NodeGenFactory.java	Sat Jul 18 18:03:36 2015 +0200
@@ -972,7 +972,7 @@
     private List<SpecializationData> calculateReachableSpecializations() {
         List<SpecializationData> specializations = new ArrayList<>();
         for (SpecializationData specialization : node.getSpecializations()) {
-            if (specialization.isReachable() && //
+            if (specialization.isReachable() &&   //
                             (specialization.isSpecialized() //
                             || (specialization.isFallback() && optimizeFallback(specialization)))) {
                 specializations.add(specialization);
@@ -1233,7 +1233,7 @@
             if (limitExpression == null) {
                 limitExpressionTree = CodeTreeBuilder.singleString("3");
             } else {
-                limitExpressionTree = DSLExpressionGenerator.write(limitExpression, accessParent(null), //
+                limitExpressionTree = DSLExpressionGenerator.write(limitExpression, accessParent(null),   //
                                 castBoundTypes(bindExpressionValues(limitExpression, specialization, currentValues)));
             }
 
--- a/truffle/com.oracle.truffle.object/src/com/oracle/truffle/object/debug/ShapeProfiler.java	Thu Jul 16 19:11:31 2015 +0200
+++ b/truffle/com.oracle.truffle.object/src/com/oracle/truffle/object/debug/ShapeProfiler.java	Sat Jul 18 18:03:36 2015 +0200
@@ -204,6 +204,7 @@
     }
 
     private static final ShapeProfiler shapeProf;
+
     static {
         if (ObjectStorageOptions.Profile) {
             shapeProf = new ShapeProfiler();
--- a/truffle/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/instrument/SLInstrumentTestRunner.java	Thu Jul 16 19:11:31 2015 +0200
+++ b/truffle/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/instrument/SLInstrumentTestRunner.java	Sat Jul 18 18:03:36 2015 +0200
@@ -56,12 +56,9 @@
 
 import com.oracle.truffle.api.instrument.*;
 import com.oracle.truffle.api.instrument.impl.*;
-import com.oracle.truffle.api.source.*;
-import com.oracle.truffle.sl.factory.*;
+import com.oracle.truffle.api.vm.*;
 import com.oracle.truffle.sl.nodes.instrument.*;
 import com.oracle.truffle.sl.nodes.local.*;
-import com.oracle.truffle.sl.parser.*;
-import com.oracle.truffle.sl.runtime.*;
 import com.oracle.truffle.sl.test.instrument.SLInstrumentTestRunner.InstrumentTestCase;
 
 /**
@@ -80,7 +77,6 @@
     private static final String ASSIGNMENT_VALUE_SUFFIX = "_assnCount";
 
     private static final String LF = System.getProperty("line.separator");
-    private static SLContext slContext;
 
     static class InstrumentTestCase {
         protected final Description name;
@@ -227,10 +223,10 @@
             // We use the name of the file to determine what visitor to attach to it.
             if (testCase.baseName.endsWith(ASSIGNMENT_VALUE_SUFFIX)) {
                 // Set up the execution context for Simple and register our two listeners
-                slContext = SLContextFactory.create(new BufferedReader(new StringReader(testCase.testInput)), printer);
+                TruffleVM vm = TruffleVM.newVM().stdIn(new BufferedReader(new StringReader(testCase.testInput))).stdOut(printer).build();
 
-                final Source source = Source.fromText(readAllLines(testCase.path), testCase.sourceName);
-                Parser.parseSL(slContext, source);
+                final String src = readAllLines(testCase.path);
+                vm.eval("application/x-sl", src);
 
                 // Attach an instrument to every probe tagged as an assignment
                 for (Probe probe : Probe.findProbesTaggedAs(StandardSyntaxTag.ASSIGNMENT)) {
@@ -238,8 +234,8 @@
                     probe.attach(Instrument.create(slPrintAssigmentValueListener, "SL print assignment value"));
                 }
 
-                SLFunction main = slContext.getFunctionRegistry().lookup("main");
-                main.getCallTarget().call();
+                TruffleVM.Symbol main = vm.findGlobalSymbol("main");
+                main.invoke(null);
             } else {
                 notifier.fireTestFailure(new Failure(testCase.name, new UnsupportedOperationException("No instrumentation found.")));
             }
--- a/truffle/com.oracle.truffle.sl.tools/src/com/oracle/truffle/sl/tools/debug/SLREPLHandler.java	Thu Jul 16 19:11:31 2015 +0200
+++ b/truffle/com.oracle.truffle.sl.tools/src/com/oracle/truffle/sl/tools/debug/SLREPLHandler.java	Sat Jul 18 18:03:36 2015 +0200
@@ -40,10 +40,11 @@
  */
 package com.oracle.truffle.sl.tools.debug;
 
+import java.io.*;
 import java.util.*;
 
 import com.oracle.truffle.api.instrument.*;
-import com.oracle.truffle.api.source.*;
+import com.oracle.truffle.api.vm.*;
 import com.oracle.truffle.tools.debug.shell.*;
 import com.oracle.truffle.tools.debug.shell.client.*;
 import com.oracle.truffle.tools.debug.shell.server.*;
@@ -113,20 +114,27 @@
         }
     };
 
+    // TODO (mlvdv) re-implement stepInto when vm support replaced
     /**
      * Runs a source, optionally stepping into a specified tag.
      */
-    private static REPLMessage[] loadHandler(REPLMessage request, REPLServerContext serverContext, boolean stepInto) {
+    private static REPLMessage[] loadHandler(REPLMessage request, REPLServerContext serverContext, @SuppressWarnings("unused") boolean stepInto) {
         final REPLMessage reply = new REPLMessage(REPLMessage.OP, REPLMessage.LOAD_RUN);
         final String fileName = request.get(REPLMessage.SOURCE_NAME);
         try {
-            final Source source = Source.fromFileName(fileName, true);
-            if (source == null) {
+            final File file = new File(fileName);
+            if (!file.canRead()) {
                 return finishReplyFailed(reply, "can't find file \"" + fileName + "\"");
             }
-            serverContext.getDebugEngine().run(source, stepInto);
-            reply.put(REPLMessage.FILE_PATH, source.getPath());
-            return finishReplySucceeded(reply, source.getName() + "  exited");
+            final TruffleVM vm = serverContext.vm();
+            vm.eval(file.toURI());
+            TruffleVM.Symbol main = vm.findGlobalSymbol("main");
+            if (main != null) {
+                main.invoke(null);
+            }
+            final String path = file.getCanonicalPath();
+            reply.put(REPLMessage.FILE_PATH, path);
+            return finishReplySucceeded(reply, fileName + "  exited");
         } catch (QuitException ex) {
             throw ex;
         } catch (KillException ex) {
--- a/truffle/com.oracle.truffle.sl.tools/src/com/oracle/truffle/sl/tools/debug/SLREPLServer.java	Thu Jul 16 19:11:31 2015 +0200
+++ b/truffle/com.oracle.truffle.sl.tools/src/com/oracle/truffle/sl/tools/debug/SLREPLServer.java	Sat Jul 18 18:03:36 2015 +0200
@@ -40,16 +40,19 @@
  */
 package com.oracle.truffle.sl.tools.debug;
 
+import com.oracle.truffle.api.debug.Breakpoint;
+import com.oracle.truffle.api.debug.Debugger;
+import com.oracle.truffle.api.debug.ExecutionEvent;
+import com.oracle.truffle.api.debug.SuspendedEvent;
+
 import java.util.*;
 
-import com.oracle.truffle.api.frame.*;
 import com.oracle.truffle.api.instrument.*;
-import com.oracle.truffle.api.nodes.*;
 import com.oracle.truffle.api.source.*;
 import com.oracle.truffle.api.vm.*;
 import com.oracle.truffle.api.vm.TruffleVM.Language;
 import com.oracle.truffle.sl.*;
-import com.oracle.truffle.tools.debug.engine.*;
+import com.oracle.truffle.sl.nodes.instrument.SLDefaultVisualizer;
 import com.oracle.truffle.tools.debug.shell.*;
 import com.oracle.truffle.tools.debug.shell.client.*;
 import com.oracle.truffle.tools.debug.shell.server.*;
@@ -58,12 +61,11 @@
  * Instantiation of the "server" side of the "REPL*" debugger for the Simple language.
  * <p>
  * The SL parser is not equipped to parse program fragments, so any debugging functions that depend
- * on this are not supported, for example {@link DebugEngine#eval(Source, Node, MaterializedFrame)}
- * and {@link Breakpoint#setCondition(String)}.
+ * on this are not supported, for example "eval" and breakpoint conditions.
  *
  * @see SimpleREPLClient
  */
-public final class SLREPLServer implements REPLServer {
+public final class SLREPLServer extends REPLServer {
 
     // TODO (mlvdv) remove when there's a better way to express this dependency
     @SuppressWarnings("unused") private static final Class<SLLanguage> DYNAMIC_DEPENDENCY = com.oracle.truffle.sl.SLLanguage.class;
@@ -83,7 +85,8 @@
     }
 
     private final Language language;
-    private final DebugEngine slDebugEngine;
+    private final TruffleVM vm;
+    private Debugger db;
     private final String statusPrefix;
     private final Map<String, REPLHandler> handlerMap = new HashMap<>();
     private SLServerContext currentServerContext;
@@ -118,13 +121,25 @@
         add(REPLHandler.TRUFFLE_HANDLER);
         add(REPLHandler.TRUFFLE_NODE_HANDLER);
 
-        TruffleVM vm = TruffleVM.newVM().build();
-        this.language = vm.getLanguages().get("application/x-sl");
+        EventConsumer<SuspendedEvent> onHalted = new EventConsumer<SuspendedEvent>(SuspendedEvent.class) {
+            @Override
+            protected void on(SuspendedEvent ev) {
+                SLREPLServer.this.haltedAt(ev);
+            }
+        };
+        EventConsumer<ExecutionEvent> onExec = new EventConsumer<ExecutionEvent>(ExecutionEvent.class) {
+            @Override
+            protected void on(ExecutionEvent event) {
+                event.prepareStepInto();
+                db = event.getDebugger();
+            }
+        };
+
+        TruffleVM newVM = TruffleVM.newVM().onEvent(onHalted).onEvent(onExec).build();
+        this.language = newVM.getLanguages().get("application/x-sl");
         assert language != null;
 
-        final SLREPLDebugClient slDebugClient = new SLREPLDebugClient(language);
-        this.slDebugEngine = DebugEngine.create(slDebugClient, language);
-
+        this.vm = newVM;
         this.statusPrefix = language.getShortName() + " REPL:";
     }
 
@@ -132,9 +147,10 @@
         this.replClient = replClient;
     }
 
+    @Override
     public REPLMessage start() {
 
-        this.currentServerContext = new SLServerContext(null, null, null);
+        this.currentServerContext = new SLServerContext(null, null);
 
         // SL doesn't load modules (like other languages), so we just return a success
         final REPLMessage reply = new REPLMessage();
@@ -143,6 +159,7 @@
         return reply;
     }
 
+    @Override
     public REPLMessage[] receive(REPLMessage request) {
         if (currentServerContext == null) {
             final REPLMessage message = new REPLMessage();
@@ -161,8 +178,8 @@
 
         private final SLServerContext predecessor;
 
-        public SLServerContext(SLServerContext predecessor, Node astNode, MaterializedFrame mFrame) {
-            super(predecessor == null ? 0 : predecessor.getLevel() + 1, astNode, mFrame);
+        public SLServerContext(SLServerContext predecessor, SuspendedEvent event) {
+            super(predecessor == null ? 0 : predecessor.getLevel() + 1, event);
             this.predecessor = predecessor;
         }
 
@@ -188,66 +205,68 @@
         }
 
         @Override
-        public DebugEngine getDebugEngine() {
-            return slDebugEngine;
+        public Visualizer getVisualizer() {
+            return new SLDefaultVisualizer();
+        }
+
+        @Override
+        public TruffleVM vm() {
+            return vm;
+        }
+
+        @Override
+        protected Debugger db() {
+            return db;
+        }
+
+        @Override
+        public void registerBreakpoint(Breakpoint breakpoint) {
+            SLREPLServer.this.registerBreakpoint(breakpoint);
+        }
+
+        @Override
+        public Breakpoint findBreakpoint(int id) {
+            return SLREPLServer.this.findBreakpoint(id);
+        }
+
+        @Override
+        public int getBreakpointID(Breakpoint breakpoint) {
+            return SLREPLServer.this.getBreakpointID(breakpoint);
         }
 
     }
 
-    /**
-     * Specialize the standard SL debug context by notifying the REPL client when execution is
-     * halted, e.g. at a breakpoint.
-     * <p>
-     * Before notification, the server creates a new context at the halted location, in which
-     * subsequent evaluations take place until such time as the client says to "continue".
-     * <p>
-     * This implementation "cheats" the intended asynchronous architecture by calling back directly
-     * to the client with the notification.
-     */
-    private final class SLREPLDebugClient implements DebugClient {
-
-        private final Language language;
-
-        SLREPLDebugClient(Language language) {
-            this.language = language;
-        }
-
-        public void haltedAt(Node node, MaterializedFrame mFrame, List<String> warnings) {
-            // Create and push a new debug context where execution is halted
-            currentServerContext = new SLServerContext(currentServerContext, node, mFrame);
+    void haltedAt(SuspendedEvent event) {
+        // Create and push a new debug context where execution is halted
+        currentServerContext = new SLServerContext(currentServerContext, event);
 
-            // Message the client that execution is halted and is in a new debugging context
-            final REPLMessage message = new REPLMessage();
-            message.put(REPLMessage.OP, REPLMessage.STOPPED);
-            final SourceSection src = node.getSourceSection();
-            final Source source = src.getSource();
-            message.put(REPLMessage.SOURCE_NAME, source.getName());
-            message.put(REPLMessage.FILE_PATH, source.getPath());
-            message.put(REPLMessage.LINE_NUMBER, Integer.toString(src.getStartLine()));
-            message.put(REPLMessage.STATUS, REPLMessage.SUCCEEDED);
-            message.put(REPLMessage.DEBUG_LEVEL, Integer.toString(currentServerContext.getLevel()));
-            if (!warnings.isEmpty()) {
-                final StringBuilder sb = new StringBuilder();
-                for (String warning : warnings) {
-                    sb.append(warning + "\n");
-                }
-                message.put(REPLMessage.WARNINGS, sb.toString());
+        // Message the client that execution is halted and is in a new debugging context
+        final REPLMessage message = new REPLMessage();
+        message.put(REPLMessage.OP, REPLMessage.STOPPED);
+        final SourceSection src = event.getNode().getSourceSection();
+        final Source source = src.getSource();
+        message.put(REPLMessage.SOURCE_NAME, source.getName());
+        message.put(REPLMessage.FILE_PATH, source.getPath());
+        message.put(REPLMessage.LINE_NUMBER, Integer.toString(src.getStartLine()));
+        message.put(REPLMessage.STATUS, REPLMessage.SUCCEEDED);
+        message.put(REPLMessage.DEBUG_LEVEL, Integer.toString(currentServerContext.getLevel()));
+        List<String> warnings = event.getRecentWarnings();
+        if (!warnings.isEmpty()) {
+            final StringBuilder sb = new StringBuilder();
+            for (String warning : warnings) {
+                sb.append(warning + "\n");
             }
-            try {
-                // Cheat with synchrony: call client directly about entering a nested debugging
-                // context.
-                replClient.halted(message);
-            } finally {
-                // Returns when "continue" is called in the new debugging context
+            message.put(REPLMessage.WARNINGS, sb.toString());
+        }
+        try {
+            // Cheat with synchrony: call client directly about entering a nested debugging
+            // context.
+            replClient.halted(message);
+        } finally {
+            // Returns when "continue" is called in the new debugging context
 
-                // Pop the debug context, and return so that the old context will continue
-                currentServerContext = currentServerContext.predecessor;
-            }
-        }
-
-        public Language getLanguage() {
-            return language;
+            // Pop the debug context, and return so that the old context will continue
+            currentServerContext = currentServerContext.predecessor;
         }
     }
-
 }
--- a/truffle/com.oracle.truffle.sl/src/com/oracle/truffle/sl/SLLanguage.java	Thu Jul 16 19:11:31 2015 +0200
+++ b/truffle/com.oracle.truffle.sl/src/com/oracle/truffle/sl/SLLanguage.java	Sat Jul 18 18:03:36 2015 +0200
@@ -164,7 +164,7 @@
 
     public SLLanguage(Env env) {
         super(env);
-        context = SLContextFactory.create(new BufferedReader(env().stdIn()), new PrintWriter(env().stdOut(), true));
+        context = SLContextFactory.create(this, new BufferedReader(env().stdIn()), new PrintWriter(env().stdOut(), true));
         LAST = this;
         for (NodeFactory<? extends SLBuiltinNode> builtin : builtins) {
             context.installBuiltin(builtin);
@@ -489,17 +489,6 @@
             }
         }
 
-        public void run(Source source) throws DebugSupportException {
-            // TODO (mlvdv) fix to run properly in the current VM
-            try {
-                SLLanguage.run(source);
-            } catch (QuitException ex) {
-                throw ex;
-            } catch (Exception e) {
-                throw new DebugSupportException(e);
-            }
-        }
-
         public Object evalInContext(Source source, Node node, MaterializedFrame mFrame) throws DebugSupportException {
             throw new DebugSupportException("evalInContext not supported in this language");
         }
--- a/truffle/com.oracle.truffle.sl/src/com/oracle/truffle/sl/factory/SLContextFactory.java	Thu Jul 16 19:11:31 2015 +0200
+++ b/truffle/com.oracle.truffle.sl/src/com/oracle/truffle/sl/factory/SLContextFactory.java	Sat Jul 18 18:03:36 2015 +0200
@@ -40,6 +40,7 @@
  */
 package com.oracle.truffle.sl.factory;
 
+import com.oracle.truffle.sl.SLLanguage;
 import java.io.*;
 
 import com.oracle.truffle.sl.runtime.*;
@@ -49,7 +50,7 @@
     private SLContextFactory() {
     }
 
-    public static SLContext create(BufferedReader input, PrintWriter output) {
-        return new SLContext(input, output);
+    public static SLContext create(SLLanguage sl, BufferedReader input, PrintWriter output) {
+        return new SLContext(sl, input, output);
     }
 }
--- a/truffle/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/SLRootNode.java	Thu Jul 16 19:11:31 2015 +0200
+++ b/truffle/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/SLRootNode.java	Sat Jul 18 18:03:36 2015 +0200
@@ -45,6 +45,7 @@
 import com.oracle.truffle.api.frame.*;
 import com.oracle.truffle.api.instrument.*;
 import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.sl.SLLanguage;
 import com.oracle.truffle.sl.builtins.*;
 import com.oracle.truffle.sl.nodes.controlflow.*;
 import com.oracle.truffle.sl.runtime.*;
@@ -70,7 +71,7 @@
     @CompilationFinal private boolean isCloningAllowed;
 
     public SLRootNode(SLContext context, FrameDescriptor frameDescriptor, SLExpressionNode bodyNode, String name) {
-        super(null, frameDescriptor);
+        super(SLLanguage.class, null, frameDescriptor);
         this.bodyNode = bodyNode;
         this.name = name;
         this.context = context;
--- a/truffle/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/access/SLReadPropertyCacheNode.java	Thu Jul 16 19:11:31 2015 +0200
+++ b/truffle/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/access/SLReadPropertyCacheNode.java	Sat Jul 18 18:03:36 2015 +0200
@@ -69,8 +69,8 @@
      */
     @Specialization(limit = "CACHE_LIMIT", guards = {"longLocation != null", "shape.check(receiver)"}, assumptions = "shape.getValidAssumption()")
     @SuppressWarnings("unused")
-    protected long doCachedLong(DynamicObject receiver, //
-                    @Cached("receiver.getShape()") Shape shape, //
+    protected long doCachedLong(DynamicObject receiver,   //
+                    @Cached("receiver.getShape()") Shape shape,   //
                     @Cached("getLongLocation(shape)") LongLocation longLocation) {
         return longLocation.getLong(receiver, true);
     }
@@ -88,8 +88,8 @@
      * contain all long cache entries.
      */
     @Specialization(limit = "CACHE_LIMIT", contains = "doCachedLong", guards = "shape.check(receiver)", assumptions = "shape.getValidAssumption()")
-    protected static Object doCachedObject(DynamicObject receiver, //
-                    @Cached("receiver.getShape()") Shape shape, //
+    protected static Object doCachedObject(DynamicObject receiver,   //
+                    @Cached("receiver.getShape()") Shape shape,   //
                     @Cached("shape.getProperty(propertyName)") Property property) {
         if (property == null) {
             return SLNull.SINGLETON;
--- a/truffle/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/access/SLWritePropertyCacheNode.java	Thu Jul 16 19:11:31 2015 +0200
+++ b/truffle/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/access/SLWritePropertyCacheNode.java	Sat Jul 18 18:03:36 2015 +0200
@@ -57,7 +57,7 @@
     public abstract void executeObject(DynamicObject receiver, Object value);
 
     @Specialization(guards = "location.isValid(receiver, value)", assumptions = "location.getAssumptions()")
-    public void writeCached(DynamicObject receiver, Object value, //
+    public void writeCached(DynamicObject receiver, Object value,   //
                     @Cached("createCachedWrite(receiver, value)") CachedWriteLocation location) {
         if (location.writeUnchecked(receiver, value)) {
             // write successful
@@ -68,7 +68,7 @@
 
     @Specialization(contains = "writeCached")
     @TruffleBoundary
-    public void writeGeneric(DynamicObject receiver, Object value, //
+    public void writeGeneric(DynamicObject receiver, Object value,   //
                     @Cached("new(createCachedWrite(receiver, value))") LRUCachedWriteLocation lru) {
         CachedWriteLocation location = lru.location;
         if (!location.isValid(receiver, value) || !location.areAssumptionsValid()) {
--- a/truffle/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/call/SLDispatchNode.java	Thu Jul 16 19:11:31 2015 +0200
+++ b/truffle/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/call/SLDispatchNode.java	Sat Jul 18 18:03:36 2015 +0200
@@ -95,8 +95,8 @@
      *            cachedFunction.
      */
     @Specialization(limit = "INLINE_CACHE_SIZE", guards = "function == cachedFunction", assumptions = "cachedFunction.getCallTargetStable()")
-    protected static Object doDirect(VirtualFrame frame, SLFunction function, Object[] arguments, //
-                    @Cached("function") SLFunction cachedFunction, //
+    protected static Object doDirect(VirtualFrame frame, SLFunction function, Object[] arguments,   //
+                    @Cached("function") SLFunction cachedFunction,   //
                     @Cached("create(cachedFunction.getCallTarget())") DirectCallNode callNode) {
         /* Inline cache hit, we are safe to execute the cached call target. */
         return callNode.call(frame, arguments);
@@ -108,7 +108,7 @@
      * no method inlining is performed.
      */
     @Specialization(contains = "doDirect")
-    protected static Object doIndirect(VirtualFrame frame, SLFunction function, Object[] arguments, //
+    protected static Object doIndirect(VirtualFrame frame, SLFunction function, Object[] arguments,   //
                     @Cached("create()") IndirectCallNode callNode) {
         /*
          * SL has a quite simple call lookup: just ask the function for the current call target, and
--- a/truffle/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLReturnNode.java	Thu Jul 16 19:11:31 2015 +0200
+++ b/truffle/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLReturnNode.java	Sat Jul 18 18:03:36 2015 +0200
@@ -69,7 +69,9 @@
         if (valueNode != null) {
             result = valueNode.executeGeneric(frame);
         } else {
-            /* Return statement that was not followed by an expression, so return the SL null value. */
+            /*
+             * Return statement that was not followed by an expression, so return the SL null value.
+             */
             result = SLNull.SINGLETON;
         }
         throw new SLReturnException(result);
--- a/truffle/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/instrument/SLDefaultVisualizer.java	Thu Jul 16 19:11:31 2015 +0200
+++ b/truffle/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/instrument/SLDefaultVisualizer.java	Sat Jul 18 18:03:36 2015 +0200
@@ -74,7 +74,7 @@
         RootNode root = node.getRootNode();
         if (root instanceof SLRootNode) {
             SLRootNode slRootNode = (SLRootNode) root;
-            return slRootNode.toString();
+            return slRootNode.getName();
 
         }
         return "unknown";
@@ -92,7 +92,7 @@
 
     @Override
     public String displayValue(Object value, int trim) {
-        if (value == SLNull.SINGLETON) {
+        if (value == null || value == SLNull.SINGLETON) {
             return "null";
         }
         return trim(value.toString(), trim);
--- a/truffle/com.oracle.truffle.sl/src/com/oracle/truffle/sl/parser/SLNodeFactory.java	Thu Jul 16 19:11:31 2015 +0200
+++ b/truffle/com.oracle.truffle.sl/src/com/oracle/truffle/sl/parser/SLNodeFactory.java	Sat Jul 18 18:03:36 2015 +0200
@@ -239,8 +239,8 @@
     }
 
     /**
-     * Returns the corresponding subclass of {@link SLExpressionNode} for binary expressions.
-     * </br>These nodes are currently not instrumented.
+     * Returns the corresponding subclass of {@link SLExpressionNode} for binary expressions. </br>
+     * These nodes are currently not instrumented.
      *
      * @param opToken The operator of the binary expression
      * @param leftNode The left node of the expression
--- a/truffle/com.oracle.truffle.sl/src/com/oracle/truffle/sl/runtime/SLContext.java	Thu Jul 16 19:11:31 2015 +0200
+++ b/truffle/com.oracle.truffle.sl/src/com/oracle/truffle/sl/runtime/SLContext.java	Sat Jul 18 18:03:36 2015 +0200
@@ -48,6 +48,7 @@
 import com.oracle.truffle.api.nodes.*;
 import com.oracle.truffle.api.object.*;
 import com.oracle.truffle.api.source.*;
+import com.oracle.truffle.sl.SLLanguage;
 import com.oracle.truffle.sl.builtins.*;
 import com.oracle.truffle.sl.nodes.*;
 import com.oracle.truffle.sl.nodes.local.*;
@@ -66,12 +67,14 @@
 public final class SLContext extends ExecutionContext {
     private static final Layout LAYOUT = Layout.createLayout();
 
+    private final SLLanguage language;
     private final BufferedReader input;
     private final PrintWriter output;
     private final SLFunctionRegistry functionRegistry;
     private final Shape emptyShape;
 
-    public SLContext(BufferedReader input, PrintWriter output) {
+    public SLContext(SLLanguage language, BufferedReader input, PrintWriter output) {
+        this.language = language;
         this.input = input;
         this.output = output;
         this.functionRegistry = new SLFunctionRegistry();
@@ -103,6 +106,10 @@
         return functionRegistry;
     }
 
+    public SLLanguage getLanguage() {
+        return language;
+    }
+
     /**
      * Adds all builtin functions to the {@link SLFunctionRegistry}. This method lists all
      * {@link SLBuiltinNode builtin implementation classes}.
--- a/truffle/com.oracle.truffle.sl/src/com/oracle/truffle/sl/runtime/SLFunctionForeignAccess.java	Thu Jul 16 19:11:31 2015 +0200
+++ b/truffle/com.oracle.truffle.sl/src/com/oracle/truffle/sl/runtime/SLFunctionForeignAccess.java	Sat Jul 18 18:03:36 2015 +0200
@@ -47,6 +47,7 @@
 import com.oracle.truffle.api.interop.TruffleObject;
 import com.oracle.truffle.api.interop.ForeignAccess;
 import com.oracle.truffle.api.interop.Message;
+import com.oracle.truffle.sl.SLLanguage;
 import com.oracle.truffle.sl.nodes.call.SLDispatchNode;
 import com.oracle.truffle.sl.nodes.call.SLDispatchNodeGen;
 import java.math.BigInteger;
@@ -80,6 +81,10 @@
     private static class SLForeignCallerRootNode extends RootNode {
         @Child private SLDispatchNode dispatch = SLDispatchNodeGen.create();
 
+        public SLForeignCallerRootNode() {
+            super(SLLanguage.class, null, null);
+        }
+
         @Override
         public Object execute(VirtualFrame frame) {
             SLFunction function = (SLFunction) ForeignAccess.getReceiver(frame);
@@ -106,6 +111,10 @@
     }
 
     private static class SLForeignNullCheckNode extends RootNode {
+        public SLForeignNullCheckNode() {
+            super(SLLanguage.class, null, null);
+        }
+
         @Override
         public Object execute(VirtualFrame frame) {
             Object receiver = ForeignAccess.getReceiver(frame);
--- a/truffle/com.oracle.truffle.tck/src/com/oracle/truffle/tck/MaxMinObject.java	Thu Jul 16 19:11:31 2015 +0200
+++ b/truffle/com.oracle.truffle.tck/src/com/oracle/truffle/tck/MaxMinObject.java	Sat Jul 18 18:03:36 2015 +0200
@@ -27,6 +27,7 @@
 import com.oracle.truffle.api.CallTarget;
 import com.oracle.truffle.api.CompilerDirectives;
 import com.oracle.truffle.api.Truffle;
+import com.oracle.truffle.api.TruffleLanguage;
 import com.oracle.truffle.api.dsl.NodeChild;
 import com.oracle.truffle.api.dsl.NodeChildren;
 import com.oracle.truffle.api.dsl.Specialization;
@@ -175,6 +176,7 @@
         private final boolean max;
 
         MaxMinNode(boolean max) {
+            super(MMLanguage.class, null, null);
             this.max = max;
         }
 
@@ -194,4 +196,9 @@
         }
     }
 
+    private abstract class MMLanguage extends TruffleLanguage {
+        public MMLanguage(Env env) {
+            super(env);
+        }
+    }
 }
--- a/truffle/com.oracle.truffle.tools.debug.engine/src/com/oracle/truffle/tools/debug/engine/Breakpoint.java	Thu Jul 16 19:11:31 2015 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,238 +0,0 @@
-/*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.truffle.tools.debug.engine;
-
-import com.oracle.truffle.api.instrument.*;
-import com.oracle.truffle.api.source.*;
-
-public abstract class Breakpoint {
-
-    /**
-     * A general model of the states occupied by a breakpoint during its lifetime.
-     */
-    public enum BreakpointState {
-
-        /**
-         * Not attached, enabled.
-         * <p>
-         * Created for a source location but not yet attached: perhaps just created and the source
-         * hasn't been loaded yet; perhaps source has been loaded, but the line location isn't
-         * probed so a breakpoint cannot be attached. Can be either enabled or disabled.
-         */
-        ENABLED_UNRESOLVED("Enabled/Unresolved"),
-
-        /**
-         * Not attached, disabled.
-         * <p>
-         * Created for a source location but not yet attached: perhaps just created and the source
-         * hasn't been loaded yet; perhaps source has been loaded, but the line location isn't
-         * probed so a breakpoint cannot be attached.
-         */
-        DISABLED_UNRESOLVED("Disabled/Unresolved"),
-
-        /**
-         * Attached, instrument enabled.
-         * <p>
-         * Is currently implemented by some {@link Instrument}, which is attached to a {@link Probe}
-         * at a specific node in the AST, and the breakpoint is enabled.
-         */
-        ENABLED("Enabled"),
-
-        /**
-         * Attached, instrument disabled.
-         * <p>
-         * Is currently implemented by some {@link Instrument}, which is attached to a {@link Probe}
-         * at a specific node in the AST, and the breakpoint is disabled.
-         */
-        DISABLED("Disabled"),
-
-        /**
-         * Not attached, instrument is permanently disabled.
-         */
-        DISPOSED("Disposed");
-
-        private final String name;
-
-        BreakpointState(String name) {
-            this.name = name;
-        }
-
-        public String getName() {
-            return name;
-        }
-
-        @Override
-        public String toString() {
-            return name;
-        }
-
-    }
-
-    private static int nextBreakpointId = 0;
-
-    private final int id;
-    private final int groupId;
-    private final boolean isOneShot;
-
-    private int ignoreCount;
-
-    private int hitCount = 0;
-
-    private BreakpointState state;
-
-    Breakpoint(BreakpointState state, int groupId, int ignoreCount, boolean isOneShot) {
-        this.state = state;
-        this.id = nextBreakpointId++;
-        this.groupId = groupId;
-        this.isOneShot = isOneShot;
-        this.ignoreCount = ignoreCount;
-    }
-
-    /**
-     * Unique ID.
-     */
-    public final int getId() {
-        return id;
-    }
-
-    /**
-     * Group ID, set when created.
-     */
-    public final int getGroupId() {
-        return groupId;
-    }
-
-    /**
-     * Enables or disables this breakpoint's AST instrumentation. The breakpoint is enabled by
-     * default.
-     *
-     * @param enabled <code>true</code> to activate the instrumentation, <code>false</code> to
-     *            deactivate the instrumentation so that it has no effect.
-     */
-    public abstract void setEnabled(boolean enabled);
-
-    /**
-     * Is this breakpoint active?
-     */
-    public abstract boolean isEnabled();
-
-    /**
-     * Sets the condition on this breakpoint, {@code null} to make it unconditional.
-     *
-     * @param expr if non{@code -null}, a boolean expression, expressed in the guest language, to be
-     *            evaluated in the lexical context at the breakpoint location.
-     * @throws DebugException if condition is invalid
-     * @throws UnsupportedOperationException if the breakpoint does not support conditions
-     */
-    public abstract void setCondition(String expr) throws DebugException;
-
-    /**
-     * Gets the string, expressed in the Guest Language, that defines the current condition on this
-     * breakpoint; {@code null} if this breakpoint is currently unconditional.
-     */
-    public String getCondition() {
-        return null;
-    }
-
-    /**
-     * Does this breakpoint remove itself after first activation?
-     */
-    public final boolean isOneShot() {
-        return isOneShot;
-    }
-
-    /**
-     * Gets the number of hits left to be ignored before halting.
-     */
-    public final int getIgnoreCount() {
-        return ignoreCount;
-    }
-
-    /**
-     * Change the threshold for when this breakpoint should start causing a break. When both an
-     * ignore count and a {@linkplain #setCondition(String) condition} are specified, the condition
-     * is evaluated first: if {@code false} it is not considered to be a hit. In other words, the
-     * ignore count is for successful conditions only.
-     */
-    public final void setIgnoreCount(int ignoreCount) {
-        this.ignoreCount = ignoreCount;
-    }
-
-    /**
-     * Number of times this breakpoint has reached, with one exception; if the breakpoint has a
-     * condition that evaluates to {@code false}, it does not count as a hit.
-     */
-    public final int getHitCount() {
-        return hitCount;
-    }
-
-    /**
-     * Disables this breakpoint and removes any associated instrumentation; it becomes permanently
-     * inert.
-     */
-    public abstract void dispose();
-
-    /**
-     * Gets a human-sensible description of this breakpoint's location in a {@link Source}.
-     */
-    public abstract String getLocationDescription();
-
-    public final BreakpointState getState() {
-        return state;
-    }
-
-    final void assertState(BreakpointState s) {
-        assert state == s;
-    }
-
-    final void setState(BreakpointState state) {
-        this.state = state;
-    }
-
-    /**
-     * Assumes that all conditions for causing the break have been satisfied, so increments the
-     * <em>hit count</em>. Then checks if the <em>ignore count</em> has been exceeded, and if so
-     * returns {@code true}. If not, it still counts as a <em>hit</em> but should be ignored.
-     *
-     * @return whether to proceed
-     */
-    final boolean incrHitCountCheckIgnore() {
-        return ++hitCount > ignoreCount;
-    }
-
-    @Override
-    public String toString() {
-        final StringBuilder sb = new StringBuilder(getClass().getSimpleName());
-        sb.append(" state=");
-        sb.append(getState() == null ? "<none>" : getState().getName());
-        if (isOneShot()) {
-            sb.append(", " + "One-Shot");
-        }
-        if (getCondition() != null) {
-            sb.append(", condition=\"" + getCondition() + "\"");
-        }
-        return sb.toString();
-    }
-}
--- a/truffle/com.oracle.truffle.tools.debug.engine/src/com/oracle/truffle/tools/debug/engine/DebugClient.java	Thu Jul 16 19:11:31 2015 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,54 +0,0 @@
-/*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.truffle.tools.debug.engine;
-
-import java.util.*;
-
-import com.oracle.truffle.api.frame.*;
-import com.oracle.truffle.api.nodes.*;
-import com.oracle.truffle.api.vm.TruffleVM.Language;
-
-/**
- * A client of the debugger where certain events should be posted.
- *
- * @see DebugEngine
- */
-public interface DebugClient {
-
-    /**
-     * Notifies client that program execution has been halted at some location; execution will
-     * resume when this method returns.
-     *
-     * @param astNode AST node that is just about to be executed
-     * @param mFrame frame that will be passed to the node when executed
-     * @param warnings any warnings generated since the most recent halt.
-     */
-    void haltedAt(Node astNode, MaterializedFrame mFrame, List<String> warnings);
-
-    /**
-     * Gets information and services for the language being debugged.
-     */
-    Language getLanguage();
-}
--- a/truffle/com.oracle.truffle.tools.debug.engine/src/com/oracle/truffle/tools/debug/engine/DebugEngine.java	Thu Jul 16 19:11:31 2015 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,851 +0,0 @@
-/*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.truffle.tools.debug.engine;
-
-import java.io.*;
-import java.util.*;
-
-import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
-import com.oracle.truffle.api.*;
-import com.oracle.truffle.api.frame.*;
-import com.oracle.truffle.api.instrument.*;
-import com.oracle.truffle.api.nodes.*;
-import com.oracle.truffle.api.source.*;
-import com.oracle.truffle.api.vm.TruffleVM.Language;
-import com.oracle.truffle.tools.debug.engine.DebugExecutionSupport.DebugExecutionListener;
-
-/**
- * Language-agnostic engine for running Truffle languages under debugging control.
- */
-public final class DebugEngine {
-
-    private static final boolean TRACE = false;
-    private static final String TRACE_PREFIX = "DEBUG ENGINE: ";
-
-    private static final PrintStream OUT = System.out;
-
-    private static final SyntaxTag STEPPING_TAG = StandardSyntaxTag.STATEMENT;
-    private static final SyntaxTag CALL_TAG = StandardSyntaxTag.CALL;
-
-    private static void trace(String format, Object... args) {
-        if (TRACE) {
-            OUT.println(TRACE_PREFIX + String.format(format, args));
-        }
-    }
-
-    interface BreakpointCallback {
-
-        /**
-         * Passes control to the debugger with execution suspended.
-         */
-        void haltedAt(Node astNode, MaterializedFrame mFrame, String haltReason);
-    }
-
-    interface WarningLog {
-
-        /**
-         * Logs a warning that is kept until the start of the next execution.
-         */
-        void addWarning(String warning);
-    }
-
-    private final Language language;
-
-    /**
-     * The client of this engine.
-     */
-    private final DebugClient debugClient;
-
-    private final DebugExecutionSupport executionSupport;
-
-    /**
-     * Implementation of line-oriented breakpoints.
-     */
-    private final LineBreakpointFactory lineBreaks;
-
-    /**
-     * Implementation of tag-oriented breakpoints.
-     */
-    private final TagBreakpointFactory tagBreaks;
-
-    /**
-     * Head of the stack of executions.
-     */
-    private DebugExecutionContext debugContext;
-
-    /**
-     * @param debugClient
-     * @param language
-     */
-    private DebugEngine(DebugClient debugClient, Language language) {
-        this.debugClient = debugClient;
-        this.language = language;
-        this.executionSupport = new DebugExecutionSupport(language.getShortName(), language.getDebugSupport());
-
-        Source.setFileCaching(true);
-
-        // Initialize execution context stack
-        debugContext = new DebugExecutionContext(null, null);
-        prepareContinue();
-        debugContext.contextTrace("START EXEC DEFAULT");
-
-        executionSupport.addExecutionListener(new DebugExecutionListener() {
-
-            public void executionStarted(Source source, boolean stepInto) {
-                // Push a new execution context onto stack
-                DebugEngine.this.debugContext = new DebugExecutionContext(source, DebugEngine.this.debugContext);
-                if (stepInto) {
-                    DebugEngine.this.prepareStepInto(1);
-                } else {
-                    DebugEngine.this.prepareContinue();
-                }
-                DebugEngine.this.debugContext.contextTrace("START EXEC ");
-            }
-
-            public void executionEnded() {
-                DebugEngine.this.lineBreaks.disposeOneShots();
-                DebugEngine.this.tagBreaks.disposeOneShots();
-                DebugEngine.this.debugContext.clearStrategy();
-                DebugEngine.this.debugContext.contextTrace("END EXEC ");
-                // Pop the stack of execution contexts.
-                DebugEngine.this.debugContext = DebugEngine.this.debugContext.predecessor;
-            }
-        });
-
-        final BreakpointCallback breakpointCallback = new BreakpointCallback() {
-
-            @TruffleBoundary
-            public void haltedAt(Node astNode, MaterializedFrame mFrame, String haltReason) {
-                debugContext.halt(astNode, mFrame, true, haltReason);
-            }
-        };
-
-        final WarningLog warningLog = new WarningLog() {
-
-            public void addWarning(String warning) {
-                assert debugContext != null;
-                debugContext.logWarning(warning);
-            }
-        };
-
-        this.lineBreaks = new LineBreakpointFactory(executionSupport, breakpointCallback, warningLog);
-
-        this.tagBreaks = new TagBreakpointFactory(executionSupport, breakpointCallback, warningLog);
-    }
-
-    public static DebugEngine create(DebugClient debugClient, Language language) {
-        return new DebugEngine(debugClient, language);
-    }
-
-    /**
-     * Runs a script. If "StepInto" is requested, halts at the first location tagged as a
-     * {@linkplain StandardSyntaxTag#STATEMENT STATEMENT}.
-     *
-     * @throws DebugException if an unexpected failure occurs
-     */
-    public void run(Source source, boolean stepInto) throws DebugException {
-        executionSupport.run(source, stepInto);
-    }
-
-    /**
-     * Sets a breakpoint to halt at a source line.
-     *
-     * @param groupId
-     * @param ignoreCount number of hits to ignore before halting
-     * @param lineLocation where to set the breakpoint (source, line number)
-     * @param oneShot breakpoint disposes itself after fist hit, if {@code true}
-     * @return a new breakpoint, initially enabled
-     * @throws DebugException if the breakpoint can not be set.
-     */
-    @TruffleBoundary
-    public LineBreakpoint setLineBreakpoint(int groupId, int ignoreCount, LineLocation lineLocation, boolean oneShot) throws DebugException {
-        return lineBreaks.create(groupId, ignoreCount, lineLocation, oneShot);
-    }
-
-    /**
-     * Sets a breakpoint to halt at any node holding a specified {@link SyntaxTag}.
-     *
-     * @param groupId
-     * @param ignoreCount number of hits to ignore before halting
-     * @param oneShot if {@code true} breakpoint removes it self after a hit
-     * @return a new breakpoint, initially enabled
-     * @throws DebugException if the breakpoint already set
-     */
-    @TruffleBoundary
-    public Breakpoint setTagBreakpoint(int groupId, int ignoreCount, SyntaxTag tag, boolean oneShot) throws DebugException {
-        return tagBreaks.create(groupId, ignoreCount, tag, oneShot);
-    }
-
-    /**
-     * Finds a breakpoint created by this engine, but not yet disposed, by id.
-     */
-    @TruffleBoundary
-    public Breakpoint findBreakpoint(long id) {
-        final Breakpoint breakpoint = lineBreaks.find(id);
-        return breakpoint == null ? tagBreaks.find(id) : breakpoint;
-    }
-
-    /**
-     * Gets all existing breakpoints, whatever their status, in natural sorted order. Modification
-     * save.
-     */
-    @TruffleBoundary
-    public Collection<Breakpoint> getBreakpoints() {
-        final Collection<Breakpoint> result = new ArrayList<>();
-        result.addAll(lineBreaks.getAll());
-        result.addAll(tagBreaks.getAll());
-        return result;
-    }
-
-    /**
-     * Prepare to execute in Continue mode when guest language program execution resumes. In this
-     * mode:
-     * <ul>
-     * <li>Execution will continue until either:
-     * <ol>
-     * <li>execution arrives at a node to which an enabled breakpoint is attached,
-     * <strong>or:</strong></li>
-     * <li>execution completes.</li>
-     * </ol>
-     * </ul>
-     */
-    @TruffleBoundary
-    public void prepareContinue() {
-        debugContext.setStrategy(new Continue());
-    }
-
-    /**
-     * Prepare to execute in StepInto mode when guest language program execution resumes. In this
-     * mode:
-     * <ul>
-     * <li>User breakpoints are disabled.</li>
-     * <li>Execution will continue until either:
-     * <ol>
-     * <li>execution arrives at a node with the tag {@linkplain StandardSyntaxTag#STATEMENT
-     * STATMENT}, <strong>or:</strong></li>
-     * <li>execution completes.</li>
-     * </ol>
-     * <li>
-     * StepInto mode persists only through one resumption (i.e. {@code stepIntoCount} steps), and
-     * reverts by default to Continue mode.</li>
-     * </ul>
-     *
-     * @param stepCount the number of times to perform StepInto before halting
-     * @throws IllegalArgumentException if the specified number is {@code <= 0}
-     */
-    @TruffleBoundary
-    public void prepareStepInto(int stepCount) {
-        if (stepCount <= 0) {
-            throw new IllegalArgumentException();
-        }
-        debugContext.setStrategy(new StepInto(stepCount));
-    }
-
-    /**
-     * Prepare to execute in StepOut mode when guest language program execution resumes. In this
-     * mode:
-     * <ul>
-     * <li>User breakpoints are enabled.</li>
-     * <li>Execution will continue until either:
-     * <ol>
-     * <li>execution arrives at the nearest enclosing call site on the stack, <strong>or</strong></li>
-     * <li>execution completes.</li>
-     * </ol>
-     * <li>StepOut mode persists only through one resumption, and reverts by default to Continue
-     * mode.</li>
-     * </ul>
-     */
-    @TruffleBoundary
-    public void prepareStepOut() {
-        debugContext.setStrategy(new StepOut());
-    }
-
-    /**
-     * Prepare to execute in StepOver mode when guest language program execution resumes. In this
-     * mode:
-     * <ul>
-     * <li>Execution will continue until either:
-     * <ol>
-     * <li>execution arrives at a node with the tag {@linkplain StandardSyntaxTag#STATEMENT
-     * STATEMENT} when not nested in one or more function/method calls, <strong>or:</strong></li>
-     * <li>execution arrives at a node to which a breakpoint is attached and when nested in one or
-     * more function/method calls, <strong>or:</strong></li>
-     * <li>execution completes.</li>
-     * </ol>
-     * <li>StepOver mode persists only through one resumption (i.e. {@code stepOverCount} steps),
-     * and reverts by default to Continue mode.</li>
-     * </ul>
-     *
-     * @param stepCount the number of times to perform StepInto before halting
-     * @throws IllegalArgumentException if the specified number is {@code <= 0}
-     */
-    @TruffleBoundary
-    public void prepareStepOver(int stepCount) {
-        if (stepCount <= 0) {
-            throw new IllegalArgumentException();
-        }
-        debugContext.setStrategy(new StepOver(stepCount));
-    }
-
-    /**
-     * Gets the stack frames from the (topmost) halted Truffle execution; {@code null} null if no
-     * execution.
-     */
-    @TruffleBoundary
-    public List<FrameDebugDescription> getStack() {
-        return debugContext == null ? null : debugContext.getFrames();
-    }
-
-    /**
-     * Evaluates code in a halted execution context, at top-level if <code>mFrame==null</code>.
-     *
-     * @throws DebugException
-     */
-    public Object eval(Source source, Node node, MaterializedFrame mFrame) throws DebugException {
-        return executionSupport.evalInContext(source, node, mFrame);
-    }
-
-    /**
-     * A mode of user navigation from a current code location to another, e.g "step in" vs.
-     * "step over".
-     */
-    private abstract class StepStrategy {
-
-        private DebugExecutionContext context;
-        protected final String strategyName;
-
-        protected StepStrategy() {
-            this.strategyName = getClass().getSimpleName();
-        }
-
-        final String getName() {
-            return strategyName;
-        }
-
-        /**
-         * Reconfigure the debugger so that when execution continues the program will halt at the
-         * location specified by this strategy.
-         */
-        final void enable(DebugExecutionContext c, int stackDepth) {
-            this.context = c;
-            setStrategy(stackDepth);
-        }
-
-        /**
-         * Return the debugger to the default navigation mode.
-         */
-        final void disable() {
-            unsetStrategy();
-        }
-
-        @TruffleBoundary
-        final void halt(Node astNode, MaterializedFrame mFrame, boolean before) {
-            context.halt(astNode, mFrame, before, this.getClass().getSimpleName());
-        }
-
-        @TruffleBoundary
-        final void replaceStrategy(StepStrategy newStrategy) {
-            context.setStrategy(newStrategy);
-        }
-
-        @TruffleBoundary
-        protected final void strategyTrace(String action, String format, Object... args) {
-            if (TRACE) {
-                context.contextTrace("%s (%s) %s", action, strategyName, String.format(format, args));
-            }
-        }
-
-        @TruffleBoundary
-        protected final void suspendUserBreakpoints() {
-            lineBreaks.setActive(false);
-            tagBreaks.setActive(false);
-        }
-
-        @SuppressWarnings("unused")
-        protected final void restoreUserBreakpoints() {
-            lineBreaks.setActive(true);
-            tagBreaks.setActive(true);
-        }
-
-        /**
-         * Reconfigure the debugger so that when execution continues, it will do so using this mode
-         * of navigation.
-         */
-        protected abstract void setStrategy(int stackDepth);
-
-        /**
-         * Return to the debugger to the default mode of navigation.
-         */
-        protected abstract void unsetStrategy();
-    }
-
-    /**
-     * Strategy: the null stepping strategy.
-     * <ul>
-     * <li>User breakpoints are enabled.</li>
-     * <li>Execution continues until either:
-     * <ol>
-     * <li>execution arrives at a node with attached user breakpoint, <strong>or:</strong></li>
-     * <li>execution completes.</li>
-     * </ol>
-     * </ul>
-     */
-    private final class Continue extends StepStrategy {
-
-        @Override
-        protected void setStrategy(int stackDepth) {
-        }
-
-        @Override
-        protected void unsetStrategy() {
-        }
-    }
-
-    /**
-     * Strategy: per-statement stepping.
-     * <ul>
-     * <li>User breakpoints are enabled.</li>
-     * <li>Execution continues until either:
-     * <ol>
-     * <li>execution <em>arrives</em> at a STATEMENT node, <strong>or:</strong></li>
-     * <li>execution <em>returns</em> to a CALL node and the call stack is smaller then when
-     * execution started, <strong>or:</strong></li>
-     * <li>execution completes.</li>
-     * </ol>
-     * </ul>
-     *
-     * @see DebugEngine#prepareStepInto(int)
-     */
-    private final class StepInto extends StepStrategy {
-        private int unfinishedStepCount;
-
-        StepInto(int stepCount) {
-            super();
-            this.unfinishedStepCount = stepCount;
-        }
-
-        @Override
-        protected void setStrategy(final int stackDepth) {
-            Probe.setBeforeTagTrap(new SyntaxTagTrap(STEPPING_TAG) {
-
-                @Override
-                public void tagTrappedAt(Node node, MaterializedFrame mFrame) {
-                    // HALT: just before statement
-                    --unfinishedStepCount;
-                    strategyTrace("TRAP BEFORE", "unfinished steps=%d", unfinishedStepCount);
-                    // Should run in fast path
-                    if (unfinishedStepCount <= 0) {
-                        halt(node, mFrame, true);
-                    }
-                    strategyTrace("RESUME BEFORE", "");
-                }
-            });
-            Probe.setAfterTagTrap(new SyntaxTagTrap(CALL_TAG) {
-
-                @Override
-                public void tagTrappedAt(Node node, MaterializedFrame mFrame) {
-                    --unfinishedStepCount;
-                    strategyTrace(null, "TRAP AFTER unfinished steps=%d", unfinishedStepCount);
-                    if (currentStackDepth() < stackDepth) {
-                        // HALT: just "stepped out"
-                        if (unfinishedStepCount <= 0) {
-                            halt(node, mFrame, false);
-                        }
-                    }
-                    strategyTrace("RESUME AFTER", "");
-                }
-            });
-        }
-
-        @Override
-        protected void unsetStrategy() {
-            Probe.setBeforeTagTrap(null);
-            Probe.setAfterTagTrap(null);
-        }
-    }
-
-    /**
-     * Strategy: execution to nearest enclosing call site.
-     * <ul>
-     * <li>User breakpoints are enabled.</li>
-     * <li>Execution continues until either:
-     * <ol>
-     * <li>execution arrives at a node with attached user breakpoint, <strong>or:</strong></li>
-     * <li>execution <em>returns</em> to a CALL node and the call stack is smaller than when
-     * execution started, <strong>or:</strong></li>
-     * <li>execution completes.</li>
-     * </ol>
-     * </ul>
-     *
-     * @see DebugEngine#prepareStepOut()
-     */
-    private final class StepOut extends StepStrategy {
-
-        @Override
-        protected void setStrategy(final int stackDepth) {
-            Probe.setAfterTagTrap(new SyntaxTagTrap(CALL_TAG) {
-
-                @TruffleBoundary
-                @Override
-                public void tagTrappedAt(Node node, MaterializedFrame mFrame) {
-                    // HALT:
-                    final int currentStackDepth = currentStackDepth();
-                    strategyTrace("TRAP AFTER", "stackDepth: start=%d current=%d", stackDepth, currentStackDepth);
-                    if (currentStackDepth < stackDepth) {
-                        halt(node, mFrame, false);
-                    }
-                    strategyTrace("RESUME AFTER", "");
-                }
-            });
-        }
-
-        @Override
-        protected void unsetStrategy() {
-            Probe.setAfterTagTrap(null);
-        }
-    }
-
-    /**
-     * Strategy: per-statement stepping, so long as not nested in method calls (i.e. at original
-     * stack depth).
-     * <ul>
-     * <li>User breakpoints are enabled.</li>
-     * <li>Execution continues until either:
-     * <ol>
-     * <li>execution arrives at a STATEMENT node with stack depth no more than when started
-     * <strong>or:</strong></li>
-     * <li>the program completes.</li>
-     * </ol>
-     * </ul>
-     */
-    private final class StepOver extends StepStrategy {
-        private int unfinishedStepCount;
-
-        StepOver(int stepCount) {
-            this.unfinishedStepCount = stepCount;
-        }
-
-        @Override
-        protected void setStrategy(final int stackDepth) {
-            Probe.setBeforeTagTrap(new SyntaxTagTrap(STEPPING_TAG) {
-
-                @Override
-                public void tagTrappedAt(Node node, MaterializedFrame mFrame) {
-                    final int currentStackDepth = currentStackDepth();
-                    if (currentStackDepth <= stackDepth) {
-                        // HALT: stack depth unchanged or smaller; treat like StepInto
-                        --unfinishedStepCount;
-                        if (TRACE) {
-                            strategyTrace("TRAP BEFORE", "unfinished steps=%d stackDepth start=%d current=%d", unfinishedStepCount, stackDepth, currentStackDepth);
-                        }
-                        // Test should run in fast path
-                        if (unfinishedStepCount <= 0) {
-                            halt(node, mFrame, true);
-                        }
-                    } else {
-                        // CONTINUE: Stack depth increased; don't count as a step
-                        strategyTrace("STEP INTO", "unfinished steps=%d stackDepth start=%d current=%d", unfinishedStepCount, stackDepth, currentStackDepth);
-                        // Stop treating like StepInto, start treating like StepOut
-                        replaceStrategy(new StepOverNested(unfinishedStepCount, stackDepth));
-                    }
-                    strategyTrace("RESUME BEFORE", "");
-                }
-            });
-
-            Probe.setAfterTagTrap(new SyntaxTagTrap(CALL_TAG) {
-
-                @Override
-                public void tagTrappedAt(Node node, MaterializedFrame mFrame) {
-                    final int currentStackDepth = currentStackDepth();
-                    if (currentStackDepth < stackDepth) {
-                        // HALT: just "stepped out"
-                        --unfinishedStepCount;
-                        strategyTrace("TRAP AFTER", "unfinished steps=%d stackDepth: start=%d current=%d", unfinishedStepCount, stackDepth, currentStackDepth);
-                        // Should run in fast path
-                        if (unfinishedStepCount <= 0) {
-                            halt(node, mFrame, false);
-                        }
-                        strategyTrace("RESUME AFTER", "");
-                    }
-                }
-            });
-        }
-
-        @Override
-        protected void unsetStrategy() {
-            Probe.setBeforeTagTrap(null);
-            Probe.setAfterTagTrap(null);
-        }
-    }
-
-    /**
-     * Strategy: per-statement stepping, not into method calls, in effect while at increased stack
-     * depth
-     * <ul>
-     * <li>User breakpoints are enabled.</li>
-     * <li>Execution continues until either:
-     * <ol>
-     * <li>execution arrives at a STATEMENT node with stack depth no more than when started
-     * <strong>or:</strong></li>
-     * <li>the program completes <strong>or:</strong></li>
-     * </ol>
-     * </ul>
-     */
-    private final class StepOverNested extends StepStrategy {
-        private int unfinishedStepCount;
-        private final int startStackDepth;
-
-        StepOverNested(int stepCount, int startStackDepth) {
-            this.unfinishedStepCount = stepCount;
-            this.startStackDepth = startStackDepth;
-        }
-
-        @Override
-        protected void setStrategy(final int stackDepth) {
-            Probe.setBeforeTagTrap(new SyntaxTagTrap(STEPPING_TAG) {
-
-                @Override
-                public void tagTrappedAt(Node node, MaterializedFrame mFrame) {
-                    final int currentStackDepth = currentStackDepth();
-                    if (currentStackDepth <= startStackDepth) {
-                        // At original step depth (or smaller) after being nested
-                        --unfinishedStepCount;
-                        strategyTrace("TRAP AFTER", "unfinished steps=%d stackDepth start=%d current=%d", unfinishedStepCount, stackDepth, currentStackDepth);
-                        if (unfinishedStepCount <= 0) {
-                            halt(node, mFrame, false);
-                        }
-                        // TODO (mlvdv) fixme for multiple steps
-                        strategyTrace("RESUME BEFORE", "");
-                    }
-                }
-            });
-        }
-
-        @Override
-        protected void unsetStrategy() {
-            Probe.setBeforeTagTrap(null);
-        }
-    }
-
-    /**
-     * Information and debugging state for a single Truffle execution (which make take place over
-     * one or more suspended executions). This holds interaction state, for example what is
-     * executing (e.g. some {@link Source}), what the execution mode is ("stepping" or
-     * "continuing"). When not running, this holds a cache of the Truffle stack for this particular
-     * execution, effectively hiding the Truffle stack for any currently suspended executions (down
-     * the stack).
-     */
-    private final class DebugExecutionContext {
-
-        // Previous halted context in stack
-        private final DebugExecutionContext predecessor;
-
-        // The current execution level; first is 0.
-        private final int level;  // Number of contexts suspended below
-        private final Source source;
-        private final int contextStackBase;  // Where the stack for this execution starts
-        private final List<String> warnings = new ArrayList<>();
-
-        private boolean running;
-
-        /**
-         * The stepping strategy currently configured in the debugger.
-         */
-        private StepStrategy strategy;
-
-        /**
-         * Where halted; null if running.
-         */
-        private Node haltedNode;
-
-        /**
-         * Where halted; null if running.
-         */
-        private MaterializedFrame haltedFrame;
-
-        /**
-         * Cached list of stack frames when halted; null if running.
-         */
-        private List<FrameDebugDescription> frames = new ArrayList<>();
-
-        private DebugExecutionContext(Source executionSource, DebugExecutionContext previousContext) {
-            this.source = executionSource;
-            this.predecessor = previousContext;
-            this.level = previousContext == null ? 0 : previousContext.level + 1;
-
-            // "Base" is the number of stack frames for all nested (halted) executions.
-            this.contextStackBase = currentStackDepth();
-            this.running = true;
-            contextTrace("NEW CONTEXT");
-        }
-
-        /**
-         * Sets up a strategy for the next resumption of execution.
-         *
-         * @param stepStrategy
-         */
-        void setStrategy(StepStrategy stepStrategy) {
-            if (this.strategy == null) {
-                this.strategy = stepStrategy;
-                this.strategy.enable(this, currentStackDepth());
-                if (TRACE) {
-                    contextTrace("SET MODE <none>-->" + stepStrategy.getName());
-                }
-            } else {
-                strategy.disable();
-                strategy = stepStrategy;
-                strategy.enable(this, currentStackDepth());
-                contextTrace("SWITCH MODE %s-->%s", strategy.getName(), stepStrategy.getName());
-            }
-        }
-
-        void clearStrategy() {
-            if (strategy != null) {
-                final StepStrategy oldStrategy = strategy;
-                strategy.disable();
-                strategy = null;
-                contextTrace("CLEAR MODE %s--><none>", oldStrategy.getName());
-            }
-        }
-
-        /**
-         * Handle a program halt, caused by a breakpoint, stepping strategy, or other cause.
-         *
-         * @param astNode the guest language node at which execution is halted
-         * @param mFrame the current execution frame where execution is halted
-         * @param before {@code true} if halted <em>before</em> the node, else <em>after</em>.
-         */
-        @TruffleBoundary
-        void halt(Node astNode, MaterializedFrame mFrame, boolean before, String haltReason) {
-            assert running;
-            assert frames.isEmpty();
-            assert haltedNode == null;
-            assert haltedFrame == null;
-
-            haltedNode = astNode;
-            haltedFrame = mFrame;
-            running = false;
-
-            clearStrategy();
-
-            // Clean up, just in cased the one-shot breakpoints got confused
-            lineBreaks.disposeOneShots();
-
-            // Map the Truffle stack for this execution, ignore nested executions
-            // The top (current) frame is not produced by the iterator.
-            frames.add(new FrameDebugDescription(0, haltedNode, Truffle.getRuntime().getCurrentFrame()));
-            final int contextStackDepth = currentStackDepth() - contextStackBase;
-            final int[] frameCount = {1};
-            Truffle.getRuntime().iterateFrames(new FrameInstanceVisitor<FrameInstance>() {
-                @Override
-                public FrameInstance visitFrame(FrameInstance frameInstance) {
-                    if (frameCount[0] < contextStackDepth) {
-                        frames.add(new FrameDebugDescription(frameCount[0], frameInstance.getCallNode(), frameInstance));
-                        frameCount[0] = frameCount[0] + 1;
-                        return null;
-                    }
-                    return frameInstance;
-                }
-            });
-
-            if (TRACE) {
-                final String reason = haltReason == null ? "" : haltReason + "";
-                final String where = before ? "BEFORE" : "AFTER";
-                contextTrace("HALT %s : (%s) stack base=%d", where, reason, contextStackBase);
-                contextTrace("CURRENT STACK:");
-                printStack(OUT);
-            }
-
-            final List<String> recentWarnings = new ArrayList<>(warnings);
-            warnings.clear();
-
-            try {
-                // Pass control to the debug client with current execution suspended
-                debugClient.haltedAt(astNode, mFrame, recentWarnings);
-                // Debug client finished normally, execution resumes
-                // Presume that the client has set a new strategy (or default to Continue)
-                running = true;
-            } catch (KillException e) {
-                contextTrace("KILL");
-                throw e;
-            } finally {
-                haltedNode = null;
-                haltedFrame = null;
-                frames.clear();
-            }
-
-        }
-
-        List<FrameDebugDescription> getFrames() {
-            return Collections.unmodifiableList(frames);
-        }
-
-        void logWarning(String warning) {
-            warnings.add(warning);
-        }
-
-        // For tracing
-        private void printStack(PrintStream stream) {
-            getFrames();
-            if (frames == null) {
-                stream.println("<empty stack>");
-            } else {
-                final Visualizer visualizer = language.getDebugSupport().getVisualizer();
-                for (FrameDebugDescription frameDesc : frames) {
-                    final StringBuilder sb = new StringBuilder("    frame " + Integer.toString(frameDesc.index()));
-                    sb.append(":at " + visualizer.displaySourceLocation(frameDesc.node()));
-                    sb.append(":in '" + visualizer.displayMethodName(frameDesc.node()) + "'");
-                    stream.println(sb.toString());
-                }
-            }
-        }
-
-        void contextTrace(String format, Object... args) {
-            if (TRACE) {
-                final String srcName = (source != null) ? source.getName() : "no source";
-                DebugEngine.trace("<%d> %s (%s)", level, String.format(format, args), srcName);
-            }
-        }
-    }
-
-    // TODO (mlvdv) wish there were fast-path access to stack depth
-    /**
-     * Depth of current Truffle stack, including nested executions. Includes the top/current frame,
-     * which the standard iterator does not count: {@code 0} if no executions.
-     */
-    @TruffleBoundary
-    private static int currentStackDepth() {
-        final int[] count = {0};
-        Truffle.getRuntime().iterateFrames(new FrameInstanceVisitor<Void>() {
-            @Override
-            public Void visitFrame(FrameInstance frameInstance) {
-                count[0] = count[0] + 1;
-                return null;
-            }
-        });
-        return count[0] == 0 ? 0 : count[0] + 1;
-
-    }
-}
--- a/truffle/com.oracle.truffle.tools.debug.engine/src/com/oracle/truffle/tools/debug/engine/DebugException.java	Thu Jul 16 19:11:31 2015 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,42 +0,0 @@
-/*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.truffle.tools.debug.engine;
-
-/**
- * An unexpected failure in the operation of the {@link DebugEngine}.
- */
-public class DebugException extends Exception {
-
-    public DebugException(String string) {
-        super(string);
-    }
-
-    public DebugException(Exception ex) {
-        super(ex);
-    }
-
-    private static final long serialVersionUID = 3307454453821997224L;
-
-}
--- a/truffle/com.oracle.truffle.tools.debug.engine/src/com/oracle/truffle/tools/debug/engine/DebugExecutionSupport.java	Thu Jul 16 19:11:31 2015 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,136 +0,0 @@
-/*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.truffle.tools.debug.engine;
-
-import java.util.*;
-
-import com.oracle.truffle.api.debug.*;
-import com.oracle.truffle.api.frame.*;
-import com.oracle.truffle.api.instrument.*;
-import com.oracle.truffle.api.nodes.*;
-import com.oracle.truffle.api.source.*;
-
-/**
- * Access to language-specific support for debugging.
- */
-final class DebugExecutionSupport {
-
-    interface DebugExecutionListener {
-
-        /**
-         * Notifies that execution is about to start and requests initial execution mode.
-         */
-        void executionStarted(Source source, boolean stepInto);
-
-        /**
-         * Notification that the current execution has just ended.
-         */
-        void executionEnded();
-    }
-
-    private final String languageName;
-    private final DebugSupportProvider provider;
-    private final List<DebugExecutionListener> listeners = new ArrayList<>();
-
-    DebugExecutionSupport(String languageName, DebugSupportProvider provider) {
-        this.languageName = languageName;
-        this.provider = provider;
-    }
-
-    void addExecutionListener(DebugExecutionListener listener) {
-        assert listener != null;
-        listeners.add(listener);
-    }
-
-    String getLanguageName() {
-        return languageName;
-    }
-
-    Visualizer getVisualizer() {
-        return provider.getVisualizer();
-    }
-
-    /**
-     * Runs a script. If "StepInto" is specified, halts at the first location tagged as a
-     * {@linkplain StandardSyntaxTag#STATEMENT STATEMENT}.
-     */
-    void run(Source source, boolean stepInto) throws DebugException {
-        for (DebugExecutionListener listener : listeners) {
-            listener.executionStarted(source, stepInto);
-        }
-        try {
-            provider.run(source);
-        } catch (DebugSupportException ex) {
-            throw new DebugException(ex);
-        } finally {
-            for (DebugExecutionListener listener : listeners) {
-                listener.executionEnded();
-            }
-        }
-    }
-
-    /**
-     * Evaluates string of language code in a halted execution context, at top level if
-     * <code>mFrame==null</code>.
-     *
-     * @throws DebugException
-     */
-    Object evalInContext(Source source, Node node, MaterializedFrame mFrame) throws DebugException {
-        for (DebugExecutionListener listener : listeners) {
-            listener.executionStarted(source, false);
-        }
-        try {
-            return provider.evalInContext(source, node, mFrame);
-        } catch (DebugSupportException ex) {
-            throw new DebugException(ex);
-        } finally {
-            for (DebugExecutionListener listener : listeners) {
-                listener.executionEnded();
-            }
-        }
-    }
-
-    /**
-     * Creates a language-specific factory to produce instances of {@link AdvancedInstrumentRoot}
-     * that, when executed, computes the result of a textual expression in the language; used to
-     * create an
-     * {@linkplain Instrument#create(AdvancedInstrumentResultListener, AdvancedInstrumentRootFactory, Class, String)
-     * Advanced Instrument}.
-     *
-     * @param expr a guest language expression
-     * @param resultListener optional listener for the result of each evaluation.
-     * @return a new factory
-     * @throws DebugException if the factory cannot be created, for example if the expression is
-     *             badly formed.
-     */
-    AdvancedInstrumentRootFactory createAdvancedInstrumentRootFactory(String expr, AdvancedInstrumentResultListener resultListener) throws DebugException {
-        try {
-            return provider.createAdvancedInstrumentRootFactory(expr, resultListener);
-        } catch (DebugSupportException ex) {
-            throw new DebugException(ex);
-        }
-    }
-
-}
--- a/truffle/com.oracle.truffle.tools.debug.engine/src/com/oracle/truffle/tools/debug/engine/FrameDebugDescription.java	Thu Jul 16 19:11:31 2015 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,67 +0,0 @@
-/*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.truffle.tools.debug.engine;
-
-import com.oracle.truffle.api.frame.*;
-import com.oracle.truffle.api.nodes.*;
-
-/**
- * A summary description of a Truffle {@link Frame} in a particular stack context.
- *
- * @see DebugEngine
- */
-public final class FrameDebugDescription {
-
-    private final int index;
-    private final Node node;
-    private final FrameInstance frameInstance;
-
-    FrameDebugDescription(int index, Node node, FrameInstance frameInstance) {
-        this.index = index;
-        this.node = node;
-        this.frameInstance = frameInstance;
-    }
-
-    /**
-     * Position in the current stack: {@code 0} at the top.
-     */
-    public int index() {
-        return index;
-    }
-
-    /**
-     * AST location.
-     */
-    public Node node() {
-        return node;
-    }
-
-    /**
-     * Access to the Truffle {@link Frame}.
-     */
-    public FrameInstance frameInstance() {
-        return frameInstance;
-    }
-}
--- a/truffle/com.oracle.truffle.tools.debug.engine/src/com/oracle/truffle/tools/debug/engine/LineBreakpoint.java	Thu Jul 16 19:11:31 2015 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,47 +0,0 @@
-/*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.truffle.tools.debug.engine;
-
-import com.oracle.truffle.api.source.*;
-
-// TODO (mlvdv) generic?
-/**
- * A breakpoint associated with a {@linkplain LineLocation source line location}.
- *
- * @see DebugEngine
- */
-public abstract class LineBreakpoint extends Breakpoint {
-
-    LineBreakpoint(BreakpointState state, int groupId, int ignoreCount, boolean isOneShot) {
-        super(state, groupId, ignoreCount, isOneShot);
-    }
-
-    /**
-     * Gets the {@linkplain LineLocation source line location} that specifies where this breakpoint
-     * will trigger.
-     */
-    public abstract LineLocation getLineLocation();
-
-}
--- a/truffle/com.oracle.truffle.tools.debug.engine/src/com/oracle/truffle/tools/debug/engine/LineBreakpointFactory.java	Thu Jul 16 19:11:31 2015 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,478 +0,0 @@
-/*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.truffle.tools.debug.engine;
-
-import static com.oracle.truffle.tools.debug.engine.Breakpoint.BreakpointState.*;
-
-import java.io.*;
-import java.util.*;
-import java.util.Map.Entry;
-
-import com.oracle.truffle.api.*;
-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.*;
-import com.oracle.truffle.api.instrument.impl.*;
-import com.oracle.truffle.api.nodes.*;
-import com.oracle.truffle.api.source.*;
-import com.oracle.truffle.api.utilities.*;
-import com.oracle.truffle.tools.*;
-import com.oracle.truffle.tools.debug.engine.DebugEngine.BreakpointCallback;
-import com.oracle.truffle.tools.debug.engine.DebugEngine.WarningLog;
-
-//TODO (mlvdv) some common functionality could be factored out of this and TagBreakpointSupport
-
-/**
- * Support class for creating and managing all existing ordinary (user visible) line breakpoints.
- * <p>
- * Notes:
- * <ol>
- * <li>Line breakpoints can only be set at nodes tagged as {@link StandardSyntaxTag#STATEMENT}.</li>
- * <li>A newly created breakpoint looks for probes matching the location, attaches to them if found
- * by installing an {@link Instrument} that calls back to the breakpoint.</li>
- * <li>When Truffle "splits" or otherwise copies an AST, any attached {@link Instrument} will be
- * copied along with the rest of the AST and will call back to the same breakpoint.</li>
- * <li>When notification is received of a new Node being tagged as a statement, and if a
- * breakpoint's line location matches the Probe's line location, then the breakpoint will attach a
- * new Instrument at the probe to activate the breakpoint at that location.</li>
- * <li>A breakpoint may have multiple Instruments deployed, one attached to each Probe that matches
- * the breakpoint's line location; this might happen when a source is reloaded.</li>
- * </ol>
- *
- */
-final class LineBreakpointFactory {
-
-    private static final boolean TRACE = false;
-    private static final PrintStream OUT = System.out;
-
-    private static final String BREAKPOINT_NAME = "LINE BREAKPOINT";
-
-    private static void trace(String format, Object... args) {
-        if (TRACE) {
-            OUT.println(String.format("%s: %s", BREAKPOINT_NAME, String.format(format, args)));
-        }
-    }
-
-    private static final Comparator<Entry<LineLocation, LineBreakpointImpl>> BREAKPOINT_COMPARATOR = new Comparator<Entry<LineLocation, LineBreakpointImpl>>() {
-
-        @Override
-        public int compare(Entry<LineLocation, LineBreakpointImpl> entry1, Entry<LineLocation, LineBreakpointImpl> entry2) {
-            final LineLocation line1 = entry1.getKey();
-            final LineLocation line2 = entry2.getKey();
-            final int nameOrder = line1.getSource().getShortName().compareTo(line2.getSource().getShortName());
-            if (nameOrder != 0) {
-                return nameOrder;
-            }
-            return Integer.compare(line1.getLineNumber(), line2.getLineNumber());
-        }
-    };
-
-    private final DebugExecutionSupport executionSupport;
-    private final BreakpointCallback breakpointCallback;
-    private final WarningLog warningLog;
-
-    /**
-     * Map: Source lines ==> attached breakpoints. There may be no more than one line breakpoint
-     * associated with a line.
-     */
-    private final Map<LineLocation, LineBreakpointImpl> lineToBreakpoint = new HashMap<>();
-
-    /**
-     * A map of {@link LineLocation} to a collection of {@link Probe}s. This list must be
-     * initialized and filled prior to being used by this class.
-     */
-    private final LineToProbesMap lineToProbesMap;
-
-    /**
-     * Globally suspends all line breakpoint activity when {@code false}, ignoring whether
-     * individual breakpoints are enabled.
-     */
-    @CompilationFinal private boolean breakpointsActive = true;
-    private final CyclicAssumption breakpointsActiveUnchanged = new CyclicAssumption(BREAKPOINT_NAME + " globally active");
-
-    LineBreakpointFactory(DebugExecutionSupport executionSupport, BreakpointCallback breakpointCallback, final WarningLog warningLog) {
-        this.executionSupport = executionSupport;
-        this.breakpointCallback = breakpointCallback;
-        this.warningLog = warningLog;
-
-        lineToProbesMap = new LineToProbesMap();
-        lineToProbesMap.install();
-
-        Probe.addProbeListener(new DefaultProbeListener() {
-
-            @Override
-            public void probeTaggedAs(Probe probe, SyntaxTag tag, Object tagValue) {
-                if (tag == StandardSyntaxTag.STATEMENT) {
-                    final SourceSection sourceSection = probe.getProbedSourceSection();
-                    if (sourceSection != null) {
-                        final LineLocation lineLocation = sourceSection.getLineLocation();
-                        if (lineLocation != null) {
-                            // A Probe with line location tagged STATEMENT we haven't seen before.
-                            final LineBreakpointImpl breakpoint = lineToBreakpoint.get(lineLocation);
-                            if (breakpoint != null) {
-                                try {
-                                    breakpoint.attach(probe);
-                                } catch (DebugException e) {
-                                    warningLog.addWarning(BREAKPOINT_NAME + " failure attaching to newly tagged Probe: " + e.getMessage());
-                                    if (TRACE) {
-                                        OUT.println(BREAKPOINT_NAME + " failure: " + e.getMessage());
-                                    }
-                                }
-                            }
-                        }
-                    }
-                }
-            }
-        });
-    }
-
-    /**
-     * Globally enables line breakpoint activity; all breakpoints are ignored when set to
-     * {@code false}. When set to {@code true}, the enabled/disabled status of each breakpoint
-     * determines whether it will trigger when flow of execution reaches it.
-     *
-     * @param breakpointsActive
-     */
-    void setActive(boolean breakpointsActive) {
-        if (this.breakpointsActive != breakpointsActive) {
-            breakpointsActiveUnchanged.invalidate();
-            this.breakpointsActive = breakpointsActive;
-        }
-    }
-
-    /**
-     * Returns the (not yet disposed) breakpoint by id; null if none.
-     */
-    LineBreakpoint find(long id) {
-        for (LineBreakpoint breakpoint : lineToBreakpoint.values()) {
-            if (breakpoint.getId() == id) {
-                return breakpoint;
-            }
-        }
-        return null;
-    }
-
-    /**
-     * Gets all current line breakpoints,regardless of status; sorted and modification safe.
-     */
-    List<LineBreakpoint> getAll() {
-        ArrayList<Entry<LineLocation, LineBreakpointImpl>> entries = new ArrayList<>(lineToBreakpoint.entrySet());
-        Collections.sort(entries, BREAKPOINT_COMPARATOR);
-
-        final ArrayList<LineBreakpoint> breakpoints = new ArrayList<>(entries.size());
-        for (Entry<LineLocation, LineBreakpointImpl> entry : entries) {
-            breakpoints.add(entry.getValue());
-        }
-        return breakpoints;
-    }
-
-    /**
-     * Creates a new line breakpoint if one doesn't already exist. If one does exist, then resets
-     * the <em>ignore count</em>.
-     *
-     * @param lineLocation where to set the breakpoint
-     * @param ignoreCount number of initial hits before the breakpoint starts causing breaks.
-     * @param oneShot whether the breakpoint should dispose itself after one hit
-     * @return a possibly new breakpoint
-     * @throws DebugException if a breakpoint already exists at the location and the ignore count is
-     *             the same
-     */
-    LineBreakpoint create(int groupId, int ignoreCount, LineLocation lineLocation, boolean oneShot) throws DebugException {
-
-        LineBreakpointImpl breakpoint = lineToBreakpoint.get(lineLocation);
-
-        if (breakpoint == null) {
-            breakpoint = new LineBreakpointImpl(groupId, ignoreCount, lineLocation, oneShot);
-
-            if (TRACE) {
-                trace("NEW " + breakpoint.getShortDescription());
-            }
-
-            lineToBreakpoint.put(lineLocation, breakpoint);
-
-            for (Probe probe : lineToProbesMap.findProbes(lineLocation)) {
-                if (probe.isTaggedAs(StandardSyntaxTag.STATEMENT)) {
-                    breakpoint.attach(probe);
-                    break;
-                }
-            }
-        } else {
-            if (ignoreCount == breakpoint.getIgnoreCount()) {
-                throw new DebugException(BREAKPOINT_NAME + " already set at line " + lineLocation);
-            }
-            breakpoint.setIgnoreCount(ignoreCount);
-            if (TRACE) {
-                trace("CHANGED ignoreCount %s", breakpoint.getShortDescription());
-            }
-        }
-        return breakpoint;
-    }
-
-    /**
-     * Returns the {@link LineBreakpoint} for a given line. There should only ever be one breakpoint
-     * per line.
-     *
-     * @param lineLocation The {@link LineLocation} to get the breakpoint for.
-     * @return The breakpoint for the given line.
-     */
-    LineBreakpoint get(LineLocation lineLocation) {
-        return lineToBreakpoint.get(lineLocation);
-    }
-
-    /**
-     * Removes the associated instrumentation for all one-shot breakpoints only.
-     */
-    void disposeOneShots() {
-        List<LineBreakpointImpl> breakpoints = new ArrayList<>(lineToBreakpoint.values());
-        for (LineBreakpointImpl breakpoint : breakpoints) {
-            if (breakpoint.isOneShot()) {
-                breakpoint.dispose();
-            }
-        }
-    }
-
-    /**
-     * Removes all knowledge of a breakpoint, presumed disposed.
-     */
-    private void forget(LineBreakpointImpl breakpoint) {
-        lineToBreakpoint.remove(breakpoint.getLineLocation());
-    }
-
-    /**
-     * Concrete representation of a line breakpoint, implemented by attaching an instrument to a
-     * probe at the designated source location.
-     */
-    private final class LineBreakpointImpl extends LineBreakpoint implements AdvancedInstrumentResultListener {
-
-        private static final String SHOULD_NOT_HAPPEN = "LineBreakpointImpl:  should not happen";
-
-        private final LineLocation lineLocation;
-
-        // Cached assumption that the global status of line breakpoint activity has not changed.
-        private Assumption breakpointsActiveAssumption;
-
-        // Whether this breakpoint is enable/disabled
-        @CompilationFinal private boolean isEnabled;
-        private Assumption enabledUnchangedAssumption;
-
-        private String conditionExpr;
-
-        /**
-         * The instrument(s) that this breakpoint currently has attached to a {@link Probe}:
-         * {@code null} if not attached.
-         */
-        private List<Instrument> instruments = new ArrayList<>();
-
-        public LineBreakpointImpl(int groupId, int ignoreCount, LineLocation lineLocation, boolean oneShot) {
-            super(ENABLED_UNRESOLVED, groupId, ignoreCount, oneShot);
-            this.lineLocation = lineLocation;
-
-            this.breakpointsActiveAssumption = LineBreakpointFactory.this.breakpointsActiveUnchanged.getAssumption();
-            this.isEnabled = true;
-            this.enabledUnchangedAssumption = Truffle.getRuntime().createAssumption(BREAKPOINT_NAME + " enabled state unchanged");
-        }
-
-        @Override
-        public boolean isEnabled() {
-            return isEnabled;
-        }
-
-        @Override
-        public void setEnabled(boolean enabled) {
-            if (enabled != isEnabled) {
-                switch (getState()) {
-                    case ENABLED:
-                        assert !enabled : SHOULD_NOT_HAPPEN;
-                        doSetEnabled(false);
-                        changeState(DISABLED);
-                        break;
-                    case ENABLED_UNRESOLVED:
-                        assert !enabled : SHOULD_NOT_HAPPEN;
-                        doSetEnabled(false);
-                        changeState(DISABLED_UNRESOLVED);
-                        break;
-                    case DISABLED:
-                        assert enabled : SHOULD_NOT_HAPPEN;
-                        doSetEnabled(true);
-                        changeState(ENABLED);
-                        break;
-                    case DISABLED_UNRESOLVED:
-                        assert enabled : SHOULD_NOT_HAPPEN;
-                        doSetEnabled(true);
-                        changeState(DISABLED_UNRESOLVED);
-                        break;
-                    case DISPOSED:
-                        assert false : "breakpoint disposed";
-                        break;
-                    default:
-                        assert false : SHOULD_NOT_HAPPEN;
-                        break;
-                }
-            }
-        }
-
-        @Override
-        public void setCondition(String expr) throws DebugException {
-            if (this.conditionExpr != null || expr != null) {
-                // De-instrument the Probes instrumented by this breakpoint
-                final ArrayList<Probe> probes = new ArrayList<>();
-                for (Instrument instrument : instruments) {
-                    probes.add(instrument.getProbe());
-                    instrument.dispose();
-                }
-                instruments.clear();
-                this.conditionExpr = expr;
-                // Re-instrument the probes previously instrumented
-                for (Probe probe : probes) {
-                    attach(probe);
-                }
-            }
-        }
-
-        @Override
-        public String getCondition() {
-            return conditionExpr;
-        }
-
-        @Override
-        public void dispose() {
-            if (getState() != DISPOSED) {
-                for (Instrument instrument : instruments) {
-                    instrument.dispose();
-                }
-                changeState(DISPOSED);
-                LineBreakpointFactory.this.forget(this);
-            }
-        }
-
-        private void attach(Probe newProbe) throws DebugException {
-            if (getState() == DISPOSED) {
-                throw new IllegalStateException("Attempt to attach a disposed " + BREAKPOINT_NAME);
-            }
-            Instrument newInstrument = null;
-            if (conditionExpr == null) {
-                newInstrument = Instrument.create(new UnconditionalLineBreakInstrumentListener(), BREAKPOINT_NAME);
-            } else {
-                newInstrument = Instrument.create(this, executionSupport.createAdvancedInstrumentRootFactory(conditionExpr, this), Boolean.class, BREAKPOINT_NAME);
-            }
-            newProbe.attach(newInstrument);
-            instruments.add(newInstrument);
-            changeState(isEnabled ? ENABLED : DISABLED);
-        }
-
-        private void doSetEnabled(boolean enabled) {
-            if (this.isEnabled != enabled) {
-                enabledUnchangedAssumption.invalidate();
-                this.isEnabled = enabled;
-            }
-        }
-
-        private String getShortDescription() {
-            return BREAKPOINT_NAME + "@" + getLineLocation().getShortDescription();
-        }
-
-        private void changeState(BreakpointState after) {
-            if (TRACE) {
-                trace("STATE %s-->%s %s", getState().getName(), after.getName(), getShortDescription());
-            }
-            setState(after);
-        }
-
-        private void doBreak(Node node, VirtualFrame vFrame) {
-            if (incrHitCountCheckIgnore()) {
-                breakpointCallback.haltedAt(node, vFrame.materialize(), BREAKPOINT_NAME);
-            }
-        }
-
-        /**
-         * Receives notification from the attached instrument that execution is about to enter node
-         * where the breakpoint is set. Designed so that when in the fast path, there is either an
-         * unconditional "halt" call to the debugger or nothing.
-         */
-        private void nodeEnter(Node astNode, VirtualFrame vFrame) {
-
-            // Deopt if the global active/inactive flag has changed
-            try {
-                this.breakpointsActiveAssumption.check();
-            } catch (InvalidAssumptionException ex) {
-                this.breakpointsActiveAssumption = LineBreakpointFactory.this.breakpointsActiveUnchanged.getAssumption();
-            }
-
-            // Deopt if the enabled/disabled state of this breakpoint has changed
-            try {
-                this.enabledUnchangedAssumption.check();
-            } catch (InvalidAssumptionException ex) {
-                this.enabledUnchangedAssumption = Truffle.getRuntime().createAssumption("LineBreakpoint enabled state unchanged");
-            }
-
-            if (LineBreakpointFactory.this.breakpointsActive && this.isEnabled) {
-                if (isOneShot()) {
-                    dispose();
-                }
-                LineBreakpointImpl.this.doBreak(astNode, vFrame);
-            }
-        }
-
-        public void notifyResult(Node node, VirtualFrame vFrame, Object result) {
-            final boolean condition = (Boolean) result;
-            if (TRACE) {
-                trace("breakpoint condition = %b  %s", condition, getShortDescription());
-            }
-            if (condition) {
-                nodeEnter(node, vFrame);
-            }
-        }
-
-        @TruffleBoundary
-        public void notifyFailure(Node node, VirtualFrame vFrame, RuntimeException ex) {
-            warningLog.addWarning(String.format("Exception in %s:  %s", getShortDescription(), ex.getMessage()));
-            if (TRACE) {
-                trace("breakpoint failure = %s  %s", ex.toString(), getShortDescription());
-            }
-            // Take the breakpoint if evaluation fails.
-            nodeEnter(node, vFrame);
-        }
-
-        @Override
-        public String getLocationDescription() {
-            return "Line: " + lineLocation.getShortDescription();
-        }
-
-        @Override
-        public LineLocation getLineLocation() {
-            return lineLocation;
-        }
-
-        private final class UnconditionalLineBreakInstrumentListener extends DefaultStandardInstrumentListener {
-
-            @Override
-            public void enter(Probe probe, Node node, VirtualFrame vFrame) {
-                LineBreakpointImpl.this.nodeEnter(node, vFrame);
-            }
-        }
-    }
-
-}
--- a/truffle/com.oracle.truffle.tools.debug.engine/src/com/oracle/truffle/tools/debug/engine/TagBreakpoint.java	Thu Jul 16 19:11:31 2015 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,46 +0,0 @@
-/*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.truffle.tools.debug.engine;
-
-import com.oracle.truffle.api.instrument.*;
-
-// TODO (mlvdv) generic?
-/**
- * A breakpoint associated with a {@link SyntaxTag}.
- *
- * @see DebugEngine
- */
-public abstract class TagBreakpoint extends Breakpoint {
-
-    TagBreakpoint(BreakpointState state, int groupId, int ignoreCount, boolean isOneShot) {
-        super(state, groupId, ignoreCount, isOneShot);
-    }
-
-    /**
-     * Gets the tag that specifies where this breakpoint will trigger.
-     */
-    public abstract SyntaxTag getTag();
-
-}
--- a/truffle/com.oracle.truffle.tools.debug.engine/src/com/oracle/truffle/tools/debug/engine/TagBreakpointFactory.java	Thu Jul 16 19:11:31 2015 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,441 +0,0 @@
-/*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.truffle.tools.debug.engine;
-
-import static com.oracle.truffle.tools.debug.engine.Breakpoint.BreakpointState.*;
-
-import java.io.*;
-import java.util.*;
-import java.util.Map.Entry;
-
-import com.oracle.truffle.api.*;
-import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
-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.utilities.*;
-import com.oracle.truffle.tools.debug.engine.DebugEngine.BreakpointCallback;
-import com.oracle.truffle.tools.debug.engine.DebugEngine.WarningLog;
-
-// TODO (mlvdv) some common functionality could be factored out of this and LineBreakpointSupport
-
-/**
- * Support class for creating and managing "Tag Breakpoints". A Tag Breakpoint halts execution just
- * before reaching any node whose Probe carries a specified {@linkplain SyntaxTag Tag}.
- * <p>
- * The {@linkplain Probe#setBeforeTagTrap(SyntaxTagTrap) Tag Trap}, which is built directly into the
- * Instrumentation Framework, does the same thing more efficiently, but there may only be one Tag
- * Trap active at a time. Any number of tag breakpoints may coexist with the Tag Trap, but it would
- * be confusing to have a Tag Breakpoint set for the same Tag as the current Tag Trap.
- * <p>
- * Notes:
- * <ol>
- * <li>Only one Tag Breakpoint can be active for a specific {@linkplain SyntaxTag Tag}.</li>
- * <li>A newly created breakpoint looks for probes matching the tag, attaches to them if found by
- * installing an {@link Instrument}.</li>
- * <li>When Truffle "splits" or otherwise copies an AST, any attached {@link Instrument} will be
- * copied along with the rest of the AST and will call back to the same breakpoint.</li>
- * <li>When notification is received that the breakpoint's Tag has been newly added to a Node, then
- * the breakpoint will attach a new Instrument at the probe to activate the breakpoint at that
- * location.</li>
- * <li>A breakpoint may have multiple Instruments deployed, one attached to each Probe that holds
- * the breakpoint's tag; this might happen when a source is reloaded.</li>
- * </ol>
- */
-final class TagBreakpointFactory {
-
-    private static final boolean TRACE = false;
-    private static final PrintStream OUT = System.out;
-
-    private static final String BREAKPOINT_NAME = "TAG BREAKPOINT";
-
-    private static void trace(String format, Object... args) {
-        if (TRACE) {
-            OUT.println(String.format("%s: %s", BREAKPOINT_NAME, String.format(format, args)));
-        }
-    }
-
-    private static final Comparator<Entry<SyntaxTag, TagBreakpointImpl>> BREAKPOINT_COMPARATOR = new Comparator<Entry<SyntaxTag, TagBreakpointImpl>>() {
-
-        @Override
-        public int compare(Entry<SyntaxTag, TagBreakpointImpl> entry1, Entry<SyntaxTag, TagBreakpointImpl> entry2) {
-            return entry1.getKey().name().compareTo(entry2.getKey().name());
-        }
-    };
-
-    private final DebugExecutionSupport executionSupport;
-    private final BreakpointCallback breakpointCallback;
-    private final WarningLog warningLog;
-
-    /**
-     * Map: Tags ==> Tag Breakpoints. There may be no more than one breakpoint per Tag.
-     */
-    private final Map<SyntaxTag, TagBreakpointImpl> tagToBreakpoint = new HashMap<>();
-
-    /**
-     * Globally suspends all line breakpoint activity when {@code false}, ignoring whether
-     * individual breakpoints are enabled.
-     */
-    @CompilationFinal private boolean breakpointsActive = true;
-    private final CyclicAssumption breakpointsActiveUnchanged = new CyclicAssumption(BREAKPOINT_NAME + " globally active");
-
-    TagBreakpointFactory(DebugExecutionSupport executionSupport, BreakpointCallback breakpointCallback, final WarningLog warningLog) {
-        this.executionSupport = executionSupport;
-        this.breakpointCallback = breakpointCallback;
-        this.warningLog = warningLog;
-
-        Probe.addProbeListener(new DefaultProbeListener() {
-
-            @Override
-            public void probeTaggedAs(Probe probe, SyntaxTag tag, Object tagValue) {
-                final TagBreakpointImpl breakpoint = tagToBreakpoint.get(tag);
-                if (breakpoint != null) {
-                    try {
-                        breakpoint.attach(probe);
-                    } catch (DebugException e) {
-                        warningLog.addWarning(BREAKPOINT_NAME + " failure attaching to newly tagged Probe: " + e.getMessage());
-                        if (TRACE) {
-                            OUT.println(BREAKPOINT_NAME + " failure: " + e.getMessage());
-                        }
-                    }
-                }
-            }
-        });
-    }
-
-    /**
-     * Globally enables tag breakpoint activity; all breakpoints are ignored when set to
-     * {@code false}. When set to {@code true}, the enabled/disabled status of each breakpoint
-     * determines whether it will trigger when flow of execution reaches it.
-     *
-     * @param breakpointsActive
-     */
-    void setActive(boolean breakpointsActive) {
-        if (this.breakpointsActive != breakpointsActive) {
-            breakpointsActiveUnchanged.invalidate();
-            this.breakpointsActive = breakpointsActive;
-        }
-    }
-
-    /**
-     * Returns the (not yet disposed) breakpoint by id, if any; null if none.
-     */
-    TagBreakpoint find(long id) {
-        for (TagBreakpointImpl breakpoint : tagToBreakpoint.values()) {
-            if (breakpoint.getId() == id) {
-                return breakpoint;
-            }
-        }
-        return null;
-    }
-
-    /**
-     * Gets all current tag breakpoints,regardless of status; sorted and modification safe.
-     */
-    List<TagBreakpoint> getAll() {
-        ArrayList<Entry<SyntaxTag, TagBreakpointImpl>> entries = new ArrayList<>(tagToBreakpoint.entrySet());
-        Collections.sort(entries, BREAKPOINT_COMPARATOR);
-
-        final ArrayList<TagBreakpoint> breakpoints = new ArrayList<>(entries.size());
-        for (Entry<SyntaxTag, TagBreakpointImpl> entry : entries) {
-            breakpoints.add(entry.getValue());
-        }
-        return breakpoints;
-    }
-
-    /**
-     * Creates a new tag breakpoint if one doesn't already exist. If one does exist, then resets the
-     * <em>ignore count</em>.
-     *
-     * @param tag where to set the breakpoint
-     * @param ignoreCount number of initial hits before the breakpoint starts causing breaks.
-     * @param oneShot whether the breakpoint should dispose itself after one hit
-     * @return a possibly new breakpoint
-     * @throws DebugException if a breakpoint already exists for the tag and the ignore count is the
-     *             same
-     */
-    TagBreakpoint create(int groupId, int ignoreCount, SyntaxTag tag, boolean oneShot) throws DebugException {
-
-        TagBreakpointImpl breakpoint = tagToBreakpoint.get(tag);
-
-        if (breakpoint == null) {
-            breakpoint = new TagBreakpointImpl(groupId, ignoreCount, tag, oneShot);
-
-            if (TRACE) {
-                trace("NEW " + breakpoint.getShortDescription());
-            }
-
-            tagToBreakpoint.put(tag, breakpoint);
-
-            for (Probe probe : Probe.findProbesTaggedAs(tag)) {
-                breakpoint.attach(probe);
-            }
-        } else {
-            if (ignoreCount == breakpoint.getIgnoreCount()) {
-                throw new DebugException(BREAKPOINT_NAME + " already set for tag " + tag.name());
-            }
-            breakpoint.setIgnoreCount(ignoreCount);
-            if (TRACE) {
-                trace("CHANGED ignoreCount %s", breakpoint.getShortDescription());
-            }
-        }
-        return breakpoint;
-    }
-
-    /**
-     * Returns the {@link TagBreakpoint} for a given tag, {@code null} if none.
-     */
-    TagBreakpoint get(SyntaxTag tag) {
-        return tagToBreakpoint.get(tag);
-    }
-
-    /**
-     * Removes the associated instrumentation for all one-shot breakpoints only.
-     */
-    void disposeOneShots() {
-        List<TagBreakpointImpl> breakpoints = new ArrayList<>(tagToBreakpoint.values());
-        for (TagBreakpointImpl breakpoint : breakpoints) {
-            if (breakpoint.isOneShot()) {
-                breakpoint.dispose();
-            }
-        }
-    }
-
-    /**
-     * Removes all knowledge of a breakpoint, presumed disposed.
-     */
-    private void forget(TagBreakpointImpl breakpoint) {
-        tagToBreakpoint.remove(breakpoint.getTag());
-    }
-
-    /**
-     * Concrete representation of a line breakpoint, implemented by attaching an instrument to a
-     * probe at the designated source location.
-     */
-    private final class TagBreakpointImpl extends TagBreakpoint implements AdvancedInstrumentResultListener {
-
-        private static final String SHOULD_NOT_HAPPEN = "TagBreakpointImpl:  should not happen";
-
-        private final SyntaxTag tag;
-
-        // Cached assumption that the global status of tag breakpoint activity has not changed.
-        private Assumption breakpointsActiveAssumption;
-
-        // Whether this breakpoint is enable/disabled
-        @CompilationFinal private boolean isEnabled;
-        private Assumption enabledUnchangedAssumption;
-
-        private String conditionExpr;
-
-        /**
-         * The instrument(s) that this breakpoint currently has attached to a {@link Probe}:
-         * {@code null} if not attached.
-         */
-        private List<Instrument> instruments = new ArrayList<>();
-
-        private TagBreakpointImpl(int groupId, int ignoreCount, SyntaxTag tag, boolean oneShot) {
-            super(ENABLED, groupId, ignoreCount, oneShot);
-            this.tag = tag;
-            this.breakpointsActiveAssumption = TagBreakpointFactory.this.breakpointsActiveUnchanged.getAssumption();
-            this.isEnabled = true;
-            this.enabledUnchangedAssumption = Truffle.getRuntime().createAssumption(BREAKPOINT_NAME + " enabled state unchanged");
-        }
-
-        @Override
-        public boolean isEnabled() {
-            return isEnabled;
-        }
-
-        @Override
-        public void setEnabled(boolean enabled) {
-            // Tag Breakpoints are never unresolved
-            if (enabled != isEnabled) {
-                switch (getState()) {
-                    case ENABLED:
-                        assert !enabled : SHOULD_NOT_HAPPEN;
-                        doSetEnabled(false);
-                        changeState(DISABLED);
-                        break;
-                    case DISABLED:
-                        assert enabled : SHOULD_NOT_HAPPEN;
-                        doSetEnabled(true);
-                        changeState(ENABLED);
-                        break;
-                    case DISPOSED:
-                        assert false : "breakpoint disposed";
-                        break;
-                    case ENABLED_UNRESOLVED:
-                    case DISABLED_UNRESOLVED:
-                    default:
-                        assert false : SHOULD_NOT_HAPPEN;
-                        break;
-                }
-            }
-        }
-
-        @Override
-        public void setCondition(String expr) throws DebugException {
-            if (this.conditionExpr != null || expr != null) {
-                // De-instrument the Probes instrumented by this breakpoint
-                final ArrayList<Probe> probes = new ArrayList<>();
-                for (Instrument instrument : instruments) {
-                    probes.add(instrument.getProbe());
-                    instrument.dispose();
-                }
-                instruments.clear();
-                this.conditionExpr = expr;
-                // Re-instrument the probes previously instrumented
-                for (Probe probe : probes) {
-                    attach(probe);
-                }
-            }
-        }
-
-        @Override
-        public String getCondition() {
-            return conditionExpr;
-        }
-
-        @Override
-        public void dispose() {
-            if (getState() != DISPOSED) {
-                for (Instrument instrument : instruments) {
-                    instrument.dispose();
-                }
-                changeState(DISPOSED);
-                TagBreakpointFactory.this.forget(this);
-            }
-        }
-
-        private void attach(Probe newProbe) throws DebugException {
-            if (getState() == DISPOSED) {
-                throw new IllegalStateException("Attempt to attach a disposed " + BREAKPOINT_NAME);
-            }
-            Instrument newInstrument = null;
-            if (conditionExpr == null) {
-                newInstrument = Instrument.create(new UnconditionalTagBreakInstrumentListener(), BREAKPOINT_NAME);
-            } else {
-                newInstrument = Instrument.create(this, executionSupport.createAdvancedInstrumentRootFactory(conditionExpr, this), Boolean.class, BREAKPOINT_NAME);
-            }
-            newProbe.attach(newInstrument);
-            instruments.add(newInstrument);
-            changeState(isEnabled ? ENABLED : DISABLED);
-        }
-
-        private void doSetEnabled(boolean enabled) {
-            if (this.isEnabled != enabled) {
-                enabledUnchangedAssumption.invalidate();
-                this.isEnabled = enabled;
-            }
-        }
-
-        private String getShortDescription() {
-            return BREAKPOINT_NAME + "@" + tag.name();
-        }
-
-        private void changeState(BreakpointState after) {
-            if (TRACE) {
-                trace("STATE %s-->%s %s", getState().getName(), after.getName(), getShortDescription());
-            }
-            setState(after);
-        }
-
-        private void doBreak(Node node, VirtualFrame vFrame) {
-            if (incrHitCountCheckIgnore()) {
-                breakpointCallback.haltedAt(node, vFrame.materialize(), BREAKPOINT_NAME);
-            }
-        }
-
-        /**
-         * Receives notification from the attached instrument that execution is about to enter node
-         * where the breakpoint is set. Designed so that when in the fast path, there is either an
-         * unconditional "halt" call to the debugger or nothing.
-         */
-        private void nodeEnter(Node astNode, VirtualFrame vFrame) {
-
-            // Deopt if the global active/inactive flag has changed
-            try {
-                this.breakpointsActiveAssumption.check();
-            } catch (InvalidAssumptionException ex) {
-                this.breakpointsActiveAssumption = TagBreakpointFactory.this.breakpointsActiveUnchanged.getAssumption();
-            }
-
-            // Deopt if the enabled/disabled state of this breakpoint has changed
-            try {
-                this.enabledUnchangedAssumption.check();
-            } catch (InvalidAssumptionException ex) {
-                this.enabledUnchangedAssumption = Truffle.getRuntime().createAssumption("LineBreakpoint enabled state unchanged");
-            }
-
-            if (TagBreakpointFactory.this.breakpointsActive && this.isEnabled) {
-                if (isOneShot()) {
-                    dispose();
-                }
-                TagBreakpointImpl.this.doBreak(astNode, vFrame);
-            }
-
-        }
-
-        public void notifyResult(Node node, VirtualFrame vFrame, Object result) {
-            final boolean condition = (Boolean) result;
-            if (TRACE) {
-                trace("breakpoint condition = %b  %s", condition, getShortDescription());
-            }
-            if (condition) {
-                nodeEnter(node, vFrame);
-            }
-        }
-
-        public void notifyFailure(Node node, VirtualFrame vFrame, RuntimeException ex) {
-            warningLog.addWarning(String.format("Exception in %s:  %s", getShortDescription(), ex.getMessage()));
-            if (TRACE) {
-                trace("breakpoint failure = %s  %s", ex.toString(), getShortDescription());
-            }
-            // Take the breakpoint if evaluation fails.
-            nodeEnter(node, vFrame);
-        }
-
-        @Override
-        public String getLocationDescription() {
-            return "Tag " + tag.name();
-        }
-
-        @Override
-        public SyntaxTag getTag() {
-            return tag;
-        }
-
-        private final class UnconditionalTagBreakInstrumentListener extends DefaultStandardInstrumentListener {
-
-            @Override
-            public void enter(Probe probe, Node node, VirtualFrame vFrame) {
-                TagBreakpointImpl.this.nodeEnter(node, vFrame);
-            }
-        }
-
-    }
-
-}
--- a/truffle/com.oracle.truffle.tools.debug.engine/src/com/oracle/truffle/tools/debug/engine/package-info.java	Thu Jul 16 19:11:31 2015 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,62 +0,0 @@
-/*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-/**
- * This package contains the shared (language-agnostic) support for implementing debuggers
- * that work with Truffle-implemented languages.
- * <p>
- * This implementation is made possible by the general purpose Instrumentation Framework built
- * into the Truffle platform.  Some online documentation for the Instrumentation Framework is available
- * online:
- * <quote>
- * <a href="https://wiki.openjdk.java.net/display/Graal/Instrumentation+API">https://wiki.openjdk.java.net/display/Graal/Instrumentation+API</a>
- * </quote>
- * <p>
- * Debugging services for a Truffle-implemented language are provided by creating an instance
- * of {@link com.oracle.truffle.tools.debug.engine.DebugEngine} specialized for a specific language.  The DebugEngine can:
- * <ul>
- * <li>Load and run sources in the language</li>
- * <li>Set breakpoints possibly with conditions and other attributes, on source lines</li>
- * <li>Navigate by Continue, StepIn, StepOver, or StepOut</li>
- * <li>Examine the execution stack</li>
- * <li>Examine the contents of a stack frame</li>
- * <li>Evaluate a code fragment in the context of a stack frame</li>
- * </ul>
- * <p>
- * Specialization of the DebugEngine for a Truffle-implemented language takes several forms:
- * <ol>
- * <li>A specification from the language implementor that adds Instrumentation "tags" to the nodes
- * that a debugger should know about, for example Statements, Calls, and Throws</li>
- * <li>Methods to run programs/scripts generally, and more specifically run text fragments in the context of
- * a particular frame/Node in a halted Truffle execution</li>
- * <li>Utility methods, such as providing textual displays of Objects that represent values in the language</li>
- * </ol>
- * <p>
- * <strong>Note:</strong> Both the functionality and API for this package are under active development.
- * <p>
- * @see com.oracle.truffle.api.instrument
- */
-package com.oracle.truffle.tools.debug.engine;
-
--- a/truffle/com.oracle.truffle.tools.debug.shell/src/com/oracle/truffle/tools/debug/shell/REPLMessage.java	Thu Jul 16 19:11:31 2015 +0200
+++ b/truffle/com.oracle.truffle.tools.debug.shell/src/com/oracle/truffle/tools/debug/shell/REPLMessage.java	Sat Jul 18 18:03:36 2015 +0200
@@ -46,7 +46,6 @@
     public static final String BREAK_AT_THROW = "break-at-throw";
     public static final String BREAK_AT_THROW_ONCE = "break-at-throw-once";
     public static final String BREAKPOINT_CONDITION = "breakpoint-condition";
-    public static final String BREAKPOINT_GROUP_ID = "breakpoint-group-id";
     public static final String BREAKPOINT_HIT_COUNT = "breakpoint-hit-count";
     public static final String BREAKPOINT_ID = "breakpoint-id";
     public static final String BREAKPOINT_IGNORE_COUNT = "breakpoint-ignore-count";
--- a/truffle/com.oracle.truffle.tools.debug.shell/src/com/oracle/truffle/tools/debug/shell/REPLServer.java	Thu Jul 16 19:11:31 2015 +0200
+++ b/truffle/com.oracle.truffle.tools.debug.shell/src/com/oracle/truffle/tools/debug/shell/REPLServer.java	Sat Jul 18 18:03:36 2015 +0200
@@ -24,22 +24,46 @@
  */
 package com.oracle.truffle.tools.debug.shell;
 
+import com.oracle.truffle.api.debug.Breakpoint;
+import java.util.*;
+
 /**
  * The server side of a simple message-based protocol for a possibly remote language
  * Read-Eval-Print-Loop.
  */
-public interface REPLServer {
+public abstract class REPLServer {
 
     /**
      * Starts up a server; status returned in a message.
      */
-    REPLMessage start();
+    public abstract REPLMessage start();
 
     /**
      * Ask the server to handle a request. Return a non-empty array of messages to simulate remote
      * operation where the protocol has possibly multiple messages being returned asynchronously in
      * response to each request.
      */
-    REPLMessage[] receive(REPLMessage request);
+    public abstract REPLMessage[] receive(REPLMessage request);
+
+    private int breakpointCounter;
+    private Map<Breakpoint, Integer> breakpoints = new WeakHashMap<>();
+
+    protected final synchronized void registerBreakpoint(Breakpoint breakpoint) {
+        breakpoints.put(breakpoint, breakpointCounter++);
+    }
+
+    protected final synchronized Breakpoint findBreakpoint(int id) {
+        for (Map.Entry<Breakpoint, Integer> entrySet : breakpoints.entrySet()) {
+            if (id == entrySet.getValue()) {
+                return entrySet.getKey();
+            }
+        }
+        return null;
+    }
+
+    protected final synchronized int getBreakpointID(Breakpoint breakpoint) {
+        final Integer id = breakpoints.get(breakpoint);
+        return id == null ? -1 : id;
+    }
 
 }
--- a/truffle/com.oracle.truffle.tools.debug.shell/src/com/oracle/truffle/tools/debug/shell/client/SimpleREPLClient.java	Thu Jul 16 19:11:31 2015 +0200
+++ b/truffle/com.oracle.truffle.tools.debug.shell/src/com/oracle/truffle/tools/debug/shell/client/SimpleREPLClient.java	Sat Jul 18 18:03:36 2015 +0200
@@ -896,7 +896,6 @@
                     sb.append("@" + message.get(REPLMessage.INFO_VALUE));
                     sb.append(" (state=" + message.get(REPLMessage.BREAKPOINT_STATE));
                     if (verboseBreakpointInfoOption.getBool()) {
-                        sb.append(", group=" + Integer.parseInt(message.get(REPLMessage.BREAKPOINT_GROUP_ID)));
                         sb.append(", hits=" + Integer.parseInt(message.get(REPLMessage.BREAKPOINT_HIT_COUNT)));
                         sb.append(", ignore=" + Integer.parseInt(message.get(REPLMessage.BREAKPOINT_IGNORE_COUNT)));
                     }
--- a/truffle/com.oracle.truffle.tools.debug.shell/src/com/oracle/truffle/tools/debug/shell/package-info.java	Thu Jul 16 19:11:31 2015 +0200
+++ b/truffle/com.oracle.truffle.tools.debug.shell/src/com/oracle/truffle/tools/debug/shell/package-info.java	Sat Jul 18 18:03:36 2015 +0200
@@ -1,58 +1,56 @@
 /*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ * 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 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
+ * 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.
+ * 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.
+ * 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.
  */
 
 /**
- * This package contains an experimental framework for building simple command-line oriented debuggers
- * that work with Truffle-implemented languages; it is used mainly for testing Truffle's built-in
- * {@link com.oracle.truffle.tools.debug.engine.DebugEngine}, which actually provides the debugging services.
+ * This package contains an experimental framework for building simple command-line oriented
+ * debuggers that work with Truffle-implemented languages; it is used mainly for testing Truffle's
+ * built-in , which actually provides the
+ * debugging services.
  * <p>
- * Truffle debugging is made possible by the general purpose Instrumentation Framework built
- * into the Truffle platform.  Some online documentation for the Instrumentation Framework is available
+ * Truffle debugging is made possible by the general purpose Instrumentation Framework built into
+ * the Truffle platform. Some online documentation for the Instrumentation Framework is available
  * online:
- * <quote>
- * <a href="https://wiki.openjdk.java.net/display/Graal/Instrumentation+API">https://wiki.openjdk.java.net/display/Graal/Instrumentation+API</a>
- * </quote>
+ * <quote> <a href="https://wiki.openjdk.java.net/display/Graal/Instrumentation+API">https://wiki.
+ * openjdk.java.net/display/Graal/Instrumentation+API</a> </quote>
  * <p>
  * Building one of these command line debuggers requires creating language-specific instances of:
  * <ol>
- * <li>{@link com.oracle.truffle.tools.debug.engine.DebugEngine},
- * noting that this instance also depends on related services provided by the language implementation,</li>
- * <li>{@link com.oracle.truffle.tools.debug.shell.REPLServer}, best accomplished by copying the implementation for
- * Truffle's demonstration language "Simple" (a.k.a. "SL").</li>
+ * <li>DebugEngine, noting that this instance also
+ * depends on related services provided by the language implementation,</li>
+ * <li>{@link com.oracle.truffle.tools.debug.shell.REPLServer}, best accomplished by copying the
+ * implementation for Truffle's demonstration language "Simple" (a.k.a. "SL").</li>
  * </ol>
  *
- * <strong>Disclaimer: </strong> although these command line debuggers are useful, they are
- * not intended, and will not be maintained as, fully functioning debuggers.  They should be
- * considered valuable tools for the maintainers of the {@link com.oracle.truffle.tools.debug.engine.DebugEngine},
- * as well as for Truffle language implementors for whom concurrent access to any kind debugging services can
- * be quite helpful.
+ * <strong>Disclaimer: </strong> although these command line debuggers are useful, they are not
+ * intended, and will not be maintained as, fully functioning debuggers. They should be considered
+ * valuable tools for the maintainers of the
+ * DebugEngine, as well as for Truffle language
+ * implementors for whom concurrent access to any kind debugging services can be quite helpful.
  * <p>
- * <strong>Note:</strong> Both the functionality and API for this package are under active development.
+ * <strong>Note:</strong> Both the functionality and API for this package are under active
+ * development.
  * <p>
+ *
  * @see com.oracle.truffle.api.instrument
- * @see com.oracle.truffle.tools.debug.engine
  */
 package com.oracle.truffle.tools.debug.shell;
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/truffle/com.oracle.truffle.tools.debug.shell/src/com/oracle/truffle/tools/debug/shell/server/FrameDebugDescription.java	Sat Jul 18 18:03:36 2015 +0200
@@ -0,0 +1,61 @@
+/*
+ * 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.tools.debug.shell.server;
+
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.nodes.*;
+
+public final class FrameDebugDescription {
+    private final int index;
+    private final Node node;
+    private final FrameInstance frameInstance;
+
+    FrameDebugDescription(int index, Node node, FrameInstance frameInstance) {
+        this.index = index;
+        this.node = node;
+        this.frameInstance = frameInstance;
+    }
+
+    /**
+     * Position in the current stack: {@code 0} at the top.
+     */
+    public int index() {
+        return index;
+    }
+
+    /**
+     * AST location.
+     */
+    public Node node() {
+        return node;
+    }
+
+    /**
+     * Access to the Truffle {@link Frame}.
+     */
+    public FrameInstance frameInstance() {
+        return frameInstance;
+    }
+}
--- a/truffle/com.oracle.truffle.tools.debug.shell/src/com/oracle/truffle/tools/debug/shell/server/REPLHandler.java	Thu Jul 16 19:11:31 2015 +0200
+++ b/truffle/com.oracle.truffle.tools.debug.shell/src/com/oracle/truffle/tools/debug/shell/server/REPLHandler.java	Sat Jul 18 18:03:36 2015 +0200
@@ -24,14 +24,14 @@
  */
 package com.oracle.truffle.tools.debug.shell.server;
 
+import com.oracle.truffle.api.debug.Breakpoint;
+import java.io.*;
 import java.util.*;
 
 import com.oracle.truffle.api.frame.*;
 import com.oracle.truffle.api.instrument.*;
 import com.oracle.truffle.api.nodes.*;
 import com.oracle.truffle.api.source.*;
-import com.oracle.truffle.api.vm.TruffleVM.Language;
-import com.oracle.truffle.tools.debug.engine.*;
 import com.oracle.truffle.tools.debug.shell.*;
 
 /**
@@ -44,9 +44,6 @@
     // TODO (mlvdv) add support for setting/using ignore count
     private static final int DEFAULT_IGNORE_COUNT = 0;
 
-    // TODO (mlvdv) add support for setting/using groupId
-    private static final int DEFAULT_GROUP_ID = 0;
-
     private final String op;
 
     protected REPLHandler(String op) {
@@ -99,11 +96,9 @@
         return replies;
     }
 
-    protected static REPLMessage createBreakpointInfoMessage(Breakpoint breakpoint) {
+    static final REPLMessage createBreakpointInfoMessage(Breakpoint breakpoint, REPLServerContext serverContext) {
         final REPLMessage infoMessage = new REPLMessage(REPLMessage.OP, REPLMessage.BREAKPOINT_INFO);
-        infoMessage.put(REPLMessage.BREAKPOINT_ID, Integer.toString(breakpoint.getId()));
-        infoMessage.put(REPLMessage.BREAKPOINT_GROUP_ID, Integer.toString(breakpoint.getGroupId()));
-        infoMessage.put(REPLMessage.BREAKPOINT_STATE, breakpoint.getState().toString());
+        infoMessage.put(REPLMessage.BREAKPOINT_ID, Integer.toString(serverContext.getBreakpointID(breakpoint)));
         infoMessage.put(REPLMessage.BREAKPOINT_HIT_COUNT, Integer.toString(breakpoint.getHitCount()));
         infoMessage.put(REPLMessage.BREAKPOINT_IGNORE_COUNT, Integer.toString(breakpoint.getIgnoreCount()));
         infoMessage.put(REPLMessage.INFO_VALUE, breakpoint.getLocationDescription().toString());
@@ -115,7 +110,7 @@
     }
 
     protected static REPLMessage createFrameInfoMessage(final REPLServerContext serverContext, FrameDebugDescription frame) {
-        final Visualizer visualizer = serverContext.getLanguage().getDebugSupport().getVisualizer();
+        final Visualizer visualizer = serverContext.getVisualizer();
         final REPLMessage infoMessage = new REPLMessage(REPLMessage.OP, REPLMessage.FRAME_INFO);
         infoMessage.put(REPLMessage.FRAME_NUMBER, Integer.toString(frame.index()));
         final Node node = frame.node();
@@ -127,11 +122,11 @@
             SourceSection section = node.getSourceSection();
             if (section == null) {
                 section = node.getEncapsulatingSourceSection();
-                if (section != null) {
-                    infoMessage.put(REPLMessage.FILE_PATH, section.getSource().getPath());
-                    infoMessage.put(REPLMessage.LINE_NUMBER, Integer.toString(section.getStartLine()));
-                    infoMessage.put(REPLMessage.SOURCE_LINE_TEXT, section.getSource().getCode(section.getStartLine()));
-                }
+            }
+            if (section != null) {
+                infoMessage.put(REPLMessage.FILE_PATH, section.getSource().getPath());
+                infoMessage.put(REPLMessage.LINE_NUMBER, Integer.toString(section.getStartLine()));
+                infoMessage.put(REPLMessage.SOURCE_LINE_TEXT, section.getSource().getCode(section.getStartLine()));
             }
         }
         infoMessage.put(REPLMessage.STATUS, REPLMessage.SUCCEEDED);
@@ -144,7 +139,7 @@
         public REPLMessage[] receive(REPLMessage request, REPLServerContext serverContext) {
             final REPLMessage reply = createReply();
             final ArrayList<REPLMessage> frameMessages = new ArrayList<>();
-            for (FrameDebugDescription frame : serverContext.getDebugEngine().getStack()) {
+            for (FrameDebugDescription frame : serverContext.getStack()) {
                 frameMessages.add(createFrameInfoMessage(serverContext, frame));
             }
             if (frameMessages.size() > 0) {
@@ -179,15 +174,16 @@
             if (ignoreCount == null) {
                 ignoreCount = 0;
             }
-            LineBreakpoint breakpoint;
+            Breakpoint breakpoint;
             try {
-                breakpoint = serverContext.getDebugEngine().setLineBreakpoint(DEFAULT_GROUP_ID, DEFAULT_IGNORE_COUNT, source.createLineLocation(lineNumber), false);
+                breakpoint = serverContext.db().setLineBreakpoint(DEFAULT_IGNORE_COUNT, source.createLineLocation(lineNumber), false);
+                serverContext.registerBreakpoint(breakpoint);
             } catch (Exception ex) {
                 return finishReplyFailed(reply, ex.getMessage());
             }
             reply.put(REPLMessage.SOURCE_NAME, fileName);
             reply.put(REPLMessage.FILE_PATH, source.getPath());
-            reply.put(REPLMessage.BREAKPOINT_ID, Integer.toString(breakpoint.getId()));
+            reply.put(REPLMessage.BREAKPOINT_ID, Integer.toString(serverContext.getBreakpointID(breakpoint)));
             reply.put(REPLMessage.LINE_NUMBER, Integer.toString(lineNumber));
             reply.put(REPLMessage.BREAKPOINT_IGNORE_COUNT, ignoreCount.toString());
             return finishReplySucceeded(reply, "Breakpoint set");
@@ -216,7 +212,8 @@
                 return finishReplyFailed(reply, "missing line number");
             }
             try {
-                serverContext.getDebugEngine().setLineBreakpoint(DEFAULT_GROUP_ID, DEFAULT_IGNORE_COUNT, source.createLineLocation(lineNumber), true);
+                Breakpoint b = serverContext.db().setLineBreakpoint(DEFAULT_IGNORE_COUNT, source.createLineLocation(lineNumber), true);
+                serverContext.registerBreakpoint(b);
             } catch (Exception ex) {
                 return finishReplyFailed(reply, ex.getMessage());
             }
@@ -233,7 +230,8 @@
         public REPLMessage[] receive(REPLMessage request, REPLServerContext serverContext) {
             final REPLMessage reply = createReply();
             try {
-                serverContext.getDebugEngine().setTagBreakpoint(DEFAULT_GROUP_ID, DEFAULT_IGNORE_COUNT, StandardSyntaxTag.THROW, false);
+                Breakpoint b = serverContext.db().setTagBreakpoint(DEFAULT_IGNORE_COUNT, StandardSyntaxTag.THROW, false);
+                serverContext.registerBreakpoint(b);
                 return finishReplySucceeded(reply, "Breakpoint at any throw set");
             } catch (Exception ex) {
                 return finishReplyFailed(reply, ex.getMessage());
@@ -247,7 +245,7 @@
         public REPLMessage[] receive(REPLMessage request, REPLServerContext serverContext) {
             final REPLMessage reply = createReply();
             try {
-                serverContext.getDebugEngine().setTagBreakpoint(DEFAULT_GROUP_ID, DEFAULT_IGNORE_COUNT, StandardSyntaxTag.THROW, true);
+                serverContext.db().setTagBreakpoint(DEFAULT_IGNORE_COUNT, StandardSyntaxTag.THROW, true);
                 return finishReplySucceeded(reply, "One-shot breakpoint at any throw set");
             } catch (Exception ex) {
                 return finishReplyFailed(reply, ex.getMessage());
@@ -261,8 +259,8 @@
         public REPLMessage[] receive(REPLMessage request, REPLServerContext serverContext) {
             final REPLMessage reply = createReply();
             final ArrayList<REPLMessage> infoMessages = new ArrayList<>();
-            for (Breakpoint breakpoint : serverContext.getDebugEngine().getBreakpoints()) {
-                infoMessages.add(createBreakpointInfoMessage(breakpoint));
+            for (Breakpoint breakpoint : serverContext.db().getBreakpoints()) {
+                infoMessages.add(createBreakpointInfoMessage(breakpoint, serverContext));
             }
             if (infoMessages.size() > 0) {
                 return infoMessages.toArray(new REPLMessage[0]);
@@ -280,7 +278,7 @@
             if (breakpointNumber == null) {
                 return finishReplyFailed(reply, "missing breakpoint number");
             }
-            final Breakpoint breakpoint = serverContext.getDebugEngine().findBreakpoint(breakpointNumber);
+            final Breakpoint breakpoint = serverContext.findBreakpoint(breakpointNumber);
             if (breakpoint == null) {
                 return finishReplyFailed(reply, "no breakpoint number " + breakpointNumber);
             }
@@ -295,7 +293,7 @@
         @Override
         public REPLMessage[] receive(REPLMessage request, REPLServerContext serverContext) {
             final REPLMessage reply = createReply();
-            serverContext.getDebugEngine().prepareContinue();
+            serverContext.prepareContinue();
             return finishReplySucceeded(reply, "Continue mode entered");
         }
     };
@@ -306,7 +304,7 @@
         public REPLMessage[] receive(REPLMessage request, REPLServerContext serverContext) {
             final REPLMessage reply = createReply();
             int deleteCount = 0;
-            for (Breakpoint breakpoint : serverContext.getDebugEngine().getBreakpoints()) {
+            for (Breakpoint breakpoint : serverContext.db().getBreakpoints()) {
                 breakpoint.dispose();
                 deleteCount++;
             }
@@ -326,7 +324,7 @@
             if (breakpointNumber == null) {
                 return finishReplyFailed(reply, "missing breakpoint number");
             }
-            final Breakpoint breakpoint = serverContext.getDebugEngine().findBreakpoint(breakpointNumber);
+            final Breakpoint breakpoint = serverContext.findBreakpoint(breakpointNumber);
             if (breakpoint == null) {
                 return finishReplyFailed(reply, "no breakpoint number " + breakpointNumber);
             }
@@ -345,7 +343,7 @@
             if (breakpointNumber == null) {
                 return finishReplyFailed(reply, "missing breakpoint number");
             }
-            final Breakpoint breakpoint = serverContext.getDebugEngine().findBreakpoint(breakpointNumber);
+            final Breakpoint breakpoint = serverContext.findBreakpoint(breakpointNumber);
             if (breakpoint == null) {
                 return finishReplyFailed(reply, "no breakpoint number " + breakpointNumber);
             }
@@ -395,15 +393,14 @@
             if (frameNumber == null) {
                 return finishReplyFailed(reply, "no frame number specified");
             }
-            final List<FrameDebugDescription> stack = serverContext.getDebugEngine().getStack();
+            final List<FrameDebugDescription> stack = serverContext.getStack();
             if (frameNumber < 0 || frameNumber >= stack.size()) {
                 return finishReplyFailed(reply, "frame number " + frameNumber + " out of range");
             }
             final FrameDebugDescription frameDescription = stack.get(frameNumber);
             final REPLMessage frameMessage = createFrameInfoMessage(serverContext, frameDescription);
             final Frame frame = frameDescription.frameInstance().getFrame(FrameInstance.FrameAccess.READ_ONLY, true);
-            final Language language = serverContext.getLanguage();
-            final Visualizer visualizer = language.getDebugSupport().getVisualizer();
+            final Visualizer visualizer = serverContext.getVisualizer();
             final FrameDescriptor frameDescriptor = frame.getFrameDescriptor();
             try {
                 final StringBuilder sb = new StringBuilder();
@@ -452,7 +449,7 @@
                 return finishReplyFailed(message, "missing breakpoint number");
             }
             message.put(REPLMessage.BREAKPOINT_ID, Integer.toString(breakpointNumber));
-            final Breakpoint breakpoint = serverContext.getDebugEngine().findBreakpoint(breakpointNumber);
+            final Breakpoint breakpoint = serverContext.findBreakpoint(breakpointNumber);
             if (breakpoint == null) {
                 return finishReplyFailed(message, "no breakpoint number " + breakpointNumber);
             }
@@ -462,7 +459,7 @@
             }
             try {
                 breakpoint.setCondition(expr);
-            } catch (DebugException ex) {
+            } catch (IOException ex) {
                 return finishReplyFailed(message, "invalid condition for " + breakpointNumber);
             } catch (UnsupportedOperationException ex) {
                 return finishReplyFailed(message, "conditions not unsupported by breakpoint " + breakpointNumber);
@@ -481,7 +478,7 @@
             if (repeat == null) {
                 repeat = 1;
             }
-            serverContext.getDebugEngine().prepareStepInto(repeat);
+            serverContext.prepareStepInto(repeat);
             return finishReplySucceeded(reply, "StepInto <" + repeat + "> enabled");
         }
     };
@@ -490,7 +487,7 @@
 
         @Override
         public REPLMessage[] receive(REPLMessage request, REPLServerContext serverContext) {
-            serverContext.getDebugEngine().prepareStepOut();
+            serverContext.prepareStepOut();
             return finishReplySucceeded(createReply(), "StepOut enabled");
         }
     };
@@ -504,7 +501,7 @@
             if (repeat == null) {
                 repeat = 1;
             }
-            debugServerContextFrame.getDebugEngine().prepareStepOver(repeat);
+            debugServerContextFrame.prepareStepOver(repeat);
             return finishReplySucceeded(reply, "StepOver <" + repeat + "> enabled");
         }
     };
@@ -514,10 +511,10 @@
         @Override
         public REPLMessage[] receive(REPLMessage request, REPLServerContext serverContext) {
             final REPLMessage reply = createReply();
-            final ASTPrinter astPrinter = serverContext.getLanguage().getDebugSupport().getVisualizer().getASTPrinter();
+            final ASTPrinter astPrinter = serverContext.getVisualizer().getASTPrinter();
             final String topic = request.get(REPLMessage.TOPIC);
             reply.put(REPLMessage.TOPIC, topic);
-            Node node = serverContext.getNode();
+            Node node = serverContext.getNodeAtHalt();
             if (node == null) {
                 return finishReplyFailed(reply, "no current AST node");
             }
@@ -531,7 +528,7 @@
                         while (node.getParent() != null) {
                             node = node.getParent();
                         }
-                        final String astText = astPrinter.printTreeToString(node, depth, serverContext.getNode());
+                        final String astText = astPrinter.printTreeToString(node, depth, serverContext.getNodeAtHalt());
                         return finishReplySucceeded(reply, astText);
                     case REPLMessage.SUBTREE:
                     case REPLMessage.SUB:
@@ -557,13 +554,13 @@
                 return finishReplyFailed(message, "missing breakpoint number");
             }
             message.put(REPLMessage.BREAKPOINT_ID, Integer.toString(breakpointNumber));
-            final Breakpoint breakpoint = serverContext.getDebugEngine().findBreakpoint(breakpointNumber);
+            final Breakpoint breakpoint = serverContext.findBreakpoint(breakpointNumber);
             if (breakpoint == null) {
                 return finishReplyFailed(message, "no breakpoint number " + breakpointNumber);
             }
             try {
                 breakpoint.setCondition(null);
-            } catch (DebugException e) {
+            } catch (IOException e) {
                 return finishReplyFailed(message, e.getMessage());
             }
             return finishReplyFailed(message, "Breakpoint " + breakpointNumber + " condition cleared");
@@ -575,8 +572,8 @@
         @Override
         public REPLMessage[] receive(REPLMessage request, REPLServerContext serverContext) {
             final REPLMessage reply = createReply();
-            final ASTPrinter astPrinter = serverContext.getLanguage().getDebugSupport().getVisualizer().getASTPrinter();
-            final Node node = serverContext.getNode();
+            final ASTPrinter astPrinter = serverContext.getVisualizer().getASTPrinter();
+            final Node node = serverContext.getNodeAtHalt();
             if (node == null) {
                 return finishReplyFailed(reply, "no current AST node");
             }
--- a/truffle/com.oracle.truffle.tools.debug.shell/src/com/oracle/truffle/tools/debug/shell/server/REPLServerContext.java	Thu Jul 16 19:11:31 2015 +0200
+++ b/truffle/com.oracle.truffle.tools.debug.shell/src/com/oracle/truffle/tools/debug/shell/server/REPLServerContext.java	Sat Jul 18 18:03:36 2015 +0200
@@ -24,22 +24,27 @@
  */
 package com.oracle.truffle.tools.debug.shell.server;
 
+import com.oracle.truffle.api.debug.Breakpoint;
+import com.oracle.truffle.api.debug.Debugger;
+import com.oracle.truffle.api.debug.SuspendedEvent;
 import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.instrument.Visualizer;
+import com.oracle.truffle.api.instrument.impl.DefaultVisualizer;
 import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.api.vm.*;
 import com.oracle.truffle.api.vm.TruffleVM.Language;
-import com.oracle.truffle.tools.debug.engine.*;
 import com.oracle.truffle.tools.debug.shell.*;
+import java.util.ArrayList;
+import java.util.List;
 
 public abstract class REPLServerContext {
 
     private final int level;
-    private final Node astNode;
-    private final MaterializedFrame mFrame;
+    private final SuspendedEvent event;
 
-    protected REPLServerContext(int level, Node astNode, MaterializedFrame mFrame) {
+    protected REPLServerContext(int level, SuspendedEvent event) {
         this.level = level;
-        this.astNode = astNode;
-        this.mFrame = mFrame;
+        this.event = event;
     }
 
     /**
@@ -52,24 +57,65 @@
     /**
      * The AST node where execution is halted in this context.
      */
-    public Node getNode() {
-        return astNode;
+    public Node getNodeAtHalt() {
+        return event.getNode();
     }
 
     /**
      * The frame where execution is halted in this context.
      */
-    public MaterializedFrame getFrame() {
-        return mFrame;
+    public MaterializedFrame getFrameAtHalt() {
+        return event.getFrame();
     }
 
     public abstract Language getLanguage();
 
-    public abstract DebugEngine getDebugEngine();
+    public Visualizer getVisualizer() {
+        return new DefaultVisualizer();
+    }
+
+    public abstract TruffleVM vm();
+
+    protected abstract Debugger db();
 
     /**
      * Dispatches a REPL request to the appropriate handler.
      */
     public abstract REPLMessage[] receive(REPLMessage request);
 
+    public abstract void registerBreakpoint(Breakpoint breakpoint);
+
+    public abstract Breakpoint findBreakpoint(int id);
+
+    public abstract int getBreakpointID(Breakpoint breakpoint);
+
+    List<FrameDebugDescription> getStack() {
+        List<FrameDebugDescription> frames = new ArrayList<>();
+        int frameCount = 1;
+        for (FrameInstance frameInstance : event.getStack()) {
+            if (frameCount == 1) {
+                frames.add(new FrameDebugDescription(frameCount, event.getNode(), frameInstance));
+            } else {
+                frames.add(new FrameDebugDescription(frameCount, frameInstance.getCallNode(), frameInstance));
+            }
+            frameCount++;
+        }
+        return frames;
+    }
+
+    void prepareStepOut() {
+        event.prepareStepOut();
+    }
+
+    void prepareStepInto(int repeat) {
+        event.prepareStepInto(repeat);
+    }
+
+    void prepareStepOver(int repeat) {
+        event.prepareStepOver(repeat);
+    }
+
+    void prepareContinue() {
+        event.prepareContinue();
+    }
 }
--- a/truffle/com.oracle.truffle.tools.test/src/com/oracle/truffle/tools/test/TestNodes.java	Thu Jul 16 19:11:31 2015 +0200
+++ b/truffle/com.oracle.truffle.tools.test/src/com/oracle/truffle/tools/test/TestNodes.java	Sat Jul 18 18:03:36 2015 +0200
@@ -162,7 +162,7 @@
          * tests run in the same environment.
          */
         public TestRootNode(TestLanguageNode body) {
-            super(null);
+            super(TruffleLanguage.class, null, null);
             this.body = body;
         }