From c490e2f9f873302f434dc98600588f7c69a9cd54 Mon Sep 17 00:00:00 2001 From: konsoletyper Date: Thu, 31 Jul 2014 21:38:32 +0400 Subject: [PATCH] Improvement of debugger plugin. Debugger itself became multithreaded --- .../teavm/chromerdp/ChromeRDPDebugger.java | 56 +++++++---- .../chromerdp/ChromeRDPDebuggerEndpoint.java | 9 ++ .../teavm/chromerdp/ChromeRDPExchange.java | 2 + .../org/teavm/chromerdp/RDPBreakpoint.java | 2 +- .../java/org/teavm/debugging/Breakpoint.java | 2 +- .../java/org/teavm/debugging/Debugger.java | 96 ++++++++++++------- .../teavm/debugging/JavaScriptDebugger.java | 2 + .../eclipse/debugger/TeaVMDebugTarget.java | 4 + .../TeaVMLaunchConfigurationDelegate.java | 64 ++----------- .../eclipse/debugger/TeaVMStackFrame.java | 2 +- .../teavm/eclipse/debugger/TeaVMThread.java | 9 +- 11 files changed, 127 insertions(+), 121 deletions(-) diff --git a/teavm-chrome-rdp/src/main/java/org/teavm/chromerdp/ChromeRDPDebugger.java b/teavm-chrome-rdp/src/main/java/org/teavm/chromerdp/ChromeRDPDebugger.java index de52d754f..38980bd54 100644 --- a/teavm-chrome-rdp/src/main/java/org/teavm/chromerdp/ChromeRDPDebugger.java +++ b/teavm-chrome-rdp/src/main/java/org/teavm/chromerdp/ChromeRDPDebugger.java @@ -2,6 +2,9 @@ package org.teavm.chromerdp; import java.io.IOException; 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.map.ObjectMapper; import org.teavm.chromerdp.data.CallFrameDTO; @@ -16,16 +19,21 @@ import org.teavm.debugging.*; * @author Alexey Andreev */ public class ChromeRDPDebugger implements JavaScriptDebugger, ChromeRDPExchangeConsumer { + private static final Object dummy = new Object(); private ChromeRDPExchange exchange; - private List listeners = new ArrayList<>(); - private Set breakpoints = new HashSet<>(); - private RDPCallFrame[] callStack = new RDPCallFrame[0]; - private Map scripts = new HashMap<>(); - private Map scriptIds = new HashMap<>(); + private ConcurrentMap listeners = new ConcurrentHashMap<>(); + private ConcurrentMap breakpoints = new ConcurrentHashMap<>(); + private volatile RDPCallFrame[] callStack = new RDPCallFrame[0]; + private ConcurrentMap scripts = new ConcurrentHashMap<>(); + private ConcurrentMap scriptIds = new ConcurrentHashMap<>(); private boolean suspended = false; private ObjectMapper mapper = new ObjectMapper(); - private Map responseHandlers = new HashMap<>(); - private int messageIdGenerator; + private ConcurrentMap responseHandlers = new ConcurrentHashMap<>(); + private AtomicInteger messageIdGenerator = new AtomicInteger(); + + private List getListeners() { + return new ArrayList<>(listeners.keySet()); + } @Override public void setExchange(ChromeRDPExchange exchange) { @@ -37,15 +45,15 @@ public class ChromeRDPDebugger implements JavaScriptDebugger, ChromeRDPExchangeC } this.exchange = exchange; if (exchange != null) { - for (RDPBreakpoint breakpoint : breakpoints) { + for (RDPBreakpoint breakpoint : breakpoints.keySet().toArray(new RDPBreakpoint[0])) { updateBreakpoint(breakpoint); } - for (JavaScriptDebuggerListener listener : listeners) { + for (JavaScriptDebuggerListener listener : getListeners()) { listener.attached(); } } else { suspended = false; - for (JavaScriptDebuggerListener listener : listeners) { + for (JavaScriptDebuggerListener listener : getListeners()) { listener.detached(); } } @@ -86,7 +94,7 @@ public class ChromeRDPDebugger implements JavaScriptDebugger, ChromeRDPExchangeC callStack[i] = map(callFrameDTOs[i]); } this.callStack = callStack; - for (JavaScriptDebuggerListener listener : listeners) { + for (JavaScriptDebuggerListener listener : getListeners()) { listener.paused(); } } @@ -94,18 +102,17 @@ public class ChromeRDPDebugger implements JavaScriptDebugger, ChromeRDPExchangeC private synchronized void fireResumed() { suspended = false; callStack = null; - for (JavaScriptDebuggerListener listener : listeners) { + for (JavaScriptDebuggerListener listener : getListeners()) { listener.resumed(); } } private synchronized void scriptParsed(ScriptParsedNotification params) { - if (scripts.containsKey(params.getScriptId())) { + if (scripts.putIfAbsent(params.getScriptId(), params.getUrl()) != null) { return; } - scripts.put(params.getScriptId(), params.getUrl()); scriptIds.put(params.getUrl(), params.getScriptId()); - for (JavaScriptDebuggerListener listener : listeners) { + for (JavaScriptDebuggerListener listener : getListeners()) { listener.scriptAdded(params.getUrl()); } } @@ -113,7 +120,7 @@ public class ChromeRDPDebugger implements JavaScriptDebugger, ChromeRDPExchangeC @Override public void addListener(JavaScriptDebuggerListener listener) { - listeners.add(listener); + listeners.put(listener, dummy); } @Override @@ -194,23 +201,32 @@ public class ChromeRDPDebugger implements JavaScriptDebugger, ChromeRDPExchangeC return exchange != null; } + @Override + public void detach() { + if (exchange != null) { + exchange.disconnect(); + } + } + @Override public JavaScriptCallFrame[] getCallStack() { if (exchange == null) { return null; } + JavaScriptCallFrame[] callStack = this.callStack; return callStack != null ? callStack.clone() : null; } @Override public JavaScriptBreakpoint createBreakpoint(JavaScriptLocation location) { RDPBreakpoint breakpoint = new RDPBreakpoint(this, location); - breakpoints.add(breakpoint); + breakpoints.put(breakpoint, dummy); updateBreakpoint(breakpoint); return breakpoint; } void destroyBreakpoint(RDPBreakpoint breakpoint) { + breakpoints.remove(breakpoint); if (breakpoint.chromeId != null) { Message message = new Message(); message.setMethod("Debugger.removeBreakpoint"); @@ -222,7 +238,7 @@ public class ChromeRDPDebugger implements JavaScriptDebugger, ChromeRDPExchangeC } void fireScriptAdded(String script) { - for (JavaScriptDebuggerListener listener : listeners) { + for (JavaScriptDebuggerListener listener : getListeners()) { listener.scriptAdded(script); } } @@ -232,7 +248,7 @@ public class ChromeRDPDebugger implements JavaScriptDebugger, ChromeRDPExchangeC return; } Message message = new Message(); - message.setId(++messageIdGenerator); + message.setId(messageIdGenerator.incrementAndGet()); message.setMethod("Debugger.setBreakpoint"); SetBreakpointCommand params = new SetBreakpointCommand(); params.setLocation(unmap(breakpoint.getLocation())); @@ -241,7 +257,7 @@ public class ChromeRDPDebugger implements JavaScriptDebugger, ChromeRDPExchangeC @Override public void received(JsonNode node) throws IOException { SetBreakpointResponse response = mapper.reader(SetBreakpointResponse.class).readValue(node); breakpoint.chromeId = response.getBreakpointId(); - for (JavaScriptDebuggerListener listener : listeners) { + for (JavaScriptDebuggerListener listener : getListeners()) { listener.breakpointChanged(breakpoint); } } diff --git a/teavm-chrome-rdp/src/main/java/org/teavm/chromerdp/ChromeRDPDebuggerEndpoint.java b/teavm-chrome-rdp/src/main/java/org/teavm/chromerdp/ChromeRDPDebuggerEndpoint.java index be6636877..bd43e0d2c 100644 --- a/teavm-chrome-rdp/src/main/java/org/teavm/chromerdp/ChromeRDPDebuggerEndpoint.java +++ b/teavm-chrome-rdp/src/main/java/org/teavm/chromerdp/ChromeRDPDebuggerEndpoint.java @@ -52,6 +52,15 @@ public class ChromeRDPDebuggerEndpoint implements ChromeRDPExchange { } } + @Override + public void disconnect() { + try { + session.close(); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + @OnMessage public void receive(String message) throws IOException { for (ChromeRDPExchangeListener listener : listeners) { diff --git a/teavm-chrome-rdp/src/main/java/org/teavm/chromerdp/ChromeRDPExchange.java b/teavm-chrome-rdp/src/main/java/org/teavm/chromerdp/ChromeRDPExchange.java index d3a8404bc..fe32f52ed 100644 --- a/teavm-chrome-rdp/src/main/java/org/teavm/chromerdp/ChromeRDPExchange.java +++ b/teavm-chrome-rdp/src/main/java/org/teavm/chromerdp/ChromeRDPExchange.java @@ -7,6 +7,8 @@ package org.teavm.chromerdp; public interface ChromeRDPExchange { void send(String message); + void disconnect(); + void addListener(ChromeRDPExchangeListener listener); void removeListener(ChromeRDPExchangeListener listener); diff --git a/teavm-chrome-rdp/src/main/java/org/teavm/chromerdp/RDPBreakpoint.java b/teavm-chrome-rdp/src/main/java/org/teavm/chromerdp/RDPBreakpoint.java index 1333992ee..08411fd65 100644 --- a/teavm-chrome-rdp/src/main/java/org/teavm/chromerdp/RDPBreakpoint.java +++ b/teavm-chrome-rdp/src/main/java/org/teavm/chromerdp/RDPBreakpoint.java @@ -48,6 +48,6 @@ public class RDPBreakpoint implements JavaScriptBreakpoint { @Override public boolean isValid() { - return chromeId != null; + return chromeId != null && debugger != null && debugger.isAttached(); } } diff --git a/teavm-core/src/main/java/org/teavm/debugging/Breakpoint.java b/teavm-core/src/main/java/org/teavm/debugging/Breakpoint.java index 649c3b211..baf995aa8 100644 --- a/teavm-core/src/main/java/org/teavm/debugging/Breakpoint.java +++ b/teavm-core/src/main/java/org/teavm/debugging/Breakpoint.java @@ -24,7 +24,7 @@ import java.util.List; */ public class Breakpoint { private Debugger debugger; - List jsBreakpoints = new ArrayList<>(); + volatile List jsBreakpoints = new ArrayList<>(); private SourceLocation location; boolean valid; diff --git a/teavm-core/src/main/java/org/teavm/debugging/Debugger.java b/teavm-core/src/main/java/org/teavm/debugging/Debugger.java index 5aac9ac0e..48dd77c78 100644 --- a/teavm-core/src/main/java/org/teavm/debugging/Debugger.java +++ b/teavm-core/src/main/java/org/teavm/debugging/Debugger.java @@ -16,6 +16,10 @@ package org.teavm.debugging; 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; /** @@ -25,16 +29,18 @@ import org.teavm.model.MethodReference; // TODO: variable name handling // TODO: class fields handling public class Debugger { - private List listeners = new ArrayList<>(); + private static final Object dummyObject = new Object(); + private ConcurrentMap listeners = new ConcurrentHashMap<>(); private JavaScriptDebugger javaScriptDebugger; private DebugInformationProvider debugInformationProvider; - private List temporaryJsBreakpoints = new ArrayList<>(); - private Map debugInformationMap = new HashMap<>(); - private Map> debugInformationFileMap = new HashMap<>(); - private Map scriptMap = new HashMap<>(); - Map breakpointMap = new HashMap<>(); - Set breakpoints = new HashSet<>(); - private CallFrame[] callStack; + private BlockingQueue temporaryBreakpoints = new LinkedBlockingQueue<>(); + private ConcurrentMap debugInformationMap = new ConcurrentHashMap<>(); + private ConcurrentMap> debugInformationFileMap = + new ConcurrentHashMap<>(); + private ConcurrentMap scriptMap = new ConcurrentHashMap<>(); + ConcurrentMap breakpointMap = new ConcurrentHashMap<>(); + ConcurrentMap breakpoints = new ConcurrentHashMap<>(); + private volatile CallFrame[] callStack; public Debugger(JavaScriptDebugger javaScriptDebugger, DebugInformationProvider debugInformationProvider) { this.javaScriptDebugger = javaScriptDebugger; @@ -43,36 +49,36 @@ public class Debugger { } public void addListener(DebuggerListener listener) { - listeners.add(listener); + listeners.put(listener, dummyObject); } public void removeListener(DebuggerListener listener) { listeners.remove(listener); } - public void suspend() { + public synchronized void suspend() { javaScriptDebugger.suspend(); } - public void resume() { + public synchronized void resume() { javaScriptDebugger.resume(); } - public void stepInto() { + public synchronized void stepInto() { javaScriptDebugger.stepInto(); } - public void stepOut() { + public synchronized void stepOut() { javaScriptDebugger.stepOut(); } - public void stepOver() { + public synchronized void stepOver() { javaScriptDebugger.stepOver(); } private List debugInformationBySource(String sourceFile) { - List list = debugInformationFileMap.get(sourceFile); - return list != null ? list : Collections.emptyList(); + Map list = debugInformationFileMap.get(sourceFile); + return list != null ? new ArrayList<>(list.keySet()) : Collections.emptyList(); } public void continueToLocation(SourceLocation location) { @@ -90,7 +96,7 @@ public class Debugger { location.getLine(), location.getColumn()); JavaScriptBreakpoint jsBreakpoint = javaScriptDebugger.createBreakpoint(jsLocation); if (jsBreakpoint != null) { - temporaryJsBreakpoints.add(jsBreakpoint); + temporaryBreakpoints.add(jsBreakpoint); } } } @@ -107,14 +113,14 @@ public class Debugger { public Breakpoint createBreakpoint(SourceLocation location) { Breakpoint breakpoint = new Breakpoint(this, location); - breakpoints.add(breakpoint); + breakpoints.put(breakpoint, dummyObject); updateInternalBreakpoints(breakpoint); updateBreakpointStatus(breakpoint, false); return breakpoint; } public Set getBreakpoints() { - return new HashSet<>(breakpoints); + return new HashSet<>(breakpoints.keySet()); } void updateInternalBreakpoints(Breakpoint breakpoint) { @@ -122,7 +128,7 @@ public class Debugger { breakpointMap.remove(jsBreakpoint); jsBreakpoint.destroy(); } - breakpoint.jsBreakpoints.clear(); + List jsBreakpoints = new ArrayList<>(); SourceLocation location = breakpoint.getLocation(); for (DebugInformation debugInformation : debugInformationBySource(location.getFileName())) { Collection locations = debugInformation.getGeneratedLocations(location); @@ -130,10 +136,15 @@ public class Debugger { JavaScriptLocation jsLocation = new JavaScriptLocation(scriptMap.get(debugInformation), genLocation.getLine(), genLocation.getColumn()); JavaScriptBreakpoint jsBreakpoint = javaScriptDebugger.createBreakpoint(jsLocation); - breakpoint.jsBreakpoints.add(jsBreakpoint); + jsBreakpoints.add(jsBreakpoint); breakpointMap.put(jsBreakpoint, breakpoint); } } + breakpoint.jsBreakpoints = jsBreakpoints; + } + + private DebuggerListener[] getListeners() { + return listeners.keySet().toArray(new DebuggerListener[0]); } void updateBreakpointStatus(Breakpoint breakpoint, boolean fireEvent) { @@ -146,7 +157,7 @@ public class Debugger { if (breakpoint.valid != valid) { breakpoint.valid = valid; if (fireEvent) { - for (DebuggerListener listener : listeners) { + for (DebuggerListener listener : getListeners()) { listener.breakpointStatusChanged(breakpoint); } } @@ -192,17 +203,23 @@ public class Debugger { if (debugInfo == null) { return; } - debugInformationMap.put(name, debugInfo); + if (debugInformationMap.putIfAbsent(name, debugInfo) != null) { + return; + } for (String sourceFile : debugInfo.getCoveredSourceFiles()) { - List list = debugInformationFileMap.get(sourceFile); + ConcurrentMap list = debugInformationFileMap.get(sourceFile); if (list == null) { - list = new ArrayList<>(); - debugInformationFileMap.put(sourceFile, list); + list = new ConcurrentHashMap<>(); + ConcurrentMap existing = debugInformationFileMap.putIfAbsent( + sourceFile, list); + if (existing != null) { + list = existing; + } } - list.add(debugInfo); + list.put(debugInfo, dummyObject); } scriptMap.put(debugInfo, name); - for (Breakpoint breakpoint : breakpoints) { + for (Breakpoint breakpoint : breakpoints.keySet()) { updateInternalBreakpoints(breakpoint); updateBreakpointStatus(breakpoint, true); } @@ -212,40 +229,45 @@ public class Debugger { return javaScriptDebugger.isAttached(); } + public void detach() { + javaScriptDebugger.detach(); + } + void destroyBreakpoint(Breakpoint breakpoint) { for (JavaScriptBreakpoint jsBreakpoint : breakpoint.jsBreakpoints) { jsBreakpoint.destroy(); breakpointMap.remove(jsBreakpoint); } - breakpoint.jsBreakpoints.clear(); + breakpoint.jsBreakpoints = new ArrayList<>(); breakpoints.remove(this); } private void fireResumed() { - for (JavaScriptBreakpoint jsBreakpoint : temporaryJsBreakpoints) { + List termporaryBreakpoints = new ArrayList<>(); + this.temporaryBreakpoints.drainTo(termporaryBreakpoints); + for (JavaScriptBreakpoint jsBreakpoint : temporaryBreakpoints) { jsBreakpoint.destroy(); } - temporaryJsBreakpoints.clear(); - for (DebuggerListener listener : listeners) { + for (DebuggerListener listener : getListeners()) { listener.resumed(); } } private void fireAttached() { - for (Breakpoint breakpoint : breakpoints) { + for (Breakpoint breakpoint : breakpoints.keySet()) { updateInternalBreakpoints(breakpoint); updateBreakpointStatus(breakpoint, false); } - for (DebuggerListener listener : listeners) { + for (DebuggerListener listener : getListeners()) { listener.attached(); } } private void fireDetached() { - for (Breakpoint breakpoint : breakpoints) { + for (Breakpoint breakpoint : breakpoints.keySet()) { updateBreakpointStatus(breakpoint, false); } - for (DebuggerListener listener : listeners) { + for (DebuggerListener listener : getListeners()) { listener.detached(); } } @@ -266,7 +288,7 @@ public class Debugger { @Override public void paused() { callStack = null; - for (DebuggerListener listener : listeners) { + for (DebuggerListener listener : getListeners()) { listener.paused(); } } diff --git a/teavm-core/src/main/java/org/teavm/debugging/JavaScriptDebugger.java b/teavm-core/src/main/java/org/teavm/debugging/JavaScriptDebugger.java index 42fcdec38..eba81e325 100644 --- a/teavm-core/src/main/java/org/teavm/debugging/JavaScriptDebugger.java +++ b/teavm-core/src/main/java/org/teavm/debugging/JavaScriptDebugger.java @@ -40,6 +40,8 @@ public interface JavaScriptDebugger { boolean isAttached(); + void detach(); + JavaScriptCallFrame[] getCallStack(); JavaScriptBreakpoint createBreakpoint(JavaScriptLocation location); diff --git a/teavm-eclipse-plugin/src/main/java/org/teavm/eclipse/debugger/TeaVMDebugTarget.java b/teavm-eclipse-plugin/src/main/java/org/teavm/eclipse/debugger/TeaVMDebugTarget.java index 70fc45088..7cdad83db 100644 --- a/teavm-eclipse-plugin/src/main/java/org/teavm/eclipse/debugger/TeaVMDebugTarget.java +++ b/teavm-eclipse-plugin/src/main/java/org/teavm/eclipse/debugger/TeaVMDebugTarget.java @@ -14,6 +14,7 @@ import org.teavm.chromerdp.ChromeRDPServer; import org.teavm.debugging.Breakpoint; import org.teavm.debugging.Debugger; 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 { ILaunch launch; Debugger teavmDebugger; + JavaScriptDebugger jsDebugger; private ChromeRDPServer server; private boolean terminated; private TeaVMDebugProcess process; @@ -90,6 +92,7 @@ public class TeaVMDebugTarget implements IDebugTarget, IStep { terminated = true; server.stop(); fireEvent(new DebugEvent(this, DebugEvent.TERMINATE)); + fireEvent(new DebugEvent(thread, DebugEvent.TERMINATE)); } @Override @@ -187,6 +190,7 @@ public class TeaVMDebugTarget implements IDebugTarget, IStep { @Override public void disconnect() throws DebugException { + teavmDebugger.detach(); } @Override diff --git a/teavm-eclipse-plugin/src/main/java/org/teavm/eclipse/debugger/TeaVMLaunchConfigurationDelegate.java b/teavm-eclipse-plugin/src/main/java/org/teavm/eclipse/debugger/TeaVMLaunchConfigurationDelegate.java index 30d34d0c0..4bdaca246 100644 --- a/teavm-eclipse-plugin/src/main/java/org/teavm/eclipse/debugger/TeaVMLaunchConfigurationDelegate.java +++ b/teavm-eclipse-plugin/src/main/java/org/teavm/eclipse/debugger/TeaVMLaunchConfigurationDelegate.java @@ -1,16 +1,13 @@ 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.IProgressMonitor; import org.eclipse.debug.core.ILaunch; import org.eclipse.debug.core.ILaunchConfiguration; import org.eclipse.debug.core.ILaunchManager; import org.eclipse.debug.core.model.ILaunchConfigurationDelegate; -import org.eclipse.ui.PlatformUI; -import org.teavm.chromerdp.*; +import org.teavm.chromerdp.ChromeRDPDebugger; +import org.teavm.chromerdp.ChromeRDPServer; import org.teavm.debugging.Debugger; import org.teavm.debugging.URLDebugInformationProvider; @@ -29,64 +26,15 @@ public class TeaVMLaunchConfigurationDelegate implements ILaunchConfigurationDel final ChromeRDPServer server = new ChromeRDPServer(); server.setPort(port); ChromeRDPDebugger jsDebugger = new ChromeRDPDebugger(); - server.setExchangeConsumer(new SynchronousMessageExchange(jsDebugger)); + server.setExchangeConsumer(jsDebugger); Debugger debugger = new Debugger(jsDebugger, new URLDebugInformationProvider("")); new Thread() { @Override public void run() { server.start(); } }.start(); - launch.addDebugTarget(new TeaVMDebugTarget(launch, debugger, server)); - } - - private static class SynchronousMessageExchange implements ChromeRDPExchangeConsumer, - ChromeRDPExchange { - private List 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); - } + TeaVMDebugTarget target = new TeaVMDebugTarget(launch, debugger, server); + launch.addDebugTarget(target); + launch.addProcess(target.getProcess()); } } diff --git a/teavm-eclipse-plugin/src/main/java/org/teavm/eclipse/debugger/TeaVMStackFrame.java b/teavm-eclipse-plugin/src/main/java/org/teavm/eclipse/debugger/TeaVMStackFrame.java index 31ec49953..0568a7dc5 100644 --- a/teavm-eclipse-plugin/src/main/java/org/teavm/eclipse/debugger/TeaVMStackFrame.java +++ b/teavm-eclipse-plugin/src/main/java/org/teavm/eclipse/debugger/TeaVMStackFrame.java @@ -74,7 +74,7 @@ public class TeaVMStackFrame implements IStackFrame { @Override public boolean canResume() { - return false; + return thread.getTopStackFrame() == this; } @Override diff --git a/teavm-eclipse-plugin/src/main/java/org/teavm/eclipse/debugger/TeaVMThread.java b/teavm-eclipse-plugin/src/main/java/org/teavm/eclipse/debugger/TeaVMThread.java index 3c53d4a75..6b966e170 100644 --- a/teavm-eclipse-plugin/src/main/java/org/teavm/eclipse/debugger/TeaVMThread.java +++ b/teavm-eclipse-plugin/src/main/java/org/teavm/eclipse/debugger/TeaVMThread.java @@ -29,11 +29,13 @@ public class TeaVMThread implements IThread { @Override public void resumed() { updateStackTrace(); + fireEvent(new DebugEvent(TeaVMThread.this, DebugEvent.RESUME)); } @Override public void paused() { updateStackTrace(); + fireEvent(new DebugEvent(TeaVMThread.this, DebugEvent.SUSPEND)); } @Override @@ -70,16 +72,17 @@ public class TeaVMThread implements IThread { @Override public boolean canTerminate() { - return false; + return true; } @Override public boolean isTerminated() { - return false; + return debugTarget.isTerminated(); } @Override public void terminate() throws DebugException { + debugTarget.terminate(); } @SuppressWarnings("rawtypes") @@ -190,6 +193,6 @@ public class TeaVMThread implements IThread { @Override public boolean hasStackFrames() throws DebugException { - return true; + return stackTrace != null; } }