Skip to content

Commit

Permalink
Merge pull request oracle#3 from jtulach/DebuggerAsInstrument
Browse files Browse the repository at this point in the history
Debugger as instrument
  • Loading branch information
mlvdv committed Feb 8, 2016
2 parents 9c00f1e + 31288d2 commit 3f070cf
Show file tree
Hide file tree
Showing 15 changed files with 319 additions and 263 deletions.
18 changes: 13 additions & 5 deletions mx.truffle/suite.py
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand All @@ -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",
],
Expand Down Expand Up @@ -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",
Expand Down Expand Up @@ -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",
Expand Down Expand Up @@ -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",
],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -50,24 +51,19 @@
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}.
* Instance of this class is delivered via {@link SuspendedEvent#getDebugger()} and
* {@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";
Expand All @@ -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 {

/**
Expand Down Expand Up @@ -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.
*
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand All @@ -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() {
Expand All @@ -980,24 +983,24 @@ 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());
}
}

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
Expand All @@ -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) {
Expand All @@ -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;
}
Original file line number Diff line number Diff line change
@@ -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);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -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;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -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);

}

}
Loading

0 comments on commit 3f070cf

Please sign in to comment.