Improvement of debugger plugin. Debugger itself became multithreaded

This commit is contained in:
konsoletyper 2014-07-31 21:38:32 +04:00
parent 930d2087ab
commit c490e2f9f8
11 changed files with 127 additions and 121 deletions

View File

@ -2,6 +2,9 @@ package org.teavm.chromerdp;
import java.io.IOException; import java.io.IOException;
import java.util.*; import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.atomic.AtomicInteger;
import org.codehaus.jackson.JsonNode; import org.codehaus.jackson.JsonNode;
import org.codehaus.jackson.map.ObjectMapper; import org.codehaus.jackson.map.ObjectMapper;
import org.teavm.chromerdp.data.CallFrameDTO; import org.teavm.chromerdp.data.CallFrameDTO;
@ -16,16 +19,21 @@ import org.teavm.debugging.*;
* @author Alexey Andreev <konsoletyper@gmail.com> * @author Alexey Andreev <konsoletyper@gmail.com>
*/ */
public class ChromeRDPDebugger implements JavaScriptDebugger, ChromeRDPExchangeConsumer { public class ChromeRDPDebugger implements JavaScriptDebugger, ChromeRDPExchangeConsumer {
private static final Object dummy = new Object();
private ChromeRDPExchange exchange; private ChromeRDPExchange exchange;
private List<JavaScriptDebuggerListener> listeners = new ArrayList<>(); private ConcurrentMap<JavaScriptDebuggerListener, Object> listeners = new ConcurrentHashMap<>();
private Set<RDPBreakpoint> breakpoints = new HashSet<>(); private ConcurrentMap<RDPBreakpoint, Object> breakpoints = new ConcurrentHashMap<>();
private RDPCallFrame[] callStack = new RDPCallFrame[0]; private volatile RDPCallFrame[] callStack = new RDPCallFrame[0];
private Map<String, String> scripts = new HashMap<>(); private ConcurrentMap<String, String> scripts = new ConcurrentHashMap<>();
private Map<String, String> scriptIds = new HashMap<>(); private ConcurrentMap<String, String> scriptIds = new ConcurrentHashMap<>();
private boolean suspended = false; private boolean suspended = false;
private ObjectMapper mapper = new ObjectMapper(); private ObjectMapper mapper = new ObjectMapper();
private Map<Integer, ResponseHandler> responseHandlers = new HashMap<>(); private ConcurrentMap<Integer, ResponseHandler> responseHandlers = new ConcurrentHashMap<>();
private int messageIdGenerator; private AtomicInteger messageIdGenerator = new AtomicInteger();
private List<JavaScriptDebuggerListener> getListeners() {
return new ArrayList<>(listeners.keySet());
}
@Override @Override
public void setExchange(ChromeRDPExchange exchange) { public void setExchange(ChromeRDPExchange exchange) {
@ -37,15 +45,15 @@ public class ChromeRDPDebugger implements JavaScriptDebugger, ChromeRDPExchangeC
} }
this.exchange = exchange; this.exchange = exchange;
if (exchange != null) { if (exchange != null) {
for (RDPBreakpoint breakpoint : breakpoints) { for (RDPBreakpoint breakpoint : breakpoints.keySet().toArray(new RDPBreakpoint[0])) {
updateBreakpoint(breakpoint); updateBreakpoint(breakpoint);
} }
for (JavaScriptDebuggerListener listener : listeners) { for (JavaScriptDebuggerListener listener : getListeners()) {
listener.attached(); listener.attached();
} }
} else { } else {
suspended = false; suspended = false;
for (JavaScriptDebuggerListener listener : listeners) { for (JavaScriptDebuggerListener listener : getListeners()) {
listener.detached(); listener.detached();
} }
} }
@ -86,7 +94,7 @@ public class ChromeRDPDebugger implements JavaScriptDebugger, ChromeRDPExchangeC
callStack[i] = map(callFrameDTOs[i]); callStack[i] = map(callFrameDTOs[i]);
} }
this.callStack = callStack; this.callStack = callStack;
for (JavaScriptDebuggerListener listener : listeners) { for (JavaScriptDebuggerListener listener : getListeners()) {
listener.paused(); listener.paused();
} }
} }
@ -94,18 +102,17 @@ public class ChromeRDPDebugger implements JavaScriptDebugger, ChromeRDPExchangeC
private synchronized void fireResumed() { private synchronized void fireResumed() {
suspended = false; suspended = false;
callStack = null; callStack = null;
for (JavaScriptDebuggerListener listener : listeners) { for (JavaScriptDebuggerListener listener : getListeners()) {
listener.resumed(); listener.resumed();
} }
} }
private synchronized void scriptParsed(ScriptParsedNotification params) { private synchronized void scriptParsed(ScriptParsedNotification params) {
if (scripts.containsKey(params.getScriptId())) { if (scripts.putIfAbsent(params.getScriptId(), params.getUrl()) != null) {
return; return;
} }
scripts.put(params.getScriptId(), params.getUrl());
scriptIds.put(params.getUrl(), params.getScriptId()); scriptIds.put(params.getUrl(), params.getScriptId());
for (JavaScriptDebuggerListener listener : listeners) { for (JavaScriptDebuggerListener listener : getListeners()) {
listener.scriptAdded(params.getUrl()); listener.scriptAdded(params.getUrl());
} }
} }
@ -113,7 +120,7 @@ public class ChromeRDPDebugger implements JavaScriptDebugger, ChromeRDPExchangeC
@Override @Override
public void addListener(JavaScriptDebuggerListener listener) { public void addListener(JavaScriptDebuggerListener listener) {
listeners.add(listener); listeners.put(listener, dummy);
} }
@Override @Override
@ -194,23 +201,32 @@ public class ChromeRDPDebugger implements JavaScriptDebugger, ChromeRDPExchangeC
return exchange != null; return exchange != null;
} }
@Override
public void detach() {
if (exchange != null) {
exchange.disconnect();
}
}
@Override @Override
public JavaScriptCallFrame[] getCallStack() { public JavaScriptCallFrame[] getCallStack() {
if (exchange == null) { if (exchange == null) {
return null; return null;
} }
JavaScriptCallFrame[] callStack = this.callStack;
return callStack != null ? callStack.clone() : null; return callStack != null ? callStack.clone() : null;
} }
@Override @Override
public JavaScriptBreakpoint createBreakpoint(JavaScriptLocation location) { public JavaScriptBreakpoint createBreakpoint(JavaScriptLocation location) {
RDPBreakpoint breakpoint = new RDPBreakpoint(this, location); RDPBreakpoint breakpoint = new RDPBreakpoint(this, location);
breakpoints.add(breakpoint); breakpoints.put(breakpoint, dummy);
updateBreakpoint(breakpoint); updateBreakpoint(breakpoint);
return breakpoint; return breakpoint;
} }
void destroyBreakpoint(RDPBreakpoint breakpoint) { void destroyBreakpoint(RDPBreakpoint breakpoint) {
breakpoints.remove(breakpoint);
if (breakpoint.chromeId != null) { if (breakpoint.chromeId != null) {
Message message = new Message(); Message message = new Message();
message.setMethod("Debugger.removeBreakpoint"); message.setMethod("Debugger.removeBreakpoint");
@ -222,7 +238,7 @@ public class ChromeRDPDebugger implements JavaScriptDebugger, ChromeRDPExchangeC
} }
void fireScriptAdded(String script) { void fireScriptAdded(String script) {
for (JavaScriptDebuggerListener listener : listeners) { for (JavaScriptDebuggerListener listener : getListeners()) {
listener.scriptAdded(script); listener.scriptAdded(script);
} }
} }
@ -232,7 +248,7 @@ public class ChromeRDPDebugger implements JavaScriptDebugger, ChromeRDPExchangeC
return; return;
} }
Message message = new Message(); Message message = new Message();
message.setId(++messageIdGenerator); message.setId(messageIdGenerator.incrementAndGet());
message.setMethod("Debugger.setBreakpoint"); message.setMethod("Debugger.setBreakpoint");
SetBreakpointCommand params = new SetBreakpointCommand(); SetBreakpointCommand params = new SetBreakpointCommand();
params.setLocation(unmap(breakpoint.getLocation())); params.setLocation(unmap(breakpoint.getLocation()));
@ -241,7 +257,7 @@ public class ChromeRDPDebugger implements JavaScriptDebugger, ChromeRDPExchangeC
@Override public void received(JsonNode node) throws IOException { @Override public void received(JsonNode node) throws IOException {
SetBreakpointResponse response = mapper.reader(SetBreakpointResponse.class).readValue(node); SetBreakpointResponse response = mapper.reader(SetBreakpointResponse.class).readValue(node);
breakpoint.chromeId = response.getBreakpointId(); breakpoint.chromeId = response.getBreakpointId();
for (JavaScriptDebuggerListener listener : listeners) { for (JavaScriptDebuggerListener listener : getListeners()) {
listener.breakpointChanged(breakpoint); listener.breakpointChanged(breakpoint);
} }
} }

View File

@ -52,6 +52,15 @@ public class ChromeRDPDebuggerEndpoint implements ChromeRDPExchange {
} }
} }
@Override
public void disconnect() {
try {
session.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
@OnMessage @OnMessage
public void receive(String message) throws IOException { public void receive(String message) throws IOException {
for (ChromeRDPExchangeListener listener : listeners) { for (ChromeRDPExchangeListener listener : listeners) {

View File

@ -7,6 +7,8 @@ package org.teavm.chromerdp;
public interface ChromeRDPExchange { public interface ChromeRDPExchange {
void send(String message); void send(String message);
void disconnect();
void addListener(ChromeRDPExchangeListener listener); void addListener(ChromeRDPExchangeListener listener);
void removeListener(ChromeRDPExchangeListener listener); void removeListener(ChromeRDPExchangeListener listener);

View File

@ -48,6 +48,6 @@ public class RDPBreakpoint implements JavaScriptBreakpoint {
@Override @Override
public boolean isValid() { public boolean isValid() {
return chromeId != null; return chromeId != null && debugger != null && debugger.isAttached();
} }
} }

View File

@ -24,7 +24,7 @@ import java.util.List;
*/ */
public class Breakpoint { public class Breakpoint {
private Debugger debugger; private Debugger debugger;
List<JavaScriptBreakpoint> jsBreakpoints = new ArrayList<>(); volatile List<JavaScriptBreakpoint> jsBreakpoints = new ArrayList<>();
private SourceLocation location; private SourceLocation location;
boolean valid; boolean valid;

View File

@ -16,6 +16,10 @@
package org.teavm.debugging; package org.teavm.debugging;
import java.util.*; import java.util.*;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.LinkedBlockingQueue;
import org.teavm.model.MethodReference; import org.teavm.model.MethodReference;
/** /**
@ -25,16 +29,18 @@ import org.teavm.model.MethodReference;
// TODO: variable name handling // TODO: variable name handling
// TODO: class fields handling // TODO: class fields handling
public class Debugger { public class Debugger {
private List<DebuggerListener> listeners = new ArrayList<>(); private static final Object dummyObject = new Object();
private ConcurrentMap<DebuggerListener, Object> listeners = new ConcurrentHashMap<>();
private JavaScriptDebugger javaScriptDebugger; private JavaScriptDebugger javaScriptDebugger;
private DebugInformationProvider debugInformationProvider; private DebugInformationProvider debugInformationProvider;
private List<JavaScriptBreakpoint> temporaryJsBreakpoints = new ArrayList<>(); private BlockingQueue<JavaScriptBreakpoint> temporaryBreakpoints = new LinkedBlockingQueue<>();
private Map<String, DebugInformation> debugInformationMap = new HashMap<>(); private ConcurrentMap<String, DebugInformation> debugInformationMap = new ConcurrentHashMap<>();
private Map<String, List<DebugInformation>> debugInformationFileMap = new HashMap<>(); private ConcurrentMap<String, ConcurrentMap<DebugInformation, Object>> debugInformationFileMap =
private Map<DebugInformation, String> scriptMap = new HashMap<>(); new ConcurrentHashMap<>();
Map<JavaScriptBreakpoint, Breakpoint> breakpointMap = new HashMap<>(); private ConcurrentMap<DebugInformation, String> scriptMap = new ConcurrentHashMap<>();
Set<Breakpoint> breakpoints = new HashSet<>(); ConcurrentMap<JavaScriptBreakpoint, Breakpoint> breakpointMap = new ConcurrentHashMap<>();
private CallFrame[] callStack; ConcurrentMap<Breakpoint, Object> breakpoints = new ConcurrentHashMap<>();
private volatile CallFrame[] callStack;
public Debugger(JavaScriptDebugger javaScriptDebugger, DebugInformationProvider debugInformationProvider) { public Debugger(JavaScriptDebugger javaScriptDebugger, DebugInformationProvider debugInformationProvider) {
this.javaScriptDebugger = javaScriptDebugger; this.javaScriptDebugger = javaScriptDebugger;
@ -43,36 +49,36 @@ public class Debugger {
} }
public void addListener(DebuggerListener listener) { public void addListener(DebuggerListener listener) {
listeners.add(listener); listeners.put(listener, dummyObject);
} }
public void removeListener(DebuggerListener listener) { public void removeListener(DebuggerListener listener) {
listeners.remove(listener); listeners.remove(listener);
} }
public void suspend() { public synchronized void suspend() {
javaScriptDebugger.suspend(); javaScriptDebugger.suspend();
} }
public void resume() { public synchronized void resume() {
javaScriptDebugger.resume(); javaScriptDebugger.resume();
} }
public void stepInto() { public synchronized void stepInto() {
javaScriptDebugger.stepInto(); javaScriptDebugger.stepInto();
} }
public void stepOut() { public synchronized void stepOut() {
javaScriptDebugger.stepOut(); javaScriptDebugger.stepOut();
} }
public void stepOver() { public synchronized void stepOver() {
javaScriptDebugger.stepOver(); javaScriptDebugger.stepOver();
} }
private List<DebugInformation> debugInformationBySource(String sourceFile) { private List<DebugInformation> debugInformationBySource(String sourceFile) {
List<DebugInformation> list = debugInformationFileMap.get(sourceFile); Map<DebugInformation, Object> list = debugInformationFileMap.get(sourceFile);
return list != null ? list : Collections.<DebugInformation>emptyList(); return list != null ? new ArrayList<>(list.keySet()) : Collections.<DebugInformation>emptyList();
} }
public void continueToLocation(SourceLocation location) { public void continueToLocation(SourceLocation location) {
@ -90,7 +96,7 @@ public class Debugger {
location.getLine(), location.getColumn()); location.getLine(), location.getColumn());
JavaScriptBreakpoint jsBreakpoint = javaScriptDebugger.createBreakpoint(jsLocation); JavaScriptBreakpoint jsBreakpoint = javaScriptDebugger.createBreakpoint(jsLocation);
if (jsBreakpoint != null) { if (jsBreakpoint != null) {
temporaryJsBreakpoints.add(jsBreakpoint); temporaryBreakpoints.add(jsBreakpoint);
} }
} }
} }
@ -107,14 +113,14 @@ public class Debugger {
public Breakpoint createBreakpoint(SourceLocation location) { public Breakpoint createBreakpoint(SourceLocation location) {
Breakpoint breakpoint = new Breakpoint(this, location); Breakpoint breakpoint = new Breakpoint(this, location);
breakpoints.add(breakpoint); breakpoints.put(breakpoint, dummyObject);
updateInternalBreakpoints(breakpoint); updateInternalBreakpoints(breakpoint);
updateBreakpointStatus(breakpoint, false); updateBreakpointStatus(breakpoint, false);
return breakpoint; return breakpoint;
} }
public Set<Breakpoint> getBreakpoints() { public Set<Breakpoint> getBreakpoints() {
return new HashSet<>(breakpoints); return new HashSet<>(breakpoints.keySet());
} }
void updateInternalBreakpoints(Breakpoint breakpoint) { void updateInternalBreakpoints(Breakpoint breakpoint) {
@ -122,7 +128,7 @@ public class Debugger {
breakpointMap.remove(jsBreakpoint); breakpointMap.remove(jsBreakpoint);
jsBreakpoint.destroy(); jsBreakpoint.destroy();
} }
breakpoint.jsBreakpoints.clear(); List<JavaScriptBreakpoint> jsBreakpoints = new ArrayList<>();
SourceLocation location = breakpoint.getLocation(); SourceLocation location = breakpoint.getLocation();
for (DebugInformation debugInformation : debugInformationBySource(location.getFileName())) { for (DebugInformation debugInformation : debugInformationBySource(location.getFileName())) {
Collection<GeneratedLocation> locations = debugInformation.getGeneratedLocations(location); Collection<GeneratedLocation> locations = debugInformation.getGeneratedLocations(location);
@ -130,10 +136,15 @@ public class Debugger {
JavaScriptLocation jsLocation = new JavaScriptLocation(scriptMap.get(debugInformation), JavaScriptLocation jsLocation = new JavaScriptLocation(scriptMap.get(debugInformation),
genLocation.getLine(), genLocation.getColumn()); genLocation.getLine(), genLocation.getColumn());
JavaScriptBreakpoint jsBreakpoint = javaScriptDebugger.createBreakpoint(jsLocation); JavaScriptBreakpoint jsBreakpoint = javaScriptDebugger.createBreakpoint(jsLocation);
breakpoint.jsBreakpoints.add(jsBreakpoint); jsBreakpoints.add(jsBreakpoint);
breakpointMap.put(jsBreakpoint, breakpoint); breakpointMap.put(jsBreakpoint, breakpoint);
} }
} }
breakpoint.jsBreakpoints = jsBreakpoints;
}
private DebuggerListener[] getListeners() {
return listeners.keySet().toArray(new DebuggerListener[0]);
} }
void updateBreakpointStatus(Breakpoint breakpoint, boolean fireEvent) { void updateBreakpointStatus(Breakpoint breakpoint, boolean fireEvent) {
@ -146,7 +157,7 @@ public class Debugger {
if (breakpoint.valid != valid) { if (breakpoint.valid != valid) {
breakpoint.valid = valid; breakpoint.valid = valid;
if (fireEvent) { if (fireEvent) {
for (DebuggerListener listener : listeners) { for (DebuggerListener listener : getListeners()) {
listener.breakpointStatusChanged(breakpoint); listener.breakpointStatusChanged(breakpoint);
} }
} }
@ -192,17 +203,23 @@ public class Debugger {
if (debugInfo == null) { if (debugInfo == null) {
return; return;
} }
debugInformationMap.put(name, debugInfo); if (debugInformationMap.putIfAbsent(name, debugInfo) != null) {
return;
}
for (String sourceFile : debugInfo.getCoveredSourceFiles()) { for (String sourceFile : debugInfo.getCoveredSourceFiles()) {
List<DebugInformation> list = debugInformationFileMap.get(sourceFile); ConcurrentMap<DebugInformation, Object> list = debugInformationFileMap.get(sourceFile);
if (list == null) { if (list == null) {
list = new ArrayList<>(); list = new ConcurrentHashMap<>();
debugInformationFileMap.put(sourceFile, list); ConcurrentMap<DebugInformation, Object> existing = debugInformationFileMap.putIfAbsent(
sourceFile, list);
if (existing != null) {
list = existing;
}
} }
list.add(debugInfo); list.put(debugInfo, dummyObject);
} }
scriptMap.put(debugInfo, name); scriptMap.put(debugInfo, name);
for (Breakpoint breakpoint : breakpoints) { for (Breakpoint breakpoint : breakpoints.keySet()) {
updateInternalBreakpoints(breakpoint); updateInternalBreakpoints(breakpoint);
updateBreakpointStatus(breakpoint, true); updateBreakpointStatus(breakpoint, true);
} }
@ -212,40 +229,45 @@ public class Debugger {
return javaScriptDebugger.isAttached(); return javaScriptDebugger.isAttached();
} }
public void detach() {
javaScriptDebugger.detach();
}
void destroyBreakpoint(Breakpoint breakpoint) { void destroyBreakpoint(Breakpoint breakpoint) {
for (JavaScriptBreakpoint jsBreakpoint : breakpoint.jsBreakpoints) { for (JavaScriptBreakpoint jsBreakpoint : breakpoint.jsBreakpoints) {
jsBreakpoint.destroy(); jsBreakpoint.destroy();
breakpointMap.remove(jsBreakpoint); breakpointMap.remove(jsBreakpoint);
} }
breakpoint.jsBreakpoints.clear(); breakpoint.jsBreakpoints = new ArrayList<>();
breakpoints.remove(this); breakpoints.remove(this);
} }
private void fireResumed() { private void fireResumed() {
for (JavaScriptBreakpoint jsBreakpoint : temporaryJsBreakpoints) { List<JavaScriptBreakpoint> termporaryBreakpoints = new ArrayList<>();
this.temporaryBreakpoints.drainTo(termporaryBreakpoints);
for (JavaScriptBreakpoint jsBreakpoint : temporaryBreakpoints) {
jsBreakpoint.destroy(); jsBreakpoint.destroy();
} }
temporaryJsBreakpoints.clear(); for (DebuggerListener listener : getListeners()) {
for (DebuggerListener listener : listeners) {
listener.resumed(); listener.resumed();
} }
} }
private void fireAttached() { private void fireAttached() {
for (Breakpoint breakpoint : breakpoints) { for (Breakpoint breakpoint : breakpoints.keySet()) {
updateInternalBreakpoints(breakpoint); updateInternalBreakpoints(breakpoint);
updateBreakpointStatus(breakpoint, false); updateBreakpointStatus(breakpoint, false);
} }
for (DebuggerListener listener : listeners) { for (DebuggerListener listener : getListeners()) {
listener.attached(); listener.attached();
} }
} }
private void fireDetached() { private void fireDetached() {
for (Breakpoint breakpoint : breakpoints) { for (Breakpoint breakpoint : breakpoints.keySet()) {
updateBreakpointStatus(breakpoint, false); updateBreakpointStatus(breakpoint, false);
} }
for (DebuggerListener listener : listeners) { for (DebuggerListener listener : getListeners()) {
listener.detached(); listener.detached();
} }
} }
@ -266,7 +288,7 @@ public class Debugger {
@Override @Override
public void paused() { public void paused() {
callStack = null; callStack = null;
for (DebuggerListener listener : listeners) { for (DebuggerListener listener : getListeners()) {
listener.paused(); listener.paused();
} }
} }

View File

@ -40,6 +40,8 @@ public interface JavaScriptDebugger {
boolean isAttached(); boolean isAttached();
void detach();
JavaScriptCallFrame[] getCallStack(); JavaScriptCallFrame[] getCallStack();
JavaScriptBreakpoint createBreakpoint(JavaScriptLocation location); JavaScriptBreakpoint createBreakpoint(JavaScriptLocation location);

View File

@ -14,6 +14,7 @@ import org.teavm.chromerdp.ChromeRDPServer;
import org.teavm.debugging.Breakpoint; import org.teavm.debugging.Breakpoint;
import org.teavm.debugging.Debugger; import org.teavm.debugging.Debugger;
import org.teavm.debugging.DebuggerListener; import org.teavm.debugging.DebuggerListener;
import org.teavm.debugging.JavaScriptDebugger;
/** /**
* *
@ -23,6 +24,7 @@ import org.teavm.debugging.DebuggerListener;
public class TeaVMDebugTarget implements IDebugTarget, IStep { public class TeaVMDebugTarget implements IDebugTarget, IStep {
ILaunch launch; ILaunch launch;
Debugger teavmDebugger; Debugger teavmDebugger;
JavaScriptDebugger jsDebugger;
private ChromeRDPServer server; private ChromeRDPServer server;
private boolean terminated; private boolean terminated;
private TeaVMDebugProcess process; private TeaVMDebugProcess process;
@ -90,6 +92,7 @@ public class TeaVMDebugTarget implements IDebugTarget, IStep {
terminated = true; terminated = true;
server.stop(); server.stop();
fireEvent(new DebugEvent(this, DebugEvent.TERMINATE)); fireEvent(new DebugEvent(this, DebugEvent.TERMINATE));
fireEvent(new DebugEvent(thread, DebugEvent.TERMINATE));
} }
@Override @Override
@ -187,6 +190,7 @@ public class TeaVMDebugTarget implements IDebugTarget, IStep {
@Override @Override
public void disconnect() throws DebugException { public void disconnect() throws DebugException {
teavmDebugger.detach();
} }
@Override @Override

View File

@ -1,16 +1,13 @@
package org.teavm.eclipse.debugger; package org.teavm.eclipse.debugger;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.debug.core.ILaunch; import org.eclipse.debug.core.ILaunch;
import org.eclipse.debug.core.ILaunchConfiguration; import org.eclipse.debug.core.ILaunchConfiguration;
import org.eclipse.debug.core.ILaunchManager; import org.eclipse.debug.core.ILaunchManager;
import org.eclipse.debug.core.model.ILaunchConfigurationDelegate; import org.eclipse.debug.core.model.ILaunchConfigurationDelegate;
import org.eclipse.ui.PlatformUI; import org.teavm.chromerdp.ChromeRDPDebugger;
import org.teavm.chromerdp.*; import org.teavm.chromerdp.ChromeRDPServer;
import org.teavm.debugging.Debugger; import org.teavm.debugging.Debugger;
import org.teavm.debugging.URLDebugInformationProvider; import org.teavm.debugging.URLDebugInformationProvider;
@ -29,64 +26,15 @@ public class TeaVMLaunchConfigurationDelegate implements ILaunchConfigurationDel
final ChromeRDPServer server = new ChromeRDPServer(); final ChromeRDPServer server = new ChromeRDPServer();
server.setPort(port); server.setPort(port);
ChromeRDPDebugger jsDebugger = new ChromeRDPDebugger(); ChromeRDPDebugger jsDebugger = new ChromeRDPDebugger();
server.setExchangeConsumer(new SynchronousMessageExchange(jsDebugger)); server.setExchangeConsumer(jsDebugger);
Debugger debugger = new Debugger(jsDebugger, new URLDebugInformationProvider("")); Debugger debugger = new Debugger(jsDebugger, new URLDebugInformationProvider(""));
new Thread() { new Thread() {
@Override public void run() { @Override public void run() {
server.start(); server.start();
} }
}.start(); }.start();
launch.addDebugTarget(new TeaVMDebugTarget(launch, debugger, server)); TeaVMDebugTarget target = new TeaVMDebugTarget(launch, debugger, server);
} launch.addDebugTarget(target);
launch.addProcess(target.getProcess());
private static class SynchronousMessageExchange implements ChromeRDPExchangeConsumer,
ChromeRDPExchange {
private List<ChromeRDPExchangeListener> listeners = new ArrayList<>();
private ChromeRDPDebugger debugger;
private ChromeRDPExchange exchange;
public SynchronousMessageExchange(ChromeRDPDebugger debugger) {
this.debugger = debugger;
}
@Override
public void setExchange(ChromeRDPExchange exchange) {
this.exchange = exchange;
debugger.setExchange(this);
exchange.addListener(new ChromeRDPExchangeListener() {
@Override public void received(final String message) throws IOException {
postToUIThread(message);
}
});
}
private void postToUIThread(final String message) {
PlatformUI.getWorkbench().getDisplay().asyncExec(new Runnable() {
@Override public void run() {
try {
for (ChromeRDPExchangeListener listener : listeners) {
listener.received(message);
}
} catch (IOException e) {
// TODO: add logging
}
}
});
}
@Override
public void send(String message) {
exchange.send(message);
}
@Override
public void addListener(ChromeRDPExchangeListener listener) {
listeners.add(listener);
}
@Override
public void removeListener(ChromeRDPExchangeListener listener) {
listeners.remove(listener);
}
} }
} }

View File

@ -74,7 +74,7 @@ public class TeaVMStackFrame implements IStackFrame {
@Override @Override
public boolean canResume() { public boolean canResume() {
return false; return thread.getTopStackFrame() == this;
} }
@Override @Override

View File

@ -29,11 +29,13 @@ public class TeaVMThread implements IThread {
@Override @Override
public void resumed() { public void resumed() {
updateStackTrace(); updateStackTrace();
fireEvent(new DebugEvent(TeaVMThread.this, DebugEvent.RESUME));
} }
@Override @Override
public void paused() { public void paused() {
updateStackTrace(); updateStackTrace();
fireEvent(new DebugEvent(TeaVMThread.this, DebugEvent.SUSPEND));
} }
@Override @Override
@ -70,16 +72,17 @@ public class TeaVMThread implements IThread {
@Override @Override
public boolean canTerminate() { public boolean canTerminate() {
return false; return true;
} }
@Override @Override
public boolean isTerminated() { public boolean isTerminated() {
return false; return debugTarget.isTerminated();
} }
@Override @Override
public void terminate() throws DebugException { public void terminate() throws DebugException {
debugTarget.terminate();
} }
@SuppressWarnings("rawtypes") @SuppressWarnings("rawtypes")
@ -190,6 +193,6 @@ public class TeaVMThread implements IThread {
@Override @Override
public boolean hasStackFrames() throws DebugException { public boolean hasStackFrames() throws DebugException {
return true; return stackTrace != null;
} }
} }