changeset 14094:3f27e57439ed

Truffle/Instrumentation: significant rearrangement (including moved class) and extension of the Truffle Instrumentation Framework. New interfaces include DebugContext (which can be attached to the ExecutionContext), through which access is provided to possibly language-specific (a) node instrumentation, (b) debug services manager, (c) notification when programs halt, (d) display of language values, and (e) display of variable identifiers.
author Michael Van De Vanter <michael.van.de.vanter@oracle.com>
date Mon, 03 Feb 2014 20:58:23 -0800
parents 64fa70319890
children cf16ff2dba69
files graal/com.oracle.truffle.api/src/com/oracle/truffle/api/ASTPrinter.java graal/com.oracle.truffle.api/src/com/oracle/truffle/api/DebugManager.java graal/com.oracle.truffle.api/src/com/oracle/truffle/api/ExecutionContext.java graal/com.oracle.truffle.api/src/com/oracle/truffle/api/debug/ASTPrinter.java graal/com.oracle.truffle.api/src/com/oracle/truffle/api/debug/DebugContext.java graal/com.oracle.truffle.api/src/com/oracle/truffle/api/debug/DebugManager.java graal/com.oracle.truffle.api/src/com/oracle/truffle/api/debug/DefaultDebugManager.java graal/com.oracle.truffle.api/src/com/oracle/truffle/api/debug/KillException.java graal/com.oracle.truffle.api/src/com/oracle/truffle/api/debug/QuitException.java graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultDebugManager.java graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/instrument/DefaultNodeInstrumenter.java graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/instrument/InstrumentationProbeNode.java graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/instrument/NodeInstrumenter.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/RubyNode.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/debug/RubyASTPrinter.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/debug/RubyProxyNode.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/instrument/DefaultRubyNodeInstrumenter.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/instrument/RubyASTPrinter.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/instrument/RubyNodeInstrumenter.java graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/instrument/RubyProxyNode.java graal/com.oracle.truffle.ruby.parser/src/com/oracle/truffle/ruby/parser/DefaultRubyNodeInstrumenter.java graal/com.oracle.truffle.ruby.parser/src/com/oracle/truffle/ruby/parser/JRubyParser.java graal/com.oracle.truffle.ruby.parser/src/com/oracle/truffle/ruby/parser/MinimumRubyDebugContext.java graal/com.oracle.truffle.ruby.parser/src/com/oracle/truffle/ruby/parser/RubyNodeInstrumenter.java graal/com.oracle.truffle.ruby.parser/src/com/oracle/truffle/ruby/parser/Translator.java graal/com.oracle.truffle.ruby.parser/src/com/oracle/truffle/ruby/parser/TranslatorEnvironment.java graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/RubyContext.java graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/control/BreakShellException.java graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/control/QuitException.java graal/com.oracle.truffle.ruby.shell/src/com/oracle/truffle/ruby/shell/Shell.java graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/RubyTests.java graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/SLScript.java
diffstat 32 files changed, 1158 insertions(+), 827 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/ASTPrinter.java	Wed Jan 22 21:34:00 2014 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,48 +0,0 @@
-/*
- * Copyright (c) 2013, 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 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;
-
-import java.io.*;
-
-import com.oracle.truffle.api.nodes.*;
-
-/**
- * Language-agnostic access to AST-based debugging support.
- * <p>
- * <strong>WARNING:</strong> this interface is under development and will change substantially.
- */
-public interface ASTPrinter {
-
-    /**
-     * Print a textual AST display, one line per node, with nesting.
-     * 
-     * @param p
-     * @param node the root node of the display.
-     * @param maxDepth the maximum number of levels to print below the root
-     * @param markNode a node to mark with a textual arrow prefix, if present.
-     */
-    void printTree(PrintWriter p, Node node, int maxDepth, Node markNode);
-
-}
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/DebugManager.java	Wed Jan 22 21:34:00 2014 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,70 +0,0 @@
-/*
- * Copyright (c) 2013, 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 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;
-
-import com.oracle.truffle.api.frame.*;
-import com.oracle.truffle.api.nodes.*;
-import com.oracle.truffle.api.nodes.instrument.*;
-import com.oracle.truffle.api.nodes.instrument.InstrumentationProbeNode.ProbeChain;
-
-/**
- * Language-agnostic access to AST-based debugging support.
- * <p>
- * <strong>Disclaimer:</strong> this interface is under development and will change.
- */
-public interface DebugManager {
-
-    /**
-     * Informs the {@link DebugManager} that the Guest Language runtime is starting to load a
-     * source. Care should be taken to ensure that under any circumstance there is always a
-     * following call to {@link #notifyFinishedLoading(Source)} with the same argument.
-     */
-    void notifyStartLoading(Source source);
-
-    /**
-     * Informs the {@link DebugManager} that the Guest Language runtime has finished loading a
-     * source. Care should be taken to ensure that under any circumstance there is always a prior
-     * call to {@link #notifyStartLoading(Source)} with the same argument.
-     */
-    void notifyFinishedLoading(Source source);
-
-    /**
-     * Return a reference to the (canonical) instrumentation site associated with a particular
-     * source code location; this site will have effect on any Truffle/AST implementation
-     * corresponding to the source location, even if the AST is copied multiple times.
-     */
-    ProbeChain getProbeChain(SourceSection sourceSection);
-
-    /**
-     * Informs the {@link DebugManager} that Truffle execution has halted; execution will resume
-     * when this method returns.
-     * 
-     * @param astNode a guest language AST node that represents the current execution site, assumed
-     *            not to be any kind of {@link InstrumentationNode},
-     * @param frame execution frame at the site where execution suspended
-     */
-    void haltedAt(Node astNode, MaterializedFrame frame);
-
-}
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/ExecutionContext.java	Wed Jan 22 21:34:00 2014 -0800
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/ExecutionContext.java	Mon Feb 03 20:58:23 2014 -0800
@@ -24,6 +24,9 @@
  */
 package com.oracle.truffle.api;
 
+import com.oracle.truffle.api.debug.*;
+import com.oracle.truffle.api.source.*;
+
 /**
  * Information about the runtime context of a Truffle program.
  * <p>
@@ -38,8 +41,13 @@
     String getLanguageShortName();
 
     /**
-     * Gets access to debugging services, {@code null} if not enabled in this context.
+     * Gets access to source management services.
      */
-    DebugManager getDebugManager();
+    SourceManager getSourceManager();
+
+    /**
+     * Gets access to debugging services. Returns an inert instance if no services installed.
+     */
+    DebugContext getDebugContext();
 
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/debug/ASTPrinter.java	Mon Feb 03 20:58:23 2014 -0800
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2013, 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 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 com.oracle.truffle.api.nodes.*;
+
+/**
+ * Language-agnostic access to AST-based debugging support.
+ * <p>
+ * <strong>WARNING:</strong> this interface is under development and will change substantially.
+ */
+public interface ASTPrinter {
+
+    /**
+     * Prints a textual AST display, one line per node, with nesting.
+     * 
+     * @param p
+     * @param node the root node of the display.
+     * @param maxDepth the maximum number of levels to print below the root
+     * @param markNode a node to mark with a textual arrow prefix, if present.
+     */
+    void printTree(PrintWriter p, Node node, int maxDepth, Node markNode);
+
+    /**
+     * Creates a textual AST display, one line per node, with nesting.
+     * 
+     * @param node the root node of the display.
+     * @param maxDepth the maximum number of levels to print below the root
+     * @param markNode a node to mark with a textual arrow prefix, if present.
+     */
+    String printTreeToString(Node node, int maxDepth, Node markNode);
+
+    /**
+     * Creates a textual AST display, one line per node, with nesting.
+     * 
+     * @param node the root node of the display.
+     * @param maxDepth the maximum number of levels to print below the root
+     */
+    String printTreeToString(Node node, int maxDepth);
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/debug/DebugContext.java	Mon Feb 03 20:58:23 2014 -0800
@@ -0,0 +1,72 @@
+/*
+ * 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 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.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.api.nodes.instrument.*;
+
+/**
+ * Access to the suite of facilities available when debugging is enabled.
+ */
+public interface DebugContext {
+
+    /**
+     * Access to the Truffle execution context being debugged.
+     */
+    ExecutionContext getContext();
+
+    /**
+     * Access to the appropriate implementation of AST node instrumentation.
+     */
+    NodeInstrumenter getNodeInstrumenter();
+
+    /**
+     * Access to the management of breakpoints, notifications, etc.
+     */
+    DebugManager getDebugManager();
+
+    /**
+     * Gets a printer for Truffle ASTs helpful for debugging guest language implementations.
+     */
+    ASTPrinter getASTPrinter();
+
+    /**
+     * Converts a value in the guest language to a display string.
+     */
+    String displayValue(Object value);
+
+    /**
+     * Converts a slot identifier in the guest language to a display string.
+     */
+    String displayIdentifier(FrameSlot slot);
+
+    /**
+     * Invokes appropriate debugging action when Truffle execution halts.
+     */
+    void executionHalted(Node node, VirtualFrame frame);
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/debug/DebugManager.java	Mon Feb 03 20:58:23 2014 -0800
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2013, 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 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.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.api.nodes.instrument.*;
+import com.oracle.truffle.api.nodes.instrument.InstrumentationProbeNode.ProbeChain;
+
+/**
+ * Language-agnostic access to AST-based debugging support.
+ * <p>
+ * <strong>Disclaimer:</strong> this interface is under development and will change.
+ */
+public interface DebugManager {
+
+    /**
+     * Informs the {@link DebugManager} that the Guest Language runtime is starting to load a
+     * source. Care should be taken to ensure that under any circumstance there is always a
+     * following call to {@link #notifyFinishedLoading(Source)} with the same argument.
+     */
+    void notifyStartLoading(Source source);
+
+    /**
+     * Informs the {@link DebugManager} that the Guest Language runtime has finished loading a
+     * source. Care should be taken to ensure that under any circumstance there is always a prior
+     * call to {@link #notifyStartLoading(Source)} with the same argument.
+     */
+    void notifyFinishedLoading(Source source);
+
+    /**
+     * Return a reference to the (canonical) instrumentation site associated with a particular
+     * source code location; this site will have effect on any Truffle/AST implementation
+     * corresponding to the source location, even if the AST is copied multiple times.
+     */
+    ProbeChain getProbeChain(SourceSection sourceSection);
+
+    /**
+     * Informs the {@link DebugManager} that Truffle execution has halted; execution will resume
+     * when this method returns.
+     * 
+     * @param astNode a guest language AST node that represents the current execution site, assumed
+     *            not to be any kind of {@link InstrumentationNode},
+     * @param frame execution frame at the site where execution suspended
+     */
+    void haltedAt(Node astNode, VirtualFrame frame);
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/debug/DefaultDebugManager.java	Mon Feb 03 20:58:23 2014 -0800
@@ -0,0 +1,111 @@
+/*
+ * 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 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.util.*;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.api.nodes.instrument.InstrumentationProbeNode.ProbeChain;
+import com.oracle.truffle.api.source.*;
+
+/**
+ * A minimal, language-agnostic implementation that tracks loaded sources, and keeps maps describing
+ * what locations in the source have instrumentation available. This implementation will do nothing
+ * unless there are calls to it during AST construction, notably {@link #notifyStartLoading(Source)}
+ * and {@link #notifyFinishedLoading(Source)} <em>and</em> there are at least some AST nodes being
+ * instrumented.
+ */
+public class DefaultDebugManager implements DebugManager {
+
+    private final Set<Source> loadedSources = new HashSet<>();
+
+    private Source beingLoaded = null;
+
+    /**
+     * Map: SourceSection ==> probe chain associated with that source section in an AST.
+     */
+    private final Map<SourceSection, ProbeChain> srcToProbeChain = new HashMap<>();
+
+    /**
+     * Map: Source lines ==> probe chains associated with source sections starting on the line.
+     */
+    private final Map<SourceLineLocation, Set<ProbeChain>> lineToProbeChains = new HashMap<>();
+
+    private final ExecutionContext context;
+
+    public DefaultDebugManager(ExecutionContext context) {
+        this.context = context;
+    }
+
+    /**
+     * Gets the {@linkplain ProbeChain probe} associated with a particular {@link SourceSection
+     * source location}, creating a new one if needed. There should only be one probe associated
+     * with each {@linkplain SourceSection source location}.
+     */
+    public ProbeChain getProbeChain(SourceSection sourceSection) {
+        assert sourceSection != null;
+        assert sourceSection.getSource().equals(beingLoaded);
+
+        ProbeChain probeChain = srcToProbeChain.get(sourceSection);
+
+        if (probeChain != null) {
+            return probeChain;
+        }
+        probeChain = new ProbeChain(context, sourceSection, null);
+
+        // Register new ProbeChain by unique SourceSection
+        srcToProbeChain.put(sourceSection, probeChain);
+
+        // Register new ProbeChain by source line, there may be more than one
+        // Create line location for map key
+        final SourceLineLocation lineLocation = new SourceLineLocation(sourceSection.getSource(), sourceSection.getStartLine());
+
+        Set<ProbeChain> probeChains = lineToProbeChains.get(lineLocation);
+        if (probeChains == null) {
+            probeChains = new HashSet<>();
+            lineToProbeChains.put(lineLocation, probeChains);
+        }
+        probeChains.add(probeChain);
+
+        return probeChain;
+    }
+
+    public void notifyStartLoading(Source source) {
+        assert beingLoaded == null;
+        beingLoaded = source;
+    }
+
+    public void notifyFinishedLoading(Source source) {
+        assert source == beingLoaded;
+        loadedSources.add(source);
+        beingLoaded = null;
+    }
+
+    public void haltedAt(Node astNode, VirtualFrame frame) {
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/debug/KillException.java	Mon Feb 03 20:58:23 2014 -0800
@@ -0,0 +1,36 @@
+/*
+ * 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 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.nodes.*;
+
+// TODO (mlvdv) does this need to extend ControlFlowException?  It was originally part of the Ruby Shell.
+/**
+ * Controls breaking out of an execution context, such as a shell or eval.
+ */
+public final class KillException extends ControlFlowException {
+
+    private static final long serialVersionUID = 3163641880088766957L;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/debug/QuitException.java	Mon Feb 03 20:58:23 2014 -0800
@@ -0,0 +1,36 @@
+/*
+ * 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 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.nodes.*;
+
+//TODO (mlvdv) does this need to extend ControlFlowException?  It was originally part of the Ruby execution environment.
+/**
+ * Controls breaking out of all executions and ending Truffle execution.
+ */
+public final class QuitException extends ControlFlowException {
+
+    private static final long serialVersionUID = -4301115629772778413L;
+}
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultDebugManager.java	Wed Jan 22 21:34:00 2014 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,108 +0,0 @@
-/*
- * Copyright (c) 2013, 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 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.impl;
-
-import java.util.*;
-
-import com.oracle.truffle.api.*;
-import com.oracle.truffle.api.frame.*;
-import com.oracle.truffle.api.nodes.*;
-import com.oracle.truffle.api.nodes.instrument.InstrumentationProbeNode.ProbeChain;
-import com.oracle.truffle.api.source.*;
-
-/**
- * A minimal, language-agnostic implementation that tracks loaded sources, and keeps maps describing
- * what locations in the source have instrumentation available.
- */
-public class DefaultDebugManager implements DebugManager {
-
-    private final Set<Source> loadedSources = new HashSet<>();
-
-    private Source beingLoaded = null;
-
-    /**
-     * Map: SourceSection ==> probe chain associated with that source section in an AST.
-     */
-    private final Map<SourceSection, ProbeChain> srcToProbeChain = new HashMap<>();
-
-    /**
-     * Map: Source lines ==> probe chains associated with source sections starting on the line.
-     */
-    private final Map<SourceLineLocation, Set<ProbeChain>> lineToProbeChains = new HashMap<>();
-
-    private final ExecutionContext context;
-
-    public DefaultDebugManager(ExecutionContext context) {
-        this.context = context;
-    }
-
-    /**
-     * Gets the {@linkplain ProbeChain probe} associated with a particular {@link SourceSection
-     * source location}, creating a new one if needed. There should only be one probe associated
-     * with each {@linkplain SourceSection source location}.
-     */
-    public ProbeChain getProbeChain(SourceSection sourceSection) {
-        assert sourceSection != null;
-        assert sourceSection.getSource().equals(beingLoaded);
-
-        ProbeChain probeChain = srcToProbeChain.get(sourceSection);
-
-        if (probeChain != null) {
-            return probeChain;
-        }
-        probeChain = new ProbeChain(context, sourceSection, null);
-
-        // Register new ProbeChain by unique SourceSection
-        srcToProbeChain.put(sourceSection, probeChain);
-
-        // Register new ProbeChain by source line, there may be more than one
-        // Create line location for map key
-        final SourceLineLocation lineLocation = new SourceLineLocation(sourceSection.getSource(), sourceSection.getStartLine());
-
-        Set<ProbeChain> probeChains = lineToProbeChains.get(lineLocation);
-        if (probeChains == null) {
-            probeChains = new HashSet<>();
-            lineToProbeChains.put(lineLocation, probeChains);
-        }
-        probeChains.add(probeChain);
-
-        return probeChain;
-    }
-
-    public void notifyStartLoading(Source source) {
-        assert beingLoaded == null;
-        beingLoaded = source;
-    }
-
-    public void notifyFinishedLoading(Source source) {
-        assert source == beingLoaded;
-        loadedSources.add(source);
-        beingLoaded = null;
-    }
-
-    public void haltedAt(Node astNode, MaterializedFrame frame) {
-    }
-
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/instrument/DefaultNodeInstrumenter.java	Mon Feb 03 20:58:23 2014 -0800
@@ -0,0 +1,38 @@
+/*
+ * 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 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.nodes.instrument;
+
+import com.oracle.truffle.api.nodes.*;
+
+/**
+ * A no-op node instrumenter; always returns the node unproxied and unmodified.
+ */
+public class DefaultNodeInstrumenter implements NodeInstrumenter {
+
+    public Node instrumentAs(Node node, NodePhylum phylum, Object... args) {
+        return node;
+    }
+
+}
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/instrument/InstrumentationProbeNode.java	Wed Jan 22 21:34:00 2014 -0800
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/instrument/InstrumentationProbeNode.java	Mon Feb 03 20:58:23 2014 -0800
@@ -371,7 +371,7 @@
                     CompilerDirectives.transferToInterpreter();
                 }
                 if (stepping) {
-                    getContext().getDebugManager().haltedAt(astNode, frame.materialize());
+                    getContext().getDebugContext().getDebugManager().haltedAt(astNode, frame);
                 }
                 if (next != null) {
                     next.internalEnter(astNode, frame);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/instrument/NodeInstrumenter.java	Mon Feb 03 20:58:23 2014 -0800
@@ -0,0 +1,46 @@
+/*
+ * 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 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.nodes.instrument;
+
+import com.oracle.truffle.api.nodes.*;
+
+/**
+ * Implements the instrumentation of a Truffle AST node and returning either:
+ * <ul>
+ * <li>the node itself, or</li>
+ * <li>a newly created {@linkplain InstrumentationProxyNode proxy node} that holds the instrumented
+ * node as its {@linkplain com.oracle.truffle.api.nodes.Node.Child child}.</li>
+ * </ul>
+ */
+public interface NodeInstrumenter {
+
+    /**
+     * Wraps a {@linkplain InstrumentationProxyNode proxy node} around a node (if not already
+     * wrapped), marks the location with a {@linkplain NodePhylum phylum (category)} for user
+     * interaction, and passes along any characteristics of the particular node that are important
+     * for instrumentation (e.g. the function/method name at a call).
+     */
+    Node instrumentAs(Node node, NodePhylum phylum, Object... args);
+}
--- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/RubyNode.java	Wed Jan 22 21:34:00 2014 -0800
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/RubyNode.java	Mon Feb 03 20:58:23 2014 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved. This
  * code is released under a tri EPL/GPL/LGPL license. You can use it,
  * redistribute it and/or modify it under the terms of the:
  *
@@ -16,7 +16,7 @@
 import com.oracle.truffle.api.frame.*;
 import com.oracle.truffle.api.nodes.*;
 import com.oracle.truffle.ruby.nodes.call.*;
-import com.oracle.truffle.ruby.nodes.debug.*;
+import com.oracle.truffle.ruby.nodes.instrument.*;
 import com.oracle.truffle.ruby.nodes.yield.*;
 import com.oracle.truffle.ruby.runtime.*;
 import com.oracle.truffle.ruby.runtime.core.*;
--- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/debug/RubyASTPrinter.java	Wed Jan 22 21:34:00 2014 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,176 +0,0 @@
-/*
- * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. This
- * code is released under a tri EPL/GPL/LGPL license. You can use it,
- * redistribute it and/or modify it under the terms of the:
- *
- * Eclipse Public License version 1.0
- * GNU General Public License version 2
- * GNU Lesser General Public License version 2.1
- */
-package com.oracle.truffle.ruby.nodes.debug;
-
-import java.io.*;
-import java.util.*;
-
-import com.oracle.truffle.api.*;
-import com.oracle.truffle.api.nodes.*;
-import com.oracle.truffle.api.nodes.NodeUtil.NodeClass;
-import com.oracle.truffle.api.nodes.NodeUtil.NodeField;
-import com.oracle.truffle.api.nodes.NodeUtil.NodeFieldKind;
-import com.oracle.truffle.api.nodes.instrument.*;
-import com.oracle.truffle.ruby.nodes.*;
-import com.oracle.truffle.ruby.nodes.call.*;
-import com.oracle.truffle.ruby.nodes.literal.*;
-import com.oracle.truffle.ruby.nodes.methods.*;
-
-/**
- * Printers for Truffle-internal AST information.
- */
-public final class RubyASTPrinter implements ASTPrinter {
-
-    public RubyASTPrinter() {
-    }
-
-    public void printTree(PrintWriter p, Node node, int maxDepth, Node markNode) {
-        printTree(p, node, maxDepth, markNode, 1);
-        p.println();
-        p.flush();
-    }
-
-    public String printTreeToString(Node node, int maxDepth, Node markNode) {
-        StringWriter out = new StringWriter();
-        printTree(new PrintWriter(out), node, maxDepth, markNode);
-        return out.toString();
-    }
-
-    public String printTreeToString(Node node, int maxDepth) {
-        return printTreeToString(node, maxDepth, null);
-    }
-
-    private static void printTree(PrintWriter p, Node node, int maxDepth, Node markNode, int level) {
-        if (node == null) {
-            p.print("null");
-            return;
-        }
-
-        p.print(nodeName(node));
-
-        String sep = "";
-        p.print("(");
-
-        final SourceSection src = node.getSourceSection();
-        if (src != null) {
-            if (!(src instanceof NullSourceSection)) {
-                p.print(src.getSource().getName() + ":" + src.getStartLine());
-            } else if (src instanceof CoreSourceSection) {
-                final CoreSourceSection coreSection = (CoreSourceSection) src;
-                p.print("core=\"" + (coreSection == null ? "?" : coreSection.toString()) + "\"");
-            }
-        }
-        if (node instanceof PhylumMarked) {
-            final PhylumMarked markedNode = (PhylumMarked) node;
-            String prefix = "";
-            for (NodePhylum phylum : markedNode.getPhylumMarks()) {
-                p.print(prefix);
-                prefix = ",";
-                p.print(phylum.toString());
-            }
-
-        }
-
-        ArrayList<NodeField> childFields = new ArrayList<>();
-
-        for (NodeField field : NodeClass.get(node.getClass()).getFields()) {
-            if (field.getKind() == NodeFieldKind.CHILD || field.getKind() == NodeFieldKind.CHILDREN) {
-                childFields.add(field);
-            } else if (field.getKind() == NodeFieldKind.DATA) {
-                // p.print(sep);
-                // sep = ", ";
-                //
-                // final String fieldName = field.getName();
-                // switch (fieldName) {
-                //
-                // }
-                // p.print(fieldName);
-                // p.print(" = ");
-                // p.print(field.loadValue(node));
-            }
-        }
-        p.print(")");
-
-        if (level <= maxDepth) {
-
-            if (childFields.size() != 0) {
-                p.print(" {");
-                for (NodeField field : childFields) {
-
-                    Object value = field.loadValue(node);
-                    if (value == null) {
-                        printNewLine(p, level);
-                        p.print(field.getName());
-                        p.print(" = null ");
-                    } else if (field.getKind() == NodeFieldKind.CHILD) {
-                        final Node valueNode = (Node) value;
-                        printNewLine(p, level, valueNode == markNode);
-                        p.print(field.getName());
-                        p.print(" = ");
-                        printTree(p, valueNode, maxDepth, markNode, level + 1);
-                    } else if (field.getKind() == NodeFieldKind.CHILDREN) {
-                        printNewLine(p, level);
-                        p.print(field.getName());
-                        Node[] children = (Node[]) value;
-                        p.print(" = [");
-                        sep = "";
-                        for (Node child : children) {
-                            p.print(sep);
-                            sep = ", ";
-                            printTree(p, child, maxDepth, markNode, level + 1);
-                        }
-                        p.print("]");
-                    } else {
-                        printNewLine(p, level);
-                        p.print(field.getName());
-                    }
-                }
-                printNewLine(p, level - 1);
-                p.print("}");
-            }
-        }
-    }
-
-    private static void printNewLine(PrintWriter p, int level, boolean mark) {
-        p.println();
-        for (int i = 0; i < level; i++) {
-            if (mark && i == 0) {
-                p.print(" -->");
-            } else {
-                p.print("    ");
-            }
-        }
-    }
-
-    private static void printNewLine(PrintWriter p, int level) {
-        printNewLine(p, level, false);
-    }
-
-    private static String nodeName(Node node) {
-        String nodeVal = null;
-        if (node instanceof CallNode) {
-            final CallNode callNode = (CallNode) node;
-            nodeVal = callNode.getName();
-
-        } else if (node instanceof FixnumLiteralNode) {
-            final FixnumLiteralNode fixnum = (FixnumLiteralNode) node;
-            nodeVal = Integer.toString(fixnum.getValue());
-        } else if (node instanceof MethodDefinitionNode) {
-            final MethodDefinitionNode defNode = (MethodDefinitionNode) node;
-            nodeVal = defNode.getName();
-        }
-        String result = node.getClass().getSimpleName();
-        if (nodeVal != null) {
-            result = result + "[\"" + nodeVal + "\"]";
-        }
-        return result;
-    }
-
-}
--- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/debug/RubyProxyNode.java	Wed Jan 22 21:34:00 2014 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,229 +0,0 @@
-/*
- * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved. This
- * code is released under a tri EPL/GPL/LGPL license. You can use it,
- * redistribute it and/or modify it under the terms of the:
- *
- * Eclipse Public License version 1.0
- * GNU General Public License version 2
- * GNU Lesser General Public License version 2.1
- */
-package com.oracle.truffle.ruby.nodes.debug;
-
-import java.math.*;
-import java.util.*;
-
-import com.oracle.truffle.api.*;
-import com.oracle.truffle.api.frame.*;
-import com.oracle.truffle.api.nodes.*;
-import com.oracle.truffle.api.nodes.instrument.*;
-import com.oracle.truffle.api.nodes.instrument.InstrumentationProbeNode.ProbeChain;
-import com.oracle.truffle.ruby.nodes.*;
-import com.oracle.truffle.ruby.runtime.*;
-import com.oracle.truffle.ruby.runtime.control.*;
-import com.oracle.truffle.ruby.runtime.core.*;
-import com.oracle.truffle.ruby.runtime.core.array.*;
-
-/**
- * An <strong>instrumentation proxy node</strong> that forwards all Ruby execution calls through to
- * a child node and returns results back to the parent, but which also sends notifications to an
- * attached {@linkplain ProbeChain chain} of {@linkplain InstrumentationProbeNode probes}.
- */
-public class RubyProxyNode extends RubyNode implements InstrumentationProxyNode {
-
-    @Child private RubyNode child;
-
-    private final ProbeChain probeChain;
-
-    public RubyProxyNode(RubyContext context, RubyNode child) {
-        super(context, SourceSection.NULL);
-        assert !(child instanceof RubyProxyNode);
-        this.child = adoptChild(child);
-        this.probeChain = context.getDebugManager().getProbeChain(child.getSourceSection());
-    }
-
-    public RubyProxyNode(RubyContext context, RubyNode child, ProbeChain probeChain) {
-        super(context, SourceSection.NULL);
-        assert !(child instanceof RubyProxyNode);
-        this.child = adoptChild(child);
-        this.probeChain = probeChain;
-    }
-
-    @Override
-    public RubyNode getNonProxyNode() {
-        return child;
-    }
-
-    public RubyNode getChild() {
-        return child;
-    }
-
-    public ProbeChain getProbeChain() {
-        return probeChain;
-    }
-
-    @Override
-    public Object execute(VirtualFrame frame) {
-        probeChain.notifyEnter(child, frame);
-
-        Object result;
-
-        try {
-            result = child.execute(frame);
-            probeChain.notifyLeave(child, frame, result);
-        } catch (BreakShellException e) {
-            throw (e);
-        } catch (Exception e) {
-            probeChain.notifyLeaveExceptional(child, frame, e);
-            throw (e);
-        }
-
-        return result;
-    }
-
-    @Override
-    public RubyArray executeArray(VirtualFrame frame) throws UnexpectedResultException {
-        probeChain.notifyEnter(child, frame);
-
-        RubyArray result;
-
-        try {
-            result = child.executeArray(frame);
-            probeChain.notifyLeave(child, frame, result);
-        } catch (BreakShellException e) {
-            throw (e);
-        } catch (Exception e) {
-            probeChain.notifyLeaveExceptional(child, frame, e);
-            throw (e);
-        }
-
-        return result;
-    }
-
-    @Override
-    public BigInteger executeBignum(VirtualFrame frame) throws UnexpectedResultException {
-        probeChain.notifyEnter(child, frame);
-
-        BigInteger result;
-
-        try {
-            result = child.executeBignum(frame);
-            probeChain.notifyLeave(child, frame, result);
-        } catch (BreakShellException e) {
-            throw (e);
-        } catch (Exception e) {
-            probeChain.notifyLeaveExceptional(child, frame, e);
-            throw (e);
-        }
-
-        return result;
-    }
-
-    @Override
-    public boolean executeBoolean(VirtualFrame frame) throws UnexpectedResultException {
-        probeChain.notifyEnter(child, frame);
-
-        boolean result;
-
-        try {
-            result = child.executeBoolean(frame);
-            probeChain.notifyLeave(child, frame, result);
-        } catch (BreakShellException e) {
-            throw (e);
-        } catch (Exception e) {
-            probeChain.notifyLeaveExceptional(child, frame, e);
-            throw (e);
-        }
-
-        return result;
-    }
-
-    @Override
-    public Object isDefined(VirtualFrame frame) {
-        return child.isDefined(frame);
-    }
-
-    @Override
-    public int executeFixnum(VirtualFrame frame) throws UnexpectedResultException {
-        probeChain.notifyEnter(child, frame);
-
-        int result;
-
-        try {
-            result = child.executeFixnum(frame);
-            probeChain.notifyLeave(child, frame, result);
-        } catch (BreakShellException e) {
-            throw (e);
-        } catch (Exception e) {
-            probeChain.notifyLeaveExceptional(child, frame, e);
-            throw (e);
-        }
-
-        return result;
-    }
-
-    @Override
-    public double executeFloat(VirtualFrame frame) throws UnexpectedResultException {
-        probeChain.notifyEnter(child, frame);
-
-        double result;
-
-        try {
-            result = child.executeFloat(frame);
-            probeChain.notifyLeave(child, frame, result);
-        } catch (BreakShellException e) {
-            throw (e);
-        } catch (Exception e) {
-            probeChain.notifyLeaveExceptional(child, frame, e);
-            throw (e);
-        }
-
-        return result;
-    }
-
-    @Override
-    public RubyString executeString(VirtualFrame frame) throws UnexpectedResultException {
-        probeChain.notifyEnter(child, frame);
-
-        RubyString result;
-
-        try {
-            result = child.executeString(frame);
-            probeChain.notifyLeave(child, frame, result);
-        } catch (BreakShellException e) {
-            throw (e);
-        } catch (Exception e) {
-            probeChain.notifyLeaveExceptional(child, frame, e);
-            throw (e);
-        }
-
-        return result;
-    }
-
-    @Override
-    public void executeVoid(VirtualFrame frame) {
-        probeChain.notifyEnter(child, frame);
-
-        try {
-            child.executeVoid(frame);
-            probeChain.notifyLeave(child, frame);
-        } catch (BreakShellException e) {
-            throw (e);
-        } catch (Exception e) {
-            probeChain.notifyLeaveExceptional(child, frame, e);
-            throw (e);
-        }
-    }
-
-    public boolean isMarkedAs(NodePhylum phylum) {
-        return probeChain.isMarkedAs(phylum);
-    }
-
-    public Set<NodePhylum> getPhylumMarks() {
-        return probeChain.getPhylumMarks();
-    }
-
-    public void markAs(NodePhylum phylum) {
-        probeChain.markAs(phylum);
-    }
-
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/instrument/DefaultRubyNodeInstrumenter.java	Mon Feb 03 20:58:23 2014 -0800
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2014 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.nodes.instrument;
+
+import com.oracle.truffle.api.nodes.instrument.*;
+import com.oracle.truffle.ruby.nodes.*;
+import com.oracle.truffle.ruby.runtime.*;
+import com.oracle.truffle.ruby.runtime.debug.*;
+import com.oracle.truffle.ruby.runtime.methods.*;
+
+/**
+ * Utility for instrumenting Ruby AST nodes to support the language's built-in <A
+ * href="http://www.ruby-doc.org/core-2.0.0/Kernel.html#method-i-set_trace_func">tracing
+ * facility</A>. It ignores nodes other than {@linkplain NodePhylum#STATEMENT statements}.
+ */
+public final class DefaultRubyNodeInstrumenter extends DefaultNodeInstrumenter implements RubyNodeInstrumenter {
+
+    // TODO (mlvdv) convert methods to the general interface? will help with dependencies
+
+    public RubyNode instrumentAsStatement(RubyNode rubyNode) {
+        assert rubyNode != null;
+        assert !(rubyNode instanceof RubyProxyNode);
+        final RubyContext context = rubyNode.getContext();
+        if (context.getConfiguration().getTrace()) {
+            final RubyProxyNode proxy = new RubyProxyNode(context, rubyNode);
+            proxy.markAs(NodePhylum.STATEMENT);
+            proxy.getProbeChain().appendProbe(new RubyTraceProbe(context));
+            return proxy;
+        }
+        return rubyNode;
+    }
+
+    public RubyNode instrumentAsCall(RubyNode node, String callName) {
+        return node;
+    }
+
+    public RubyNode instrumentAsLocalAssignment(RubyNode node, UniqueMethodIdentifier methodIdentifier, String localName) {
+        return node;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/instrument/RubyASTPrinter.java	Mon Feb 03 20:58:23 2014 -0800
@@ -0,0 +1,177 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.nodes.instrument;
+
+import java.io.*;
+import java.util.*;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.debug.*;
+import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.api.nodes.NodeUtil.NodeClass;
+import com.oracle.truffle.api.nodes.NodeUtil.NodeField;
+import com.oracle.truffle.api.nodes.NodeUtil.NodeFieldKind;
+import com.oracle.truffle.api.nodes.instrument.*;
+import com.oracle.truffle.ruby.nodes.*;
+import com.oracle.truffle.ruby.nodes.call.*;
+import com.oracle.truffle.ruby.nodes.literal.*;
+import com.oracle.truffle.ruby.nodes.methods.*;
+
+/**
+ * Printers for Truffle-internal AST information.
+ */
+public final class RubyASTPrinter implements ASTPrinter {
+
+    public RubyASTPrinter() {
+    }
+
+    public void printTree(PrintWriter p, Node node, int maxDepth, Node markNode) {
+        printTree(p, node, maxDepth, markNode, 1);
+        p.println();
+        p.flush();
+    }
+
+    public String printTreeToString(Node node, int maxDepth, Node markNode) {
+        StringWriter out = new StringWriter();
+        printTree(new PrintWriter(out), node, maxDepth, markNode);
+        return out.toString();
+    }
+
+    public String printTreeToString(Node node, int maxDepth) {
+        return printTreeToString(node, maxDepth, null);
+    }
+
+    private static void printTree(PrintWriter p, Node node, int maxDepth, Node markNode, int level) {
+        if (node == null) {
+            p.print("null");
+            return;
+        }
+
+        p.print(nodeName(node));
+
+        String sep = "";
+        p.print("(");
+
+        final SourceSection src = node.getSourceSection();
+        if (src != null) {
+            if (!(src instanceof NullSourceSection)) {
+                p.print(src.getSource().getName() + ":" + src.getStartLine());
+            } else if (src instanceof CoreSourceSection) {
+                final CoreSourceSection coreSection = (CoreSourceSection) src;
+                p.print("core=\"" + (coreSection == null ? "?" : coreSection.toString()) + "\"");
+            }
+        }
+        if (node instanceof PhylumMarked) {
+            final PhylumMarked markedNode = (PhylumMarked) node;
+            String prefix = "";
+            for (NodePhylum phylum : markedNode.getPhylumMarks()) {
+                p.print(prefix);
+                prefix = ",";
+                p.print(phylum.toString());
+            }
+
+        }
+
+        ArrayList<NodeField> childFields = new ArrayList<>();
+
+        for (NodeField field : NodeClass.get(node.getClass()).getFields()) {
+            if (field.getKind() == NodeFieldKind.CHILD || field.getKind() == NodeFieldKind.CHILDREN) {
+                childFields.add(field);
+            } else if (field.getKind() == NodeFieldKind.DATA) {
+                // p.print(sep);
+                // sep = ", ";
+                //
+                // final String fieldName = field.getName();
+                // switch (fieldName) {
+                //
+                // }
+                // p.print(fieldName);
+                // p.print(" = ");
+                // p.print(field.loadValue(node));
+            }
+        }
+        p.print(")");
+
+        if (level <= maxDepth) {
+
+            if (childFields.size() != 0) {
+                p.print(" {");
+                for (NodeField field : childFields) {
+
+                    Object value = field.loadValue(node);
+                    if (value == null) {
+                        printNewLine(p, level);
+                        p.print(field.getName());
+                        p.print(" = null ");
+                    } else if (field.getKind() == NodeFieldKind.CHILD) {
+                        final Node valueNode = (Node) value;
+                        printNewLine(p, level, valueNode == markNode);
+                        p.print(field.getName());
+                        p.print(" = ");
+                        printTree(p, valueNode, maxDepth, markNode, level + 1);
+                    } else if (field.getKind() == NodeFieldKind.CHILDREN) {
+                        printNewLine(p, level);
+                        p.print(field.getName());
+                        Node[] children = (Node[]) value;
+                        p.print(" = [");
+                        sep = "";
+                        for (Node child : children) {
+                            p.print(sep);
+                            sep = ", ";
+                            printTree(p, child, maxDepth, markNode, level + 1);
+                        }
+                        p.print("]");
+                    } else {
+                        printNewLine(p, level);
+                        p.print(field.getName());
+                    }
+                }
+                printNewLine(p, level - 1);
+                p.print("}");
+            }
+        }
+    }
+
+    private static void printNewLine(PrintWriter p, int level, boolean mark) {
+        p.println();
+        for (int i = 0; i < level; i++) {
+            if (mark && i == 0) {
+                p.print(" -->");
+            } else {
+                p.print("    ");
+            }
+        }
+    }
+
+    private static void printNewLine(PrintWriter p, int level) {
+        printNewLine(p, level, false);
+    }
+
+    private static String nodeName(Node node) {
+        String nodeVal = null;
+        if (node instanceof CallNode) {
+            final CallNode callNode = (CallNode) node;
+            nodeVal = callNode.getName();
+
+        } else if (node instanceof FixnumLiteralNode) {
+            final FixnumLiteralNode fixnum = (FixnumLiteralNode) node;
+            nodeVal = Integer.toString(fixnum.getValue());
+        } else if (node instanceof MethodDefinitionNode) {
+            final MethodDefinitionNode defNode = (MethodDefinitionNode) node;
+            nodeVal = defNode.getName();
+        }
+        String result = node.getClass().getSimpleName();
+        if (nodeVal != null) {
+            result = result + "[\"" + nodeVal + "\"]";
+        }
+        return result;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/instrument/RubyNodeInstrumenter.java	Mon Feb 03 20:58:23 2014 -0800
@@ -0,0 +1,54 @@
+/*
+ * 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 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.ruby.nodes.instrument;
+
+import com.oracle.truffle.api.nodes.instrument.*;
+import com.oracle.truffle.ruby.nodes.*;
+import com.oracle.truffle.ruby.runtime.methods.*;
+
+public interface RubyNodeInstrumenter extends NodeInstrumenter {
+
+    /**
+     * Adds instrumentation support at a node that should be considered a member of
+     * {@link NodePhylum#STATEMENT}, possibly returning a new {@link InstrumentationProxyNode} that
+     * holds the original as its child.
+     */
+    RubyNode instrumentAsStatement(RubyNode node);
+
+    /**
+     * Adds instrumentation support at a node that should be considered a member of
+     * {@link NodePhylum#CALL}, possibly returning a new {@link InstrumentationProxyNode} that holds
+     * the original as its child.
+     */
+    RubyNode instrumentAsCall(RubyNode node, String callName);
+
+    /**
+     * Adds instrumentation support at a node that should be considered a member of
+     * {@link NodePhylum#ASSIGNMENT}, possibly returning a new {@link InstrumentationProxyNode} that
+     * holds the original as its child.
+     */
+    RubyNode instrumentAsLocalAssignment(RubyNode node, UniqueMethodIdentifier methodIdentifier, String localName);
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/instrument/RubyProxyNode.java	Mon Feb 03 20:58:23 2014 -0800
@@ -0,0 +1,229 @@
+/*
+ * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.nodes.instrument;
+
+import java.math.*;
+import java.util.*;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.debug.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.api.nodes.instrument.*;
+import com.oracle.truffle.api.nodes.instrument.InstrumentationProbeNode.ProbeChain;
+import com.oracle.truffle.ruby.nodes.*;
+import com.oracle.truffle.ruby.runtime.*;
+import com.oracle.truffle.ruby.runtime.core.*;
+import com.oracle.truffle.ruby.runtime.core.array.*;
+
+/**
+ * An <strong>instrumentation proxy node</strong> that forwards all Ruby execution calls through to
+ * a child node and returns results back to the parent, but which also sends notifications to an
+ * attached {@linkplain ProbeChain chain} of {@linkplain InstrumentationProbeNode probes}.
+ */
+public class RubyProxyNode extends RubyNode implements InstrumentationProxyNode {
+
+    @Child private RubyNode child;
+
+    private final ProbeChain probeChain;
+
+    public RubyProxyNode(RubyContext context, RubyNode child) {
+        super(context, SourceSection.NULL);
+        assert !(child instanceof RubyProxyNode);
+        this.child = adoptChild(child);
+        this.probeChain = context.getDebugContext().getDebugManager().getProbeChain(child.getSourceSection());
+    }
+
+    public RubyProxyNode(RubyContext context, RubyNode child, ProbeChain probeChain) {
+        super(context, SourceSection.NULL);
+        assert !(child instanceof RubyProxyNode);
+        this.child = adoptChild(child);
+        this.probeChain = probeChain;
+    }
+
+    @Override
+    public RubyNode getNonProxyNode() {
+        return child;
+    }
+
+    public RubyNode getChild() {
+        return child;
+    }
+
+    public ProbeChain getProbeChain() {
+        return probeChain;
+    }
+
+    @Override
+    public Object execute(VirtualFrame frame) {
+        probeChain.notifyEnter(child, frame);
+
+        Object result;
+
+        try {
+            result = child.execute(frame);
+            probeChain.notifyLeave(child, frame, result);
+        } catch (KillException e) {
+            throw (e);
+        } catch (Exception e) {
+            probeChain.notifyLeaveExceptional(child, frame, e);
+            throw (e);
+        }
+
+        return result;
+    }
+
+    @Override
+    public RubyArray executeArray(VirtualFrame frame) throws UnexpectedResultException {
+        probeChain.notifyEnter(child, frame);
+
+        RubyArray result;
+
+        try {
+            result = child.executeArray(frame);
+            probeChain.notifyLeave(child, frame, result);
+        } catch (KillException e) {
+            throw (e);
+        } catch (Exception e) {
+            probeChain.notifyLeaveExceptional(child, frame, e);
+            throw (e);
+        }
+
+        return result;
+    }
+
+    @Override
+    public BigInteger executeBignum(VirtualFrame frame) throws UnexpectedResultException {
+        probeChain.notifyEnter(child, frame);
+
+        BigInteger result;
+
+        try {
+            result = child.executeBignum(frame);
+            probeChain.notifyLeave(child, frame, result);
+        } catch (KillException e) {
+            throw (e);
+        } catch (Exception e) {
+            probeChain.notifyLeaveExceptional(child, frame, e);
+            throw (e);
+        }
+
+        return result;
+    }
+
+    @Override
+    public boolean executeBoolean(VirtualFrame frame) throws UnexpectedResultException {
+        probeChain.notifyEnter(child, frame);
+
+        boolean result;
+
+        try {
+            result = child.executeBoolean(frame);
+            probeChain.notifyLeave(child, frame, result);
+        } catch (KillException e) {
+            throw (e);
+        } catch (Exception e) {
+            probeChain.notifyLeaveExceptional(child, frame, e);
+            throw (e);
+        }
+
+        return result;
+    }
+
+    @Override
+    public Object isDefined(VirtualFrame frame) {
+        return child.isDefined(frame);
+    }
+
+    @Override
+    public int executeFixnum(VirtualFrame frame) throws UnexpectedResultException {
+        probeChain.notifyEnter(child, frame);
+
+        int result;
+
+        try {
+            result = child.executeFixnum(frame);
+            probeChain.notifyLeave(child, frame, result);
+        } catch (KillException e) {
+            throw (e);
+        } catch (Exception e) {
+            probeChain.notifyLeaveExceptional(child, frame, e);
+            throw (e);
+        }
+
+        return result;
+    }
+
+    @Override
+    public double executeFloat(VirtualFrame frame) throws UnexpectedResultException {
+        probeChain.notifyEnter(child, frame);
+
+        double result;
+
+        try {
+            result = child.executeFloat(frame);
+            probeChain.notifyLeave(child, frame, result);
+        } catch (KillException e) {
+            throw (e);
+        } catch (Exception e) {
+            probeChain.notifyLeaveExceptional(child, frame, e);
+            throw (e);
+        }
+
+        return result;
+    }
+
+    @Override
+    public RubyString executeString(VirtualFrame frame) throws UnexpectedResultException {
+        probeChain.notifyEnter(child, frame);
+
+        RubyString result;
+
+        try {
+            result = child.executeString(frame);
+            probeChain.notifyLeave(child, frame, result);
+        } catch (KillException e) {
+            throw (e);
+        } catch (Exception e) {
+            probeChain.notifyLeaveExceptional(child, frame, e);
+            throw (e);
+        }
+
+        return result;
+    }
+
+    @Override
+    public void executeVoid(VirtualFrame frame) {
+        probeChain.notifyEnter(child, frame);
+
+        try {
+            child.executeVoid(frame);
+            probeChain.notifyLeave(child, frame);
+        } catch (KillException e) {
+            throw (e);
+        } catch (Exception e) {
+            probeChain.notifyLeaveExceptional(child, frame, e);
+            throw (e);
+        }
+    }
+
+    public boolean isMarkedAs(NodePhylum phylum) {
+        return probeChain.isMarkedAs(phylum);
+    }
+
+    public Set<NodePhylum> getPhylumMarks() {
+        return probeChain.getPhylumMarks();
+    }
+
+    public void markAs(NodePhylum phylum) {
+        probeChain.markAs(phylum);
+    }
+
+}
--- a/graal/com.oracle.truffle.ruby.parser/src/com/oracle/truffle/ruby/parser/DefaultRubyNodeInstrumenter.java	Wed Jan 22 21:34:00 2014 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,50 +0,0 @@
-/*
- * Copyright (c) 2014 Oracle and/or its affiliates. All rights reserved. This
- * code is released under a tri EPL/GPL/LGPL license. You can use it,
- * redistribute it and/or modify it under the terms of the:
- *
- * Eclipse Public License version 1.0
- * GNU General Public License version 2
- * GNU Lesser General Public License version 2.1
- */
-package com.oracle.truffle.ruby.parser;
-
-import com.oracle.truffle.api.nodes.instrument.*;
-import com.oracle.truffle.ruby.nodes.*;
-import com.oracle.truffle.ruby.nodes.debug.*;
-import com.oracle.truffle.ruby.runtime.*;
-import com.oracle.truffle.ruby.runtime.debug.*;
-import com.oracle.truffle.ruby.runtime.methods.*;
-
-/**
- * Utility for instrumenting Ruby AST nodes to support the language's built-in <A
- * href="http://www.ruby-doc.org/core-2.0.0/Kernel.html#method-i-set_trace_func">tracing
- * facility</A>. It ignores nodes other than {@linkplain NodePhylum#STATEMENT statements}.
- */
-final class DefaultRubyNodeInstrumenter implements RubyNodeInstrumenter {
-
-    public DefaultRubyNodeInstrumenter() {
-    }
-
-    public RubyNode instrumentAsStatement(RubyNode rubyNode) {
-        assert rubyNode != null;
-        assert !(rubyNode instanceof RubyProxyNode);
-        final RubyContext context = rubyNode.getContext();
-        if (context.getConfiguration().getTrace()) {
-            final RubyProxyNode proxy = new RubyProxyNode(context, rubyNode);
-            proxy.markAs(NodePhylum.STATEMENT);
-            proxy.getProbeChain().appendProbe(new RubyTraceProbe(context));
-            return proxy;
-        }
-        return rubyNode;
-    }
-
-    public RubyNode instrumentAsCall(RubyNode node, String callName) {
-        return node;
-    }
-
-    public RubyNode instrumentAsLocalAssignment(RubyNode node, UniqueMethodIdentifier methodIdentifier, String localName) {
-        return node;
-    }
-
-}
--- a/graal/com.oracle.truffle.ruby.parser/src/com/oracle/truffle/ruby/parser/JRubyParser.java	Wed Jan 22 21:34:00 2014 -0800
+++ b/graal/com.oracle.truffle.ruby.parser/src/com/oracle/truffle/ruby/parser/JRubyParser.java	Mon Feb 03 20:58:23 2014 -0800
@@ -27,15 +27,7 @@
 
     private long nextReturnID = 0;
 
-    private final RubyNodeInstrumenter instrumenter;
-
     public JRubyParser() {
-        this(new DefaultRubyNodeInstrumenter());
-    }
-
-    public JRubyParser(RubyNodeInstrumenter instrumenter) {
-        assert instrumenter != null;
-        this.instrumenter = instrumenter;
     }
 
     @Override
@@ -111,11 +103,8 @@
 
         RubyNode truffleNode;
 
-        final DebugManager debugManager = context.getDebugManager();
         try {
-            if (debugManager != null) {
-                debugManager.notifyStartLoading(source);
-            }
+            context.getDebugContext().getDebugManager().notifyStartLoading(source);
 
             if (node.getBody() == null) {
                 truffleNode = new NilNode(context, null);
@@ -166,9 +155,7 @@
             // Return the root and the frame descriptor
             return new RubyParserResult(root);
         } finally {
-            if (debugManager != null) {
-                debugManager.notifyFinishedLoading(source);
-            }
+            context.getDebugContext().getDebugManager().notifyFinishedLoading(source);
         }
     }
 
@@ -182,10 +169,6 @@
         return allocated;
     }
 
-    public RubyNodeInstrumenter getNodeInstrumenter() {
-        return instrumenter;
-    }
-
     private TranslatorEnvironment environmentForFrame(RubyContext context, MaterializedFrame frame) {
         if (frame == null) {
             return null;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.parser/src/com/oracle/truffle/ruby/parser/MinimumRubyDebugContext.java	Mon Feb 03 20:58:23 2014 -0800
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.parser;
+
+import com.oracle.truffle.api.debug.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.ruby.nodes.instrument.*;
+import com.oracle.truffle.ruby.runtime.*;
+
+/**
+ * Minimum possible debugging support for Ruby implementation. Some facilities are needed to support
+ * the Ruby trace mechanism.
+ */
+public final class MinimumRubyDebugContext implements DebugContext {
+
+    private final RubyContext executionContext;
+    private final RubyNodeInstrumenter instrumenter;
+    private final DebugManager debugManager;
+
+    public MinimumRubyDebugContext(RubyContext context) {
+        this.executionContext = context;
+        this.instrumenter = new DefaultRubyNodeInstrumenter();
+        this.debugManager = new DefaultDebugManager(context);
+    }
+
+    public RubyContext getContext() {
+        return executionContext;
+    }
+
+    public RubyNodeInstrumenter getNodeInstrumenter() {
+        return instrumenter;
+    }
+
+    public DebugManager getDebugManager() {
+        return debugManager;
+    }
+
+    public RubyASTPrinter getASTPrinter() {
+        return null;
+    }
+
+    public String displayValue(Object value) {
+        return value.toString();
+    }
+
+    public String displayIdentifier(FrameSlot slot) {
+        return slot.getIdentifier().toString();
+    }
+
+    public void executionHalted(Node node, VirtualFrame frame) {
+        assert false;
+    }
+
+}
--- a/graal/com.oracle.truffle.ruby.parser/src/com/oracle/truffle/ruby/parser/RubyNodeInstrumenter.java	Wed Jan 22 21:34:00 2014 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,54 +0,0 @@
-/*
- * 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 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.ruby.parser;
-
-import com.oracle.truffle.api.nodes.instrument.*;
-import com.oracle.truffle.ruby.nodes.*;
-import com.oracle.truffle.ruby.runtime.methods.*;
-
-public interface RubyNodeInstrumenter {
-
-    /**
-     * Adds instrumentation support at a node that should be considered a member of
-     * {@link NodePhylum#STATEMENT}, possibly returning a new {@link InstrumentationProxyNode} that
-     * holds the original as its child.
-     */
-    RubyNode instrumentAsStatement(RubyNode node);
-
-    /**
-     * Adds instrumentation support at a node that should be considered a member of
-     * {@link NodePhylum#CALL}, possibly returning a new {@link InstrumentationProxyNode} that holds
-     * the original as its child.
-     */
-    RubyNode instrumentAsCall(RubyNode node, String callName);
-
-    /**
-     * Adds instrumentation support at a node that should be considered a member of
-     * {@link NodePhylum#ASSIGNMENT}, possibly returning a new {@link InstrumentationProxyNode} that
-     * holds the original as its child.
-     */
-    RubyNode instrumentAsLocalAssignment(RubyNode node, UniqueMethodIdentifier methodIdentifier, String localName);
-
-}
--- a/graal/com.oracle.truffle.ruby.parser/src/com/oracle/truffle/ruby/parser/Translator.java	Wed Jan 22 21:34:00 2014 -0800
+++ b/graal/com.oracle.truffle.ruby.parser/src/com/oracle/truffle/ruby/parser/Translator.java	Mon Feb 03 20:58:23 2014 -0800
@@ -22,6 +22,7 @@
 import com.oracle.truffle.ruby.nodes.constants.*;
 import com.oracle.truffle.ruby.nodes.control.*;
 import com.oracle.truffle.ruby.nodes.core.*;
+import com.oracle.truffle.ruby.nodes.instrument.*;
 import com.oracle.truffle.ruby.nodes.literal.*;
 import com.oracle.truffle.ruby.nodes.literal.array.*;
 import com.oracle.truffle.ruby.nodes.methods.*;
--- a/graal/com.oracle.truffle.ruby.parser/src/com/oracle/truffle/ruby/parser/TranslatorEnvironment.java	Wed Jan 22 21:34:00 2014 -0800
+++ b/graal/com.oracle.truffle.ruby.parser/src/com/oracle/truffle/ruby/parser/TranslatorEnvironment.java	Mon Feb 03 20:58:23 2014 -0800
@@ -14,6 +14,7 @@
 import com.oracle.truffle.api.*;
 import com.oracle.truffle.api.frame.*;
 import com.oracle.truffle.ruby.nodes.*;
+import com.oracle.truffle.ruby.nodes.instrument.*;
 import com.oracle.truffle.ruby.nodes.methods.locals.*;
 import com.oracle.truffle.ruby.runtime.*;
 import com.oracle.truffle.ruby.runtime.core.*;
@@ -226,6 +227,6 @@
     }
 
     public RubyNodeInstrumenter getNodeInstrumenter() {
-        return parser.getNodeInstrumenter();
+        return (RubyNodeInstrumenter) context.getDebugContext().getNodeInstrumenter();
     }
 }
--- a/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/RubyContext.java	Wed Jan 22 21:34:00 2014 -0800
+++ b/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/RubyContext.java	Mon Feb 03 20:58:23 2014 -0800
@@ -15,8 +15,8 @@
 import jnr.posix.*;
 
 import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.debug.*;
 import com.oracle.truffle.api.frame.*;
-import com.oracle.truffle.api.impl.*;
 import com.oracle.truffle.api.nodes.*;
 import com.oracle.truffle.api.source.*;
 import com.oracle.truffle.ruby.runtime.configuration.*;
@@ -40,9 +40,8 @@
     private final ThreadManager threadManager;
     private final FiberManager fiberManager;
     private final AtExitManager atExitManager;
-    private final DebugManager debugManager;
     private final SourceManager sourceManager;
-    private final ASTPrinter astPrinter;
+    private DebugContext debugContext = null;
 
     private AtomicLong nextObjectID = new AtomicLong(0);
 
@@ -51,20 +50,14 @@
     private POSIX posix = POSIXFactory.getPOSIX();
 
     public RubyContext(RubyParser parser) {
-        this(new Configuration(new ConfigurationBuilder()), parser, null);
+        this(new Configuration(new ConfigurationBuilder()), parser);
     }
 
     public RubyContext(Configuration configuration, RubyParser parser) {
-        this(configuration, parser, null);
-    }
-
-    public RubyContext(Configuration configuration, RubyParser parser, ASTPrinter astPrinter) {
         assert configuration != null;
 
         this.configuration = configuration;
         this.parser = parser;
-        this.astPrinter = astPrinter;
-
         objectSpaceManager = new ObjectSpaceManager(this);
         traceManager = new TraceManager(this);
 
@@ -76,8 +69,6 @@
         atExitManager = new AtExitManager();
         sourceManager = new SourceManager();
 
-        debugManager = new DefaultDebugManager(this);
-
         // Must initialize threads before fibers
 
         threadManager = new ThreadManager(this);
@@ -88,12 +79,16 @@
         return "Ruby " + CoreLibrary.RUBY_VERSION;
     }
 
-    public DebugManager getDebugManager() {
-        return debugManager;
+    public SourceManager getSourceManager() {
+        return sourceManager;
     }
 
-    public ASTPrinter getASTPrinter() {
-        return astPrinter;
+    public DebugContext getDebugContext() {
+        return debugContext;
+    }
+
+    public void setDebugContext(DebugContext debugContext) {
+        this.debugContext = debugContext;
     }
 
     public void implementationMessage(String format, Object... arguments) {
@@ -155,7 +150,7 @@
                 configuration.getStandardOut().println("=> " + result.getResult());
 
                 existingLocals = result.getFrame();
-            } catch (BreakShellException e) {
+            } catch (KillException e) {
                 return;
             } catch (Exception e) {
                 e.printStackTrace();
@@ -179,7 +174,7 @@
             throw e;
         } catch (ThrowException e) {
             throw new RaiseException(context.getCoreLibrary().argumentErrorUncaughtThrow(e.getTag()));
-        } catch (BreakShellException | QuitException e) {
+        } catch (KillException | QuitException e) {
             throw e;
         } catch (Throwable e) {
             throw new RaiseException(ExceptionTranslator.translateException(this, e));
@@ -296,8 +291,4 @@
         return atExitManager;
     }
 
-    public SourceManager getSourceManager() {
-        return sourceManager;
-    }
-
 }
--- a/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/control/BreakShellException.java	Wed Jan 22 21:34:00 2014 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,21 +0,0 @@
-/*
- * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
- * code is released under a tri EPL/GPL/LGPL license. You can use it,
- * redistribute it and/or modify it under the terms of the:
- *
- * Eclipse Public License version 1.0
- * GNU General Public License version 2
- * GNU Lesser General Public License version 2.1
- */
-package com.oracle.truffle.ruby.runtime.control;
-
-import com.oracle.truffle.api.nodes.*;
-
-/**
- * Controls breaking out of a shell.
- */
-public final class BreakShellException extends ControlFlowException {
-
-    private static final long serialVersionUID = 6448983812696841922L;
-
-}
--- a/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/control/QuitException.java	Wed Jan 22 21:34:00 2014 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,21 +0,0 @@
-/*
- * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
- * code is released under a tri EPL/GPL/LGPL license. You can use it,
- * redistribute it and/or modify it under the terms of the:
- *
- * Eclipse Public License version 1.0
- * GNU General Public License version 2
- * GNU Lesser General Public License version 2.1
- */
-package com.oracle.truffle.ruby.runtime.control;
-
-import com.oracle.truffle.api.nodes.*;
-
-/**
- * Controls breaking out of all executions and ending Ruby execution.
- */
-public final class QuitException extends ControlFlowException {
-
-    private static final long serialVersionUID = -3568511099628564190L;
-
-}
--- a/graal/com.oracle.truffle.ruby.shell/src/com/oracle/truffle/ruby/shell/Shell.java	Wed Jan 22 21:34:00 2014 -0800
+++ b/graal/com.oracle.truffle.ruby.shell/src/com/oracle/truffle/ruby/shell/Shell.java	Mon Feb 03 20:58:23 2014 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved. This
  * code is released under a tri EPL/GPL/LGPL license. You can use it,
  * redistribute it and/or modify it under the terms of the:
  *
@@ -74,6 +74,9 @@
 
         final RubyContext context = new RubyContext(new Configuration(configurationBuilder), new JRubyParser());
 
+        // Ruby should always have a debug context.
+        context.setDebugContext(new MinimumRubyDebugContext(context));
+
         // Bring in core method nodes
 
         CoreMethodNodeManager.addMethods(context.getCoreLibrary().getObjectClass());
--- a/graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/RubyTests.java	Wed Jan 22 21:34:00 2014 -0800
+++ b/graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/RubyTests.java	Mon Feb 03 20:58:23 2014 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved. This
  * code is released under a tri EPL/GPL/LGPL license. You can use it,
  * redistribute it and/or modify it under the terms of the:
  *
@@ -80,6 +80,7 @@
         });
 
         final RubyContext context = new RubyContext(new Configuration(configurationBuilder), new JRubyParser());
+        context.setDebugContext(new MinimumRubyDebugContext(context));
 
         CoreMethodNodeManager.addMethods(context.getCoreLibrary().getObjectClass());
         context.getCoreLibrary().initializeAfterMethodsAdded();
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/SLScript.java	Wed Jan 22 21:34:00 2014 -0800
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/SLScript.java	Mon Feb 03 20:58:23 2014 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * 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
@@ -22,6 +22,8 @@
  */
 package com.oracle.truffle.sl;
 
+import java.io.*;
+
 import javax.script.*;
 
 import com.oracle.truffle.api.*;
@@ -71,4 +73,77 @@
         }
         return new SLScript(context, main);
     }
+
+    public static SLScript create(SLContext context, InputStream input) throws ScriptException {
+        SLNodeFactory factory = new SLNodeFactory(context);
+        Parser parser = new Parser(new Scanner(input), factory);
+        factory.setParser(parser);
+        factory.setSource(new Source() {
+            public String getName() {
+                return "Unknown";
+            }
+
+            public String getCode() {
+                return null;
+            }
+
+            @Override
+            public String getPath() {
+                // TODO Auto-generated method stub
+                return null;
+            }
+
+            @Override
+            public Reader getReader() {
+                // TODO Auto-generated method stub
+                return null;
+            }
+
+            @Override
+            public InputStream getInputStream() {
+                // TODO Auto-generated method stub
+                return null;
+            }
+
+            @Override
+            public String getCode(int lineNumber) {
+                // TODO Auto-generated method stub
+                return null;
+            }
+
+            @Override
+            public int getLineCount() {
+                // TODO Auto-generated method stub
+                return 0;
+            }
+
+            @Override
+            public int getLineNumber(int offset) {
+                // TODO Auto-generated method stub
+                return 0;
+            }
+
+            @Override
+            public int getLineStartOffset(int lineNumber) {
+                // TODO Auto-generated method stub
+                return 0;
+            }
+
+            @Override
+            public int getLineLength(int lineNumber) {
+                // TODO Auto-generated method stub
+                return 0;
+            }
+        });
+        String error = parser.ParseErrors();
+        if (!error.isEmpty()) {
+            throw new ScriptException(String.format("Error(s) parsing script: %s", error));
+        }
+
+        CallTarget main = context.getFunctionRegistry().lookup("main");
+        if (main == null) {
+            throw new ScriptException("No main function found.");
+        }
+        return new SLScript(context, main);
+    }
 }