From b9a6280eb0b8d81c4580e396a819a207128164a6 Mon Sep 17 00:00:00 2001
From: Jaroslav Tulach <jaroslav.tulach@oracle.com>
Date: Mon, 8 Feb 2016 09:19:10 +0100
Subject: [PATCH 1/2] Bringing lookup into branch that is capable of some
 debugging

---
 .../instrumentation/InstrumentationTest.java  |  8 ++-
 .../examples/DebuggerController.java          | 53 ++++++++++++++++
 .../examples/DebuggerExample.java             | 54 +++-------------
 .../examples/DebuggerExampleTest.java         | 61 ++++++++-----------
 .../InstrumentationHandler.java               | 55 ++++++++++++-----
 .../InstrumentationLanguage.java              | 56 -----------------
 .../api/instrumentation/package-info.java     |  8 +--
 .../oracle/truffle/api/vm/PolyglotEngine.java | 10 +--
 .../oracle/truffle/api/TruffleLanguage.java   | 33 ++++++++++
 .../com/oracle/truffle/api/impl/Accessor.java |  9 ++-
 10 files changed, 182 insertions(+), 165 deletions(-)
 create mode 100644 truffle/com.oracle.truffle.api.instrumentation.test/src/com/oracle/truffle/api/instrumentation/examples/DebuggerController.java
 delete mode 100644 truffle/com.oracle.truffle.api.instrumentation/src/com/oracle/truffle/api/instrumentation/InstrumentationLanguage.java

diff --git a/truffle/com.oracle.truffle.api.instrumentation.test/src/com/oracle/truffle/api/instrumentation/InstrumentationTest.java b/truffle/com.oracle.truffle.api.instrumentation.test/src/com/oracle/truffle/api/instrumentation/InstrumentationTest.java
index bba25009f540..511d1529ee9d 100644
--- a/truffle/com.oracle.truffle.api.instrumentation.test/src/com/oracle/truffle/api/instrumentation/InstrumentationTest.java
+++ b/truffle/com.oracle.truffle.api.instrumentation.test/src/com/oracle/truffle/api/instrumentation/InstrumentationTest.java
@@ -202,15 +202,14 @@ private static class MyLanguageException extends RuntimeException {
     }
 
     @TruffleLanguage.Registration(name = "", version = "", mimeType = "testLanguageInstrumentation")
-    public static class TestLanguageInstrumentationLanguage extends TruffleLanguage<Void> implements InstrumentationLanguage<Void> {
+    public static class TestLanguageInstrumentationLanguage extends TruffleLanguage<Void> {
 
         public static final TestLanguageInstrumentationLanguage INSTANCE = new TestLanguageInstrumentationLanguage();
 
         static int installInstrumentationsCounter = 0;
         static int createContextCounter = 0;
 
-        @Override
-        public void installInstrumentations(Void env, Instrumenter instrumenter) {
+        private static void installInstrumentations(Instrumenter instrumenter) {
             installInstrumentationsCounter++;
             instrumenter.attachListener(SourceSectionFilter.newBuilder().tagIs(InstrumentationTestLanguage.EXPRESSION).build(), new EventListener() {
                 public void onReturnValue(EventContext context, VirtualFrame frame, Object result) {
@@ -244,6 +243,9 @@ public void onEnter(EventContext context, VirtualFrame frame) {
         @Override
         protected Void createContext(com.oracle.truffle.api.TruffleLanguage.Env env) {
             createContextCounter++;
+            Instrumenter instrumenter = env.lookup(Instrumenter.class);
+            Assert.assertNotNull("Instrumenter found", instrumenter);
+            installInstrumentations(instrumenter);
             return null;
         }
 
diff --git a/truffle/com.oracle.truffle.api.instrumentation.test/src/com/oracle/truffle/api/instrumentation/examples/DebuggerController.java b/truffle/com.oracle.truffle.api.instrumentation.test/src/com/oracle/truffle/api/instrumentation/examples/DebuggerController.java
new file mode 100644
index 000000000000..e18565633a7b
--- /dev/null
+++ b/truffle/com.oracle.truffle.api.instrumentation.test/src/com/oracle/truffle/api/instrumentation/examples/DebuggerController.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2016, 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.instrumentation.examples;
+
+import com.oracle.truffle.api.instrumentation.EventContext;
+import com.oracle.truffle.api.vm.PolyglotEngine;
+
+/**
+ * Publicly exposed API of a debugger. Provides operations that its clients can use to control the
+ * execution. Put this class into an API package of your instrument. The clients shall use
+ * {@link PolyglotEngine.Instrument#lookup(java.lang.Class)} with
+ * <code>DebuggerController.<b>class</b></code> parameter to obtain the interface.
+ */
+public interface DebuggerController {
+    public static final String ID = "example-debugger";
+
+    public void installBreakpoint(int i, Callback callback);
+
+    public void stepInto(Callback callback);
+
+    public void stepOut(Callback callback);
+
+    public void stepOver(Callback callback);
+
+    public interface Callback {
+
+        void halted(DebuggerController debugger, EventContext haltedAt);
+
+    }
+
+}
diff --git a/truffle/com.oracle.truffle.api.instrumentation.test/src/com/oracle/truffle/api/instrumentation/examples/DebuggerExample.java b/truffle/com.oracle.truffle.api.instrumentation.test/src/com/oracle/truffle/api/instrumentation/examples/DebuggerExample.java
index b05a2a2e65ba..7e533684afda 100644
--- a/truffle/com.oracle.truffle.api.instrumentation.test/src/com/oracle/truffle/api/instrumentation/examples/DebuggerExample.java
+++ b/truffle/com.oracle.truffle.api.instrumentation.test/src/com/oracle/truffle/api/instrumentation/examples/DebuggerExample.java
@@ -24,9 +24,6 @@
  */
 package com.oracle.truffle.api.instrumentation.examples;
 
-import java.util.ArrayList;
-import java.util.List;
-
 import com.oracle.truffle.api.CompilerDirectives;
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.api.Truffle;
@@ -43,41 +40,26 @@
 import com.oracle.truffle.api.instrumentation.TruffleInstrument.Registration;
 
 /**
- * This is an example how debugging can be implemented using the instrumentation framework. Debugger
- * front-ends can be used by installing a {@link DebuggerFrontEnd} implementation with
- * {@link #installFrontEnd(Class)}.
+ * This is an example how debugging can be implemented using the instrumentation framework. This
+ * class itself shall be hidden in an implementation package. The actual API that
+ * {@link DebuggerExampleTest clients} can use to talk to the debugger is exposed in a separate
+ * {@link DebuggerController} interface.
  */
-@Registration(id = DebuggerExample.ID)
-public final class DebuggerExample extends TruffleInstrument {
-
-    public static final String ID = "example-debugger";
-
+@Registration(id = DebuggerController.ID)
+public final class DebuggerExample extends TruffleInstrument implements DebuggerController {
     private Instrumenter instrumenter;
     private EventBinding<?> stepping;
 
-    private final List<DebuggerFrontEnd> frontEnds = new ArrayList<>();
     private Callback currentStatementCallback;
 
     @Override
     protected void onCreate(Env env, Instrumenter originalInstrumenter) {
         assert this.instrumenter == null;
         this.instrumenter = originalInstrumenter;
-        for (Class<? extends DebuggerFrontEnd> frontEnd : installedFrontEnds) {
-            try {
-                DebuggerFrontEnd frontEndInstance = frontEnd.newInstance();
-                frontEndInstance.onAttach(this);
-                frontEnds.add(frontEndInstance);
-            } catch (Exception e) {
-                throw new RuntimeException(e);
-            }
-        }
     }
 
     @Override
     protected void onDispose(Env env) {
-        for (DebuggerFrontEnd debugger : frontEnds) {
-            debugger.onDispose();
-        }
     }
 
     public boolean isStepping() {
@@ -194,7 +176,7 @@ private abstract class StepCallBack implements Callback {
             this.delegate = delegate;
         }
 
-        public void halted(DebuggerExample debugger, EventContext haltedAt) {
+        public void halted(DebuggerController debugger, EventContext haltedAt) {
             if (shouldHalt()) {
                 currentStatementCallback = null;
                 delegate.halted(debugger, haltedAt);
@@ -251,26 +233,4 @@ protected boolean shouldHalt() {
 
     }
 
-    public interface Callback {
-
-        void halted(DebuggerExample debugger, EventContext haltedAt);
-
-    }
-
-    // in a production debugger this should be implemented using a proper service provider interface
-
-    private static final List<Class<? extends DebuggerFrontEnd>> installedFrontEnds = new ArrayList<>();
-
-    public static void installFrontEnd(Class<? extends DebuggerFrontEnd> frontEndClass) {
-        installedFrontEnds.add(frontEndClass);
-    }
-
-    public interface DebuggerFrontEnd {
-
-        void onAttach(DebuggerExample example);
-
-        void onDispose();
-
-    }
-
 }
diff --git a/truffle/com.oracle.truffle.api.instrumentation.test/src/com/oracle/truffle/api/instrumentation/examples/DebuggerExampleTest.java b/truffle/com.oracle.truffle.api.instrumentation.test/src/com/oracle/truffle/api/instrumentation/examples/DebuggerExampleTest.java
index 0df136c8571b..53afa81ef2ba 100644
--- a/truffle/com.oracle.truffle.api.instrumentation.test/src/com/oracle/truffle/api/instrumentation/examples/DebuggerExampleTest.java
+++ b/truffle/com.oracle.truffle.api.instrumentation.test/src/com/oracle/truffle/api/instrumentation/examples/DebuggerExampleTest.java
@@ -29,38 +29,25 @@
 
 import org.junit.Assert;
 import org.junit.Before;
-import org.junit.BeforeClass;
 import org.junit.Test;
 
 import com.oracle.truffle.api.instrumentation.AbstractInstrumentationTest;
 import com.oracle.truffle.api.instrumentation.EventContext;
 import com.oracle.truffle.api.instrumentation.InstrumentationTestLanguage;
-import com.oracle.truffle.api.instrumentation.examples.DebuggerExample.Callback;
-import com.oracle.truffle.api.instrumentation.examples.DebuggerExample.DebuggerFrontEnd;
+import com.oracle.truffle.api.instrumentation.examples.DebuggerController.Callback;
 import com.oracle.truffle.api.source.Source;
+import com.oracle.truffle.api.vm.PolyglotEngine.Instrument;
+import static org.junit.Assert.assertNotNull;
 
 public final class DebuggerExampleTest extends AbstractInstrumentationTest {
-
-    private static DebuggerExample debugger;
-
-    public static class TestFrontEnd implements DebuggerFrontEnd {
-        public void onAttach(DebuggerExample example) {
-            DebuggerExampleTest.debugger = example;
-        }
-
-        public void onDispose() {
-            DebuggerExampleTest.debugger = null;
-        }
-    }
-
-    @BeforeClass
-    public static void installFrontEnd() {
-        DebuggerExample.installFrontEnd(TestFrontEnd.class);
-    }
+    private DebuggerController debugger;
 
     @Before
     public void setupDebugger() throws IOException {
-        engine.getInstruments().get(DebuggerExample.ID).setEnabled(true);
+        Instrument instrument = engine.getInstruments().get(DebuggerController.ID);
+        instrument.setEnabled(true);
+        debugger = instrument.lookup(DebuggerController.class);
+        assertNotNull("Debugger interface found", debugger);
         assertEvalOut("", ""); // ensure debugger gets loaded
     }
 
@@ -68,7 +55,8 @@ public void setupDebugger() throws IOException {
     public void testBreakpoint() throws IOException {
         final AtomicBoolean breakpointHit = new AtomicBoolean();
         debugger.installBreakpoint(1, new Callback() {
-            public void halted(DebuggerExample d, EventContext haltedAt) {
+            @Override
+            public void halted(DebuggerController d, EventContext haltedAt) {
                 Assert.assertTrue(containsTag(haltedAt.getInstrumentedSourceSection().getTags(), InstrumentationTestLanguage.STATEMENT));
                 Assert.assertEquals(1, haltedAt.getInstrumentedSourceSection().getStartLine());
                 breakpointHit.set(true);
@@ -91,22 +79,22 @@ public void testStepInto() throws IOException {
 
         final AtomicBoolean allStepped = new AtomicBoolean();
         debugger.installBreakpoint(7, new Callback() {
-            public void halted(DebuggerExample debugger, EventContext haltedAt) {
+            public void halted(DebuggerController debugger, EventContext haltedAt) {
                 assertLineAt(haltedAt, 7);
                 debugger.stepInto(new Callback() {
-                    public void halted(DebuggerExample debugger, EventContext haltedAt) {
+                    public void halted(DebuggerController debugger, EventContext haltedAt) {
                         assertLineAt(haltedAt, 4);
                         debugger.stepInto(new Callback() {
-                            public void halted(DebuggerExample debugger, EventContext haltedAt) {
+                            public void halted(DebuggerController debugger, EventContext haltedAt) {
                                 assertLineAt(haltedAt, 5);
                                 debugger.stepInto(new Callback() {
-                                    public void halted(DebuggerExample debugger, EventContext haltedAt) {
+                                    public void halted(DebuggerController debugger, EventContext haltedAt) {
                                         assertLineAt(haltedAt, 2);
                                         debugger.stepInto(new Callback() {
-                                            public void halted(DebuggerExample debugger, EventContext haltedAt) {
+                                            public void halted(DebuggerController debugger, EventContext haltedAt) {
                                                 assertLineAt(haltedAt, 6);
                                                 debugger.stepInto(new Callback() {
-                                                    public void halted(DebuggerExample debugger, EventContext haltedAt) {
+                                                    public void halted(DebuggerController debugger, EventContext haltedAt) {
                                                         throw new AssertionError();
                                                     }
                                                 });
@@ -144,17 +132,17 @@ public void testStepOver() throws IOException {
 
         final AtomicBoolean allStepped = new AtomicBoolean();
         debugger.installBreakpoint(4, new Callback() {
-            public void halted(DebuggerExample debugger, EventContext haltedAt) {
+            public void halted(DebuggerController debugger, EventContext haltedAt) {
                 assertLineAt(haltedAt, 4);
                 debugger.stepOver(new Callback() {
-                    public void halted(DebuggerExample debugger, EventContext haltedAt) {
+                    public void halted(DebuggerController debugger, EventContext haltedAt) {
                         assertLineAt(haltedAt, 5);
                         debugger.stepOver(new Callback() {
-                            public void halted(DebuggerExample debugger, EventContext haltedAt) {
+                            public void halted(DebuggerController debugger, EventContext haltedAt) {
                                 assertLineAt(haltedAt, 6);
                                 allStepped.set(true);
                                 debugger.stepOver(new Callback() {
-                                    public void halted(DebuggerExample debugger, EventContext haltedAt) {
+                                    public void halted(DebuggerController debugger, EventContext haltedAt) {
                                         throw new AssertionError();
                                     }
                                 });
@@ -181,13 +169,16 @@ public void testStepOut() throws IOException {
 
         final AtomicBoolean allStepped = new AtomicBoolean();
         debugger.installBreakpoint(2, new Callback() {
-            public void halted(DebuggerExample debugger, EventContext haltedAt) {
+            @Override
+            public void halted(DebuggerController debugger, EventContext haltedAt) {
                 assertLineAt(haltedAt, 2);
                 debugger.stepOut(new Callback() {
-                    public void halted(DebuggerExample debugger, EventContext haltedAt) {
+                    @Override
+                    public void halted(DebuggerController debugger, EventContext haltedAt) {
                         assertLineAt(haltedAt, 6);
                         debugger.stepOver(new Callback() {
-                            public void halted(DebuggerExample debugger, EventContext haltedAt) {
+                            @Override
+                            public void halted(DebuggerController debugger, EventContext haltedAt) {
                                 throw new AssertionError();
                             }
                         });
diff --git a/truffle/com.oracle.truffle.api.instrumentation/src/com/oracle/truffle/api/instrumentation/InstrumentationHandler.java b/truffle/com.oracle.truffle.api.instrumentation/src/com/oracle/truffle/api/instrumentation/InstrumentationHandler.java
index bf316a0c8f9b..1e4b67cd4dba 100644
--- a/truffle/com.oracle.truffle.api.instrumentation/src/com/oracle/truffle/api/instrumentation/InstrumentationHandler.java
+++ b/truffle/com.oracle.truffle.api.instrumentation/src/com/oracle/truffle/api/instrumentation/InstrumentationHandler.java
@@ -49,6 +49,7 @@
 import com.oracle.truffle.api.nodes.RootNode;
 import com.oracle.truffle.api.source.Source;
 import com.oracle.truffle.api.source.SourceSection;
+import java.util.Set;
 
 /**
  * Central coordinator class for the Truffle instrumentation framework. Allocated once per engine.
@@ -124,8 +125,8 @@ void disposeInstrumentation(Object key, boolean cleanupRequired) {
         }
     }
 
-    void attachLanguage(Object context, InstrumentationLanguage<Object> language) {
-        addInstrumenter(context, new LanguageInstrumenter<>(language, context));
+    Instrumenter forLanguage(TruffleLanguage.Env context, TruffleLanguage<?> language) {
+        return new LanguageInstrumenter<>(language, context);
     }
 
     void detachLanguage(Object context) {
@@ -413,6 +414,11 @@ static Instrumentable getInstrumentable(Node node) {
         return null;
     }
 
+    private <T> T lookup(Object key, Class<T> type) {
+        AbstractInstrumenter value = instrumentations.get(key);
+        return value == null ? null : value.lookup(this, type);
+    }
+
     private abstract class AbstractNodeVisitor implements NodeVisitor {
 
         abstract boolean shouldVisit(RootNode root);
@@ -611,19 +617,29 @@ void dispose() {
             }
         }
 
+        @Override
+        <T> T lookup(InstrumentationHandler handler, Class<T> type) {
+            if (type.isAssignableFrom(getInstrumentationClass())) {
+                if (instrumentation == null) {
+                    handler.initialize();
+                }
+                return type.cast(instrumentation);
+            }
+            return null;
+        }
+
     }
 
     /**
      * Instrumenter implementation for use in {@link TruffleLanguage}.
      */
     final class LanguageInstrumenter<T> extends AbstractInstrumenter {
+        @SuppressWarnings("unused") private final TruffleLanguage.Env env;
+        private final TruffleLanguage<T> language;
 
-        private final T context;
-        private final InstrumentationLanguage<T> language;
-
-        LanguageInstrumenter(InstrumentationLanguage<T> language, T context) {
+        LanguageInstrumenter(TruffleLanguage<T> language, TruffleLanguage.Env env) {
             this.language = language;
-            this.context = context;
+            this.env = env;
         }
 
         @Override
@@ -637,13 +653,18 @@ boolean isInstrumentable(Node node) {
 
         @Override
         void initialize() {
-            language.installInstrumentations(context, this);
+            // language.installInstrumentations(env, this);
         }
 
         @Override
         void dispose() {
             // nothing todo
         }
+
+        @Override
+        <S> S lookup(InstrumentationHandler handler, Class<S> type) {
+            return null;
+        }
     }
 
     /**
@@ -657,6 +678,8 @@ abstract class AbstractInstrumenter extends Instrumenter {
 
         abstract void dispose();
 
+        abstract <T> T lookup(InstrumentationHandler handler, Class<T> type);
+
         void disposeBinding(EventBinding<?> binding) {
             InstrumentationHandler.this.disposeBinding(binding);
         }
@@ -712,12 +735,16 @@ protected boolean isInstrumentable(RootNode rootNode) {
         }
 
         @Override
-        @SuppressWarnings("unchecked")
-        protected void attachToInstrumentation(Object vm, TruffleLanguage<?> impl, com.oracle.truffle.api.TruffleLanguage.Env env) {
-            if (impl instanceof InstrumentationLanguage) {
-                InstrumentationHandler instrumentationHandler = (InstrumentationHandler) ACCESSOR.getInstrumentationHandler(vm);
-                instrumentationHandler.attachLanguage(findContext(env), (InstrumentationLanguage<Object>) impl);
-            }
+        protected void collectEnvServices(Set<Object> collectTo, Object vm, TruffleLanguage<?> impl, TruffleLanguage.Env env) {
+            InstrumentationHandler instrumentationHandler = (InstrumentationHandler) ACCESSOR.getInstrumentationHandler(vm);
+            Instrumenter instrumenter = instrumentationHandler.forLanguage(env, impl);
+            collectTo.add(instrumenter);
+        }
+
+        @Override
+        protected <T> T getInstrumentationHandlerService(Object vm, Object key, Class<T> type) {
+            InstrumentationHandler instrumentationHandler = (InstrumentationHandler) vm;
+            return instrumentationHandler.lookup(key, type);
         }
 
         @Override
diff --git a/truffle/com.oracle.truffle.api.instrumentation/src/com/oracle/truffle/api/instrumentation/InstrumentationLanguage.java b/truffle/com.oracle.truffle.api.instrumentation/src/com/oracle/truffle/api/instrumentation/InstrumentationLanguage.java
deleted file mode 100644
index 77b94db044fb..000000000000
--- a/truffle/com.oracle.truffle.api.instrumentation/src/com/oracle/truffle/api/instrumentation/InstrumentationLanguage.java
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright (c) 2016, 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.instrumentation;
-
-import com.oracle.truffle.api.TruffleLanguage;
-
-/**
- * <p>
- * {@link TruffleLanguage} implementations can decide to implement this additional interface to
- * register {@link EventBinding bindings} specifically for this language. This can be useful to
- * implement core language features using the instrumentation API. Instrumentations created by an
- * {@link InstrumentationLanguage} have elevated rights in the system. Exceptions thrown by
- * {@link EventBinding bindings} that were created using the {@link Instrumenter} passed in
- * {@link #installInstrumentations(Object, Instrumenter)} are directly passed on to the guest
- * language AST.
- * </p>
- *
- * Bindings created by the guest language are also automatically disposed together with the
- * language.
- */
-public interface InstrumentationLanguage<C> {
-
-    /**
-     * Invoked for each allocated context on guest language startup. Bindings attached to the
-     * instrumenter apply only for the given context and guest language.
-     *
-     * @param context the context of the language that
-     * @param instrumenter
-     *
-     * @see Instrumenter
-     */
-    void installInstrumentations(C context, Instrumenter instrumenter);
-
-}
diff --git a/truffle/com.oracle.truffle.api.instrumentation/src/com/oracle/truffle/api/instrumentation/package-info.java b/truffle/com.oracle.truffle.api.instrumentation/src/com/oracle/truffle/api/instrumentation/package-info.java
index 600a9267cd13..0232f32216f2 100644
--- a/truffle/com.oracle.truffle.api.instrumentation/src/com/oracle/truffle/api/instrumentation/package-info.java
+++ b/truffle/com.oracle.truffle.api.instrumentation/src/com/oracle/truffle/api/instrumentation/package-info.java
@@ -35,9 +35,10 @@
  * {@link com.oracle.truffle.api.instrumentation.TruffleInstrument} interface. Please refer to
  * {@link com.oracle.truffle.api.instrumentation.TruffleInstrument} for further details.
  *
- * Guest languages that want to use the capabilities of the instrumentation framework can implement
- * {@link com.oracle.truffle.api.instrumentation.InstrumentationLanguage} for their
- * {@link com.oracle.truffle.api.TruffleLanguage language} subclass.
+ * Guest languages that want to use the capabilities of the instrumentation framework can access
+ * {@link com.oracle.truffle.api.instrumentation.Instrumenter} for their
+ * {@link com.oracle.truffle.api.TruffleLanguage language} by calling
+ * {@link com.oracle.truffle.api.TruffleLanguage.Env#lookup lookup(Instrumenter.class)}.
  * {@link com.oracle.truffle.api.instrumentation.SourceSectionFilter Filters} created using guest
  * languages may be used to implement guest language features that require meta-programming
  * capabilities.
@@ -45,7 +46,6 @@
  * Instrumentations can get enabled/disabled using PolyglotEngine.
  *
  * @see com.oracle.truffle.api.instrumentation.TruffleInstrument
- * @see com.oracle.truffle.api.instrumentation.InstrumentationLanguage
  * @see com.oracle.truffle.api.instrumentation.Instrumentable
  */
 package com.oracle.truffle.api.instrumentation;
diff --git a/truffle/com.oracle.truffle.api.vm/src/com/oracle/truffle/api/vm/PolyglotEngine.java b/truffle/com.oracle.truffle.api.vm/src/com/oracle/truffle/api/vm/PolyglotEngine.java
index 2b5a5d3b40d0..42c404deb956 100644
--- a/truffle/com.oracle.truffle.api.vm/src/com/oracle/truffle/api/vm/PolyglotEngine.java
+++ b/truffle/com.oracle.truffle.api.vm/src/com/oracle/truffle/api/vm/PolyglotEngine.java
@@ -818,6 +818,10 @@ public boolean isEnabled() {
             return enabled;
         }
 
+        public <T> T lookup(Class<T> type) {
+            return SPI.getInstrumentationHandlerService(instrumentationHandler, this, type);
+        }
+
         public void setEnabled(final boolean enabled) {
             checkThread();
             if (this.enabled != enabled) {
@@ -852,7 +856,6 @@ void setEnabledImpl(final boolean enabled, boolean cleanup) {
         public String toString() {
             return "Instrument [id=" + getId() + ", name=" + getName() + ", version=" + getVersion() + ", enabled=" + enabled + "]";
         }
-
     }
 
     /**
@@ -946,7 +949,6 @@ TruffleLanguage.Env getEnv(boolean create) {
             if (env == null && create) {
                 TruffleLanguage<?> impl = info.getImpl(true);
                 env = SPI.attachEnv(PolyglotEngine.this, impl, out, err, in);
-                SPI.attachToInstrumentation(PolyglotEngine.this, impl, env);
             }
             return env;
         }
@@ -1067,8 +1069,8 @@ protected Object getInstrumentationHandler(Object obj) {
         }
 
         @Override
-        protected void attachToInstrumentation(Object vm, TruffleLanguage<?> impl, Env env) {
-            super.attachToInstrumentation(vm, impl, env);
+        protected <T> T getInstrumentationHandlerService(Object vm, Object key, Class<T> type) {
+            return super.getInstrumentationHandlerService(vm, key, type);
         }
 
         @Override
diff --git a/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/TruffleLanguage.java b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/TruffleLanguage.java
index cfae7e692599..b381ebe97edb 100644
--- a/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/TruffleLanguage.java
+++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/TruffleLanguage.java
@@ -45,6 +45,8 @@
 import com.oracle.truffle.api.nodes.Node;
 import com.oracle.truffle.api.nodes.RootNode;
 import com.oracle.truffle.api.source.Source;
+import java.util.LinkedHashSet;
+import java.util.Set;
 
 /**
  * An entry point for everyone who wants to implement a Truffle based language. By providing an
@@ -356,6 +358,7 @@ public static final class Env {
         private final InputStream in;
         private final OutputStream err;
         private final OutputStream out;
+        private final Object[] services;
 
         Env(Object vm, TruffleLanguage<?> lang, OutputStream out, OutputStream err, InputStream in) {
             this.vm = vm;
@@ -363,6 +366,9 @@ public static final class Env {
             this.err = err;
             this.out = out;
             this.lang = lang;
+            LinkedHashSet<Object> collectedServices = new LinkedHashSet<>();
+            API.collectEnvServices(collectedServices, vm, lang, this);
+            this.services = collectedServices.toArray();
             this.langCtx = new LangCtx<>(lang, this);
         }
 
@@ -433,6 +439,28 @@ public OutputStream err() {
         public Instrumenter instrumenter() {
             return null;
         }
+
+        /**
+         * Looks additional service up. An environment for a particular {@link TruffleLanguage
+         * language} and a {@link com.oracle.truffle.api.vm.PolyglotEngine} may also be associated
+         * with additional services. One can request implementations of such services by calling
+         * this method with the type identifying the requested service and its API.
+         *
+         * Services that can be obtained via this method include
+         * {@link com.oracle.truffle.api.instrumentation.Instrumenter} and others.
+         *
+         * @param <T> type of requested service
+         * @param type class of requested service
+         * @return instance of T or <code>null</code> if there is no such service available
+         */
+        public <T> T lookup(Class<T> type) {
+            for (Object obj : services) {
+                if (type.isInstance(obj)) {
+                    return type.cast(obj);
+                }
+            }
+            return null;
+        }
     }
 
     private static final AccessAPI API = new AccessAPI();
@@ -445,6 +473,11 @@ protected Env attachEnv(Object vm, TruffleLanguage<?> language, OutputStream std
             return env;
         }
 
+        @Override
+        protected void collectEnvServices(Set<Object> collectTo, Object vm, TruffleLanguage<?> impl, Env context) {
+            super.collectEnvServices(collectTo, vm, impl, context);
+        }
+
         @Override
         protected Object importSymbol(Object vm, TruffleLanguage<?> queryingLang, String globalName) {
             return super.importSymbol(vm, queryingLang, globalName);
diff --git a/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/Accessor.java b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/Accessor.java
index 840c026c1fa3..291b83a68129 100644
--- a/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/Accessor.java
+++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/Accessor.java
@@ -45,6 +45,7 @@
 import com.oracle.truffle.api.nodes.Node;
 import com.oracle.truffle.api.nodes.RootNode;
 import com.oracle.truffle.api.source.Source;
+import java.util.Set;
 
 /**
  * Communication between PolyglotEngine, TruffleLanguage API/SPI, and other services.
@@ -261,6 +262,10 @@ protected Object getInstrumentationHandler(Object known) {
         return SPI.getInstrumentationHandler(vm);
     }
 
+    protected <T> T getInstrumentationHandlerService(Object handler, Object key, Class<T> type) {
+        return INSTRUMENTHANDLER.getInstrumentationHandlerService(handler, key, type);
+    }
+
     // new instrumentation
     protected Object createInstrumentationHandler(Object vm, OutputStream out, OutputStream err, InputStream in) {
         return INSTRUMENTHANDLER.createInstrumentationHandler(vm, out, err, in);
@@ -337,8 +342,8 @@ protected void initializeCallTarget(RootCallTarget target) {
         INSTRUMENTHANDLER.initializeCallTarget(target);
     }
 
-    protected void attachToInstrumentation(Object vm, TruffleLanguage<?> impl, Env context) {
-        INSTRUMENTHANDLER.attachToInstrumentation(vm, impl, context);
+    protected void collectEnvServices(Set<Object> collectTo, Object vm, TruffleLanguage<?> impl, Env context) {
+        INSTRUMENTHANDLER.collectEnvServices(collectTo, vm, impl, context);
     }
 
     protected void detachFromInstrumentation(Object vm, Env context) {

From 31288d2afc46041504fca12723d46d000612fc09 Mon Sep 17 00:00:00 2001
From: Jaroslav Tulach <jaroslav.tulach@oracle.com>
Date: Mon, 8 Feb 2016 11:56:09 +0100
Subject: [PATCH 2/2] Debugger.find(PolyglotEngine) is a way to initialize
 debugger. The call can be made sooner than any script is evaluated.

---
 mx.truffle/suite.py                           |  18 +++-
 .../oracle/truffle/api/debug/Debugger.java    | 100 +++++++++---------
 .../api/debug/impl/DebuggerInstrument.java    |  58 ++++++++++
 .../oracle/truffle/api/vm/EventConsumer.java  |   4 +-
 .../oracle/truffle/api/vm/PolyglotEngine.java |  45 ++------
 .../com/oracle/truffle/api/impl/Accessor.java |   9 +-
 .../tools/debug/shell/server/REPLServer.java  |   1 +
 7 files changed, 137 insertions(+), 98 deletions(-)
 create mode 100644 truffle/com.oracle.truffle.api.debug/src/com/oracle/truffle/api/debug/impl/DebuggerInstrument.java

diff --git a/mx.truffle/suite.py b/mx.truffle/suite.py
index 118d5e1b4f9f..b824086706e8 100644
--- a/mx.truffle/suite.py
+++ b/mx.truffle/suite.py
@@ -51,7 +51,7 @@
       "sourceDirs" : ["src"],
       "dependencies" : [
         "com.oracle.truffle.api.interop.java",
-        "com.oracle.truffle.api.debug",
+        "com.oracle.truffle.api.instrumentation",
       ],
       "javaCompliance" : "1.7",
       "workingSets" : "API,Truffle",
@@ -63,6 +63,7 @@
       "dependencies" : [
         "com.oracle.truffle.api.profiles",
         "com.oracle.truffle.api.interop",
+        "com.oracle.truffle.api.debug",
         "com.oracle.truffle.api.vm",
         "mx:JUNIT",
       ],
@@ -146,7 +147,10 @@
     "com.oracle.truffle.api.debug" : {
       "subDir" : "truffle",
       "sourceDirs" : ["src"],
-      "dependencies" : ["com.oracle.truffle.api.instrumentation"],
+      "dependencies" : [
+        "com.oracle.truffle.api.instrumentation",
+        "com.oracle.truffle.api.vm"
+      ],
       "checkstyle" : "com.oracle.truffle.api",
       "annotationProcessors" : ["INTERNAL_PROCESSOR"],
       "javaCompliance" : "1.7",
@@ -268,9 +272,12 @@
     "com.oracle.truffle.tools.debug.shell" : {
       "subDir" : "truffle",
       "sourceDirs" : ["src"],
-      "dependencies" : ["com.oracle.truffle.tools", 
-                        "com.oracle.truffle.api.vm",
-                        "JLINE"],
+      "dependencies" : [
+        "com.oracle.truffle.tools", 
+        "com.oracle.truffle.api.debug",
+        "com.oracle.truffle.api.vm",
+        "JLINE"
+      ],
       "checkstyle" : "com.oracle.truffle.api",
       "javaCompliance" : "1.7",
       "workingSets" : "Truffle,Tools",
@@ -331,6 +338,7 @@
         "com.oracle.truffle.api.interop.java",
         "com.oracle.truffle.api.dsl",
         "com.oracle.truffle.api.profiles",
+        "com.oracle.truffle.api.debug",
         "com.oracle.truffle.api.vm",
         "com.oracle.truffle.object.basic",
       ],
diff --git a/truffle/com.oracle.truffle.api.debug/src/com/oracle/truffle/api/debug/Debugger.java b/truffle/com.oracle.truffle.api.debug/src/com/oracle/truffle/api/debug/Debugger.java
index e0a9b2b49a73..25d49d534d92 100644
--- a/truffle/com.oracle.truffle.api.debug/src/com/oracle/truffle/api/debug/Debugger.java
+++ b/truffle/com.oracle.truffle.api.debug/src/com/oracle/truffle/api/debug/Debugger.java
@@ -38,6 +38,7 @@
 import com.oracle.truffle.api.QuitException;
 import com.oracle.truffle.api.Truffle;
 import com.oracle.truffle.api.TruffleLanguage;
+import com.oracle.truffle.api.debug.impl.DebuggerInstrument;
 import com.oracle.truffle.api.frame.FrameInstance;
 import com.oracle.truffle.api.frame.FrameInstance.FrameAccess;
 import com.oracle.truffle.api.frame.FrameInstanceVisitor;
@@ -50,12 +51,11 @@
 import com.oracle.truffle.api.instrumentation.EventListener;
 import com.oracle.truffle.api.instrumentation.Instrumenter;
 import com.oracle.truffle.api.instrumentation.SourceSectionFilter;
-import com.oracle.truffle.api.instrumentation.TruffleInstrument;
-import com.oracle.truffle.api.instrumentation.TruffleInstrument.Registration;
 import com.oracle.truffle.api.nodes.Node;
 import com.oracle.truffle.api.source.LineLocation;
 import com.oracle.truffle.api.source.Source;
 import com.oracle.truffle.api.source.SourceSection;
+import com.oracle.truffle.api.vm.PolyglotEngine;
 
 /**
  * Represents debugging related state of a {@link com.oracle.truffle.api.vm.PolyglotEngine}.
@@ -63,11 +63,7 @@
  * {@link ExecutionEvent#getDebugger()} events, once {@link com.oracle.truffle.api.debug debugging
  * is turned on}.
  */
-@Registration(id = Debugger.ID, autostart = true)
-public final class Debugger extends TruffleInstrument {
-
-    public static final String ID = "debugger";
-
+public final class Debugger {
     public static final String BLOCK_TAG = "debug-BLOCK";
 
     public static final String CALL_TAG = "debug-CALL";
@@ -83,17 +79,53 @@ public final class Debugger extends TruffleInstrument {
     private static final SourceSectionFilter CALL_FILTER = SourceSectionFilter.newBuilder().tagIs(CALL_TAG).build();
     private static final SourceSectionFilter HALT_FILTER = SourceSectionFilter.newBuilder().tagIs(HALT_TAG).build();
 
+    /** Finds debugger associated with given engine. There is at most one
+     * debugger associated with any {@link PolyglotEngine}. One can access it
+     * by calling this static method. Once the debugger is initialized, events
+     * like {@link SuspendedEvent} or {@link ExecutionEvent} are delivered to
+     * {@link com.oracle.truffle.api.vm.PolyglotEngine.Builder#onEvent(com.oracle.truffle.api.vm.EventConsumer) registered event handlers}
+     * whenever an important event (related to debugging) occurs in the 
+     * engine.
+     * 
+     * 
+     * @param engine the engine to find debugger for
+     * @return an instance of associated debugger, never <code>null</code>
+     */
+    public static Debugger find(PolyglotEngine engine) {
+        return find(engine, true);
+    }
+
+    private static final DebuggerInstrument.Factory FACTORY = new DebuggerInstrument.Factory() {
+        @Override
+        public Debugger create(PolyglotEngine engine, Instrumenter instrumenter) {
+            return new Debugger(engine, instrumenter);
+        }
+    };
+
+    private static Debugger find(PolyglotEngine engine, boolean create) {
+        PolyglotEngine.Instrument instrument = engine.getInstruments().get(DebuggerInstrument.ID);
+        if (instrument == null) {
+            throw new IllegalStateException();
+        }
+        final DebuggerInstrument debugInstrument = instrument.lookup(DebuggerInstrument.class);
+        return debugInstrument.getDebugger(engine, create ? FACTORY : null);
+    }
+
     private static void trace(String format, Object... args) {
         if (TRACE) {
             OUT.println(TRACE_PREFIX + String.format(format, args));
         }
     }
 
-    private Instrumenter instrumenter;
-
-    private Object vm = null;  // TODO
+    private final PolyglotEngine engine;
+    private final Instrumenter instrumenter;
     private Source lastSource;
 
+    Debugger(PolyglotEngine engine, Instrumenter instrumenter) {
+        this.engine = engine;
+        this.instrumenter = instrumenter;
+    }
+
     interface BreakpointCallback {
 
         /**
@@ -141,32 +173,6 @@ public void addWarning(String warning) {
      */
     private DebugExecutionContext debugContext;
 
-    @Override
-    protected void onCreate(Env env, Instrumenter originalInstrumenter) {
-
-        if (TRACE) {
-            trace("BEGIN onCreate()");
-        }
-
-        this.instrumenter = originalInstrumenter;
-        Source.setFileCaching(true);
-
-        // Initialize execution context stack
-        debugContext = new DebugExecutionContext(null, null, 0);
-        debugContext.setStrategy(0, new Continue());
-        debugContext.contextTrace("START EXEC DEFAULT");
-
-        this.lineBreaks = new LineBreakpointFactory(this, instrumenter, breakpointCallback, warningLog);
-        this.tagBreaks = new TagBreakpointFactory(this, breakpointCallback, warningLog);
-
-        newestDebugger = this;  // TODO (mlvdv) hack
-
-        if (TRACE) {
-            trace("END onCreate()");
-        }
-
-    }
-
     /**
      * Sets a breakpoint to halt at a source line.
      *
@@ -885,7 +891,7 @@ public FrameInstance visitFrame(FrameInstance frameInstance) {
 
             try {
                 // Pass control to the debug client with current execution suspended
-                ACCESSOR.dispatchEvent(vm, new SuspendedEvent(Debugger.this, haltedNode, haltedFrame, contextStack, recentWarnings));
+                ACCESSOR.dispatchEvent(engine, new SuspendedEvent(Debugger.this, haltedNode, haltedFrame, contextStack, recentWarnings));
                 // Debug client finished normally, execution resumes
                 // Presume that the client has set a new strategy (or default to Continue)
                 running = true;
@@ -944,9 +950,6 @@ public Void visitFrame(FrameInstance frameInstance) {
     }
 
     void executionStarted(Object theVM, int depth, Source source) {
-        if (this.vm == null) {
-            this.vm = theVM;
-        }
         Source execSource = source;
         if (execSource == null) {
             execSource = lastSource;
@@ -957,7 +960,7 @@ void executionStarted(Object theVM, int depth, Source source) {
         debugContext = new DebugExecutionContext(execSource, debugContext, depth);
         prepareContinue(depth);
         debugContext.contextTrace("START EXEC ");
-        ACCESSOR.dispatchEvent(vm, new ExecutionEvent(this));
+        ACCESSOR.dispatchEvent(engine, new ExecutionEvent(this));
     }
 
     void executionEnded() {
@@ -980,9 +983,9 @@ void executionEnded() {
      */
     Object evalInContext(SuspendedEvent ev, String code, FrameInstance frameInstance) throws IOException {
         if (frameInstance == null) {
-            return ACCESSOR.evalInContext(vm, ev, code, debugContext.haltedNode, debugContext.haltedFrame);
+            return ACCESSOR.evalInContext(engine, ev, code, debugContext.haltedNode, debugContext.haltedFrame);
         } else {
-            return ACCESSOR.evalInContext(vm, ev, code, frameInstance.getCallNode(), frameInstance.getFrame(FrameAccess.MATERIALIZE, true).materialize());
+            return ACCESSOR.evalInContext(engine, ev, code, frameInstance.getCallNode(), frameInstance.getFrame(FrameAccess.MATERIALIZE, true).materialize());
         }
     }
 
@@ -990,14 +993,14 @@ static final class AccessorDebug extends Accessor {
 
         @Override
         protected Closeable executionStart(Object vm, int currentDepth, final Object d, Source s) {
-            if (d == null) {
+            final Debugger debugger = find((PolyglotEngine)vm, false);
+            if (debugger == null) {
                 return new Closeable() {
                     @Override
                     public void close() throws IOException {
                     }
                 };
             }
-            final Debugger debugger = (Debugger) d;
             debugger.executionStarted(vm, currentDepth, s);
             return new Closeable() {
                 @Override
@@ -1007,11 +1010,6 @@ public void close() throws IOException {
             };
         }
 
-        @Override
-        protected Object getDebugger(Object vm) {
-            return newestDebugger;
-        }
-
         @SuppressWarnings("rawtypes")
         @Override
         protected Class<? extends TruffleLanguage> findLanguage(Node node) {
@@ -1037,6 +1035,4 @@ protected CallTarget parse(Class<? extends TruffleLanguage> languageClass, Sourc
 
     // registers into Accessor.DEBUG
     static final AccessorDebug ACCESSOR = new AccessorDebug();
-
-    static Debugger newestDebugger = null;
 }
diff --git a/truffle/com.oracle.truffle.api.debug/src/com/oracle/truffle/api/debug/impl/DebuggerInstrument.java b/truffle/com.oracle.truffle.api.debug/src/com/oracle/truffle/api/debug/impl/DebuggerInstrument.java
new file mode 100644
index 000000000000..0e17ade9c4f5
--- /dev/null
+++ b/truffle/com.oracle.truffle.api.debug/src/com/oracle/truffle/api/debug/impl/DebuggerInstrument.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2015, 2016, 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.impl;
+
+import com.oracle.truffle.api.debug.Debugger;
+import com.oracle.truffle.api.instrumentation.Instrumenter;
+import com.oracle.truffle.api.instrumentation.TruffleInstrument;
+import com.oracle.truffle.api.instrumentation.TruffleInstrument.Registration;
+import com.oracle.truffle.api.source.Source;
+import com.oracle.truffle.api.vm.PolyglotEngine;
+
+@Registration(id = DebuggerInstrument.ID, autostart = true)
+public final class DebuggerInstrument extends TruffleInstrument {
+    public static final String ID = "debugger";
+
+    private Debugger debugger;
+    private Instrumenter instrumenter;
+
+    @Override
+    protected void onCreate(Env env, Instrumenter originalInstrumenter) {
+        this.instrumenter = originalInstrumenter;
+        Source.setFileCaching(true);
+    }
+
+    public Debugger getDebugger(PolyglotEngine engine, Factory factory) {
+        if (debugger == null && factory != null) {
+            debugger = factory.create(engine, instrumenter);
+        }
+        debugger.getClass();
+        return debugger;
+    }
+
+    public static interface Factory {
+        Debugger create(PolyglotEngine engine, Instrumenter instrumenter);
+    }
+}
diff --git a/truffle/com.oracle.truffle.api.vm/src/com/oracle/truffle/api/vm/EventConsumer.java b/truffle/com.oracle.truffle.api.vm/src/com/oracle/truffle/api/vm/EventConsumer.java
index da1f2fb8a89e..c3f79d267a73 100644
--- a/truffle/com.oracle.truffle.api.vm/src/com/oracle/truffle/api/vm/EventConsumer.java
+++ b/truffle/com.oracle.truffle.api.vm/src/com/oracle/truffle/api/vm/EventConsumer.java
@@ -25,14 +25,12 @@
 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 PolyglotEngine} generates various events and delivers them to
  * {@link PolyglotEngine.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
+ * {@link com.oracle.truffle.api.debug.ExecutionEvent} or {@link com.oracle.truffle.api.debug.SuspendedEvent} useful when debugging {@link TruffleLanguage
  * Truffle language}s.
  *
  * @param <Event> type of event to observe and handle
diff --git a/truffle/com.oracle.truffle.api.vm/src/com/oracle/truffle/api/vm/PolyglotEngine.java b/truffle/com.oracle.truffle.api.vm/src/com/oracle/truffle/api/vm/PolyglotEngine.java
index 42c404deb956..f9622bf6c1f6 100644
--- a/truffle/com.oracle.truffle.api.vm/src/com/oracle/truffle/api/vm/PolyglotEngine.java
+++ b/truffle/com.oracle.truffle.api.vm/src/com/oracle/truffle/api/vm/PolyglotEngine.java
@@ -50,9 +50,6 @@
 import com.oracle.truffle.api.TruffleLanguage.Env;
 import com.oracle.truffle.api.TruffleLanguage.Registration;
 import com.oracle.truffle.api.TruffleOptions;
-import com.oracle.truffle.api.debug.Debugger;
-import com.oracle.truffle.api.debug.ExecutionEvent;
-import com.oracle.truffle.api.debug.SuspendedEvent;
 import com.oracle.truffle.api.frame.MaterializedFrame;
 import com.oracle.truffle.api.frame.VirtualFrame;
 import com.oracle.truffle.api.impl.Accessor;
@@ -114,7 +111,6 @@ public class PolyglotEngine {
     private final Map<String, Object> globals;
     private final Object instrumentationHandler;
     private final Map<String, Instrument> instruments;
-    private Object debugger = null;
     private boolean disposed;
 
     static {
@@ -140,7 +136,6 @@ public class PolyglotEngine {
         this.globals = null;
         this.executor = null;
         this.instrumentationHandler = null;
-        this.debugger = null;
         this.instruments = null;
     }
 
@@ -167,19 +162,6 @@ public class PolyglotEngine {
         }
         this.langs = map;
         this.instruments = createAndAutostartDescriptors(InstrumentCache.load(getClass().getClassLoader()));
-        try {
-            Class.forName("com.oracle.truffle.api.debug.Debugger", true, Debugger.class.getClassLoader());
-        } catch (ClassNotFoundException e) {
-            // TODO Auto-generated catch block
-            e.printStackTrace();
-        }
-    }
-
-    private Object getDebugger() {
-        if (debugger == null) {
-            debugger = SPI.getDebugger(this);
-        }
-        return debugger;
     }
 
     private Map<String, Instrument> createAndAutostartDescriptors(List<InstrumentCache> instrumentCaches) {
@@ -482,7 +464,7 @@ Language createLanguage(Map.Entry<String, LanguageCache> en) {
 
     @SuppressWarnings("try")
     private Object evalImpl(TruffleLanguage<?>[] fillLang, Source s, Language l) throws IOException {
-        try (Closeable d = SPI.executionStart(this, -1, getDebugger(), s)) {
+        try (Closeable d = SPI.executionStart(this, -1, null, s)) {
             TruffleLanguage<?> langImpl = l.getImpl(true);
             fillLang[0] = langImpl;
             return SPI.eval(langImpl, s, l.cache);
@@ -493,7 +475,7 @@ private Object evalImpl(TruffleLanguage<?>[] fillLang, Source s, Language l) thr
     final Object invokeForeign(final Node foreignNode, VirtualFrame frame, final TruffleObject receiver) throws IOException {
         Object res;
         if (executor == null) {
-            try (final Closeable c = SPI.executionStart(PolyglotEngine.this, -1, getDebugger(), null)) {
+            try (final Closeable c = SPI.executionStart(PolyglotEngine.this, -1, null, null)) {
                 final Object[] args = ForeignAccess.getArguments(frame).toArray();
                 res = ForeignAccess.execute(foreignNode, frame, receiver, args);
             }
@@ -514,7 +496,7 @@ private Object invokeForeignOnExecutor(final Node foreignNode, VirtualFrame fram
             @SuppressWarnings("try")
             @Override
             protected Object compute() throws IOException {
-                try (final Closeable c = SPI.executionStart(PolyglotEngine.this, -1, getDebugger(), null)) {
+                try (final Closeable c = SPI.executionStart(PolyglotEngine.this, -1, null, null)) {
                     final Object[] args = ForeignAccess.getArguments(materialized).toArray();
                     RootNode node = SymbolInvokerImpl.createTemporaryRoot(TruffleLanguage.class, foreignNode, receiver, args.length);
                     final CallTarget target = Truffle.getRuntime().createCallTarget(node);
@@ -601,21 +583,21 @@ private void checkThread() {
     @SuppressWarnings("unchecked")
     void dispatch(Object ev) {
         Class type = ev.getClass();
-        if (type == SuspendedEvent.class) {
-            dispatchSuspendedEvent((SuspendedEvent) ev);
+        if (type.getSimpleName().equals("SuspendedEvent")) {
+            dispatchSuspendedEvent(ev);
         }
-        if (type == ExecutionEvent.class) {
-            dispatchExecutionEvent((ExecutionEvent) ev);
+        if (type.getSimpleName().equals("ExecutionEvent")) {
+            dispatchExecutionEvent(ev);
         }
         dispatch(type, ev);
     }
 
     @SuppressWarnings("unused")
-    void dispatchSuspendedEvent(SuspendedEvent event) {
+    void dispatchSuspendedEvent(Object event) {
     }
 
     @SuppressWarnings("unused")
-    void dispatchExecutionEvent(ExecutionEvent event) {
+    void dispatchExecutionEvent(Object event) {
     }
 
     @SuppressWarnings("unchecked")
@@ -757,7 +739,7 @@ public Value execute(final Object... args) throws IOException {
                 @SuppressWarnings("try")
                 @Override
                 protected Object compute() throws IOException {
-                    try (final Closeable c = SPI.executionStart(PolyglotEngine.this, -1, debugger, null)) {
+                    try (final Closeable c = SPI.executionStart(PolyglotEngine.this, -1, null, null)) {
                         List<Object> arr = new ArrayList<>();
                         arr.addAll(Arrays.asList(args));
                         for (;;) {
@@ -931,7 +913,7 @@ public Value eval(Source source) throws IOException {
         @SuppressWarnings("try")
         public Value getGlobalObject() {
             checkThread();
-            try (Closeable d = SPI.executionStart(PolyglotEngine.this, -1, debugger, null)) {
+            try (Closeable d = SPI.executionStart(PolyglotEngine.this, -1, null, null)) {
                 Object res = SPI.languageGlobal(getEnv(true));
                 return res == null ? null : new Value(new TruffleLanguage[]{info.getImpl(true)}, res);
             } catch (IOException ex) {
@@ -1057,11 +1039,6 @@ protected Object createInstrumentationHandler(Object vm, OutputStream out, Outpu
             return super.createInstrumentationHandler(vm, out, err, in);
         }
 
-        @Override
-        protected Object getDebugger(Object vm) {
-            return super.getDebugger(vm);
-        }
-
         @Override
         protected Object getInstrumentationHandler(Object obj) {
             final PolyglotEngine vm = (PolyglotEngine) obj;
diff --git a/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/Accessor.java b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/Accessor.java
index 291b83a68129..3ef0738bda8d 100644
--- a/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/Accessor.java
+++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/Accessor.java
@@ -110,6 +110,11 @@ protected Object evalInContext(Source source, Node node, MaterializedFrame mFram
         new Node(null) {
         }.getRootNode();
 
+        try {
+            Class.forName("com.oracle.truffle.api.debug.Debugger", true, Accessor.class.getClassLoader());
+        } catch (ClassNotFoundException ex) {
+            throw new IllegalStateException(ex);
+        }
     }
 
     protected Accessor() {
@@ -271,10 +276,6 @@ protected Object createInstrumentationHandler(Object vm, OutputStream out, Outpu
         return INSTRUMENTHANDLER.createInstrumentationHandler(vm, out, err, in);
     }
 
-    protected Object getDebugger(Object vm) {
-        return DEBUG == null ? null : DEBUG.getDebugger(vm);
-    }
-
     private static Reference<Object> previousVM = new WeakReference<>(null);
     private static Assumption oneVM = Truffle.getRuntime().createAssumption();
 
diff --git a/truffle/com.oracle.truffle.tools.debug.shell/src/com/oracle/truffle/tools/debug/shell/server/REPLServer.java b/truffle/com.oracle.truffle.tools.debug.shell/src/com/oracle/truffle/tools/debug/shell/server/REPLServer.java
index afd3b625d39a..9b09a2bb28c3 100644
--- a/truffle/com.oracle.truffle.tools.debug.shell/src/com/oracle/truffle/tools/debug/shell/server/REPLServer.java
+++ b/truffle/com.oracle.truffle.tools.debug.shell/src/com/oracle/truffle/tools/debug/shell/server/REPLServer.java
@@ -120,6 +120,7 @@ public int compare(Language lang1, Language lang2) {
     public REPLServer(String defaultMIMEType, Visualizer visualizer) {
         this.visualizer = visualizer == null ? new DefaultVisualizer() : visualizer;
         this.engine = PolyglotEngine.newBuilder().onEvent(onHalted).onEvent(onExec).build();
+        this.db = Debugger.find(this.engine);
         engineLanguages.addAll(engine.getLanguages().values());
         if (engineLanguages.size() == 0) {
             throw new RuntimeException("No language implementations installed");