diff --git a/core/src/main/java/org/teavm/debugging/Debugger.java b/core/src/main/java/org/teavm/debugging/Debugger.java index 4df730210..db30396e3 100644 --- a/core/src/main/java/org/teavm/debugging/Debugger.java +++ b/core/src/main/java/org/teavm/debugging/Debugger.java @@ -432,10 +432,14 @@ public class Debugger { } @Override - public void paused() { + public void paused(JavaScriptBreakpoint breakpoint) { callStack = null; + Breakpoint javaBreakpoint = null; + if (breakpoint != null && !temporaryBreakpoints.contains(breakpoint)) { + javaBreakpoint = breakpointMap.get(breakpoint); + } for (DebuggerListener listener : getListeners()) { - listener.paused(); + listener.paused(javaBreakpoint); } } diff --git a/core/src/main/java/org/teavm/debugging/DebuggerListener.java b/core/src/main/java/org/teavm/debugging/DebuggerListener.java index 3de207bf8..d62f2d960 100644 --- a/core/src/main/java/org/teavm/debugging/DebuggerListener.java +++ b/core/src/main/java/org/teavm/debugging/DebuggerListener.java @@ -18,7 +18,7 @@ package org.teavm.debugging; public interface DebuggerListener { void resumed(); - void paused(); + void paused(Breakpoint breakpoint); void breakpointStatusChanged(Breakpoint breakpoint); diff --git a/core/src/main/java/org/teavm/debugging/javascript/JavaScriptDebuggerListener.java b/core/src/main/java/org/teavm/debugging/javascript/JavaScriptDebuggerListener.java index d221abe5b..b5a79f039 100644 --- a/core/src/main/java/org/teavm/debugging/javascript/JavaScriptDebuggerListener.java +++ b/core/src/main/java/org/teavm/debugging/javascript/JavaScriptDebuggerListener.java @@ -16,7 +16,7 @@ package org.teavm.debugging.javascript; public interface JavaScriptDebuggerListener { - void paused(); + void paused(JavaScriptBreakpoint breakpoint); void resumed(); diff --git a/tools/chrome-rdp/src/main/java/org/teavm/chromerdp/ChromeRDPDebugger.java b/tools/chrome-rdp/src/main/java/org/teavm/chromerdp/ChromeRDPDebugger.java index a3e8123b5..7fca146a5 100644 --- a/tools/chrome-rdp/src/main/java/org/teavm/chromerdp/ChromeRDPDebugger.java +++ b/tools/chrome-rdp/src/main/java/org/teavm/chromerdp/ChromeRDPDebugger.java @@ -64,6 +64,7 @@ public class ChromeRDPDebugger implements JavaScriptDebugger, ChromeRDPExchangeC private ConcurrentMap listeners = new ConcurrentHashMap<>(); private ConcurrentMap breakpointLocationMap = new ConcurrentHashMap<>(); private ConcurrentMap breakpoints = new ConcurrentHashMap<>(); + private ConcurrentMap breakpointsByChromeId = new ConcurrentHashMap<>(); private volatile RDPCallFrame[] callStack = new RDPCallFrame[0]; private ConcurrentMap scripts = new ConcurrentHashMap<>(); private ConcurrentMap scriptIds = new ConcurrentHashMap<>(); @@ -106,7 +107,7 @@ public class ChromeRDPDebugger implements JavaScriptDebugger, ChromeRDPExchangeC } } - private ChromeRDPExchangeListener exchangeListener = messageText -> receiveMessage(messageText); + private ChromeRDPExchangeListener exchangeListener = this::receiveMessage; private void receiveMessage(final String messageText) { new Thread(() -> { @@ -160,8 +161,14 @@ public class ChromeRDPDebugger implements JavaScriptDebugger, ChromeRDPExchangeC callStack[i] = map(callFrameDTOs[i]); } this.callStack = callStack; + + RDPBreakpoint breakpoint = null; + if (params.getHitBreakpoints() != null && !params.getHitBreakpoints().isEmpty()) { + breakpoint = breakpointsByChromeId.get(params.getHitBreakpoints().get(0)); + } + for (JavaScriptDebuggerListener listener : getListeners()) { - listener.paused(); + listener.paused(breakpoint); } } @@ -316,6 +323,7 @@ public class ChromeRDPDebugger implements JavaScriptDebugger, ChromeRDPExchangeC breakpointLocationMap.remove(breakpoint.getLocation()); breakpoints.remove(breakpoint); if (breakpoint.chromeId != null) { + breakpointsByChromeId.remove(breakpoint.chromeId); if (logger.isInfoEnabled()) { logger.info("Removing breakpoint at {}", breakpoint.getLocation()); } @@ -333,13 +341,7 @@ public class ChromeRDPDebugger implements JavaScriptDebugger, ChromeRDPExchangeC } } - void fireScriptAdded(String script) { - for (JavaScriptDebuggerListener listener : getListeners()) { - listener.scriptAdded(script); - } - } - - void updateBreakpoint(final RDPBreakpoint breakpoint) { + private void updateBreakpoint(final RDPBreakpoint breakpoint) { if (exchange == null || breakpoint.chromeId != null) { return; } @@ -353,9 +355,15 @@ public class ChromeRDPDebugger implements JavaScriptDebugger, ChromeRDPExchangeC logger.info("Setting breakpoint at {}, message id is ", breakpoint.getLocation(), message.getId()); } setResponseHandler(message.getId(), (node, out) -> { + if (breakpoint.chromeId != null) { + breakpointsByChromeId.remove(breakpoint.chromeId); + } if (node != null) { SetBreakpointResponse response = mapper.reader(SetBreakpointResponse.class).readValue(node); breakpoint.chromeId = response.getBreakpointId(); + if (breakpoint.chromeId != null) { + breakpointsByChromeId.put(breakpoint.chromeId, breakpoint); + } } else { if (logger.isWarnEnabled()) { logger.warn("Error setting breakpoint at {}, message id is {}", @@ -468,10 +476,10 @@ public class ChromeRDPDebugger implements JavaScriptDebugger, ChromeRDPExchangeC } } - private static class RepresentationWrapper { + static class RepresentationWrapper { String repr; - public RepresentationWrapper(String repr) { + RepresentationWrapper(String repr) { super(); this.repr = repr; } @@ -523,7 +531,7 @@ public class ChromeRDPDebugger implements JavaScriptDebugger, ChromeRDPExchangeC } } - RDPCallFrame map(CallFrameDTO dto) { + private RDPCallFrame map(CallFrameDTO dto) { String scopeId = null; RDPValue thisObject = null; RDPValue closure = null; @@ -546,11 +554,11 @@ public class ChromeRDPDebugger implements JavaScriptDebugger, ChromeRDPExchangeC thisObject, closure); } - JavaScriptLocation map(LocationDTO dto) { + private JavaScriptLocation map(LocationDTO dto) { return new JavaScriptLocation(scripts.get(dto.getScriptId()), dto.getLineNumber(), dto.getColumnNumber()); } - LocationDTO unmap(JavaScriptLocation location) { + private LocationDTO unmap(JavaScriptLocation location) { LocationDTO dto = new LocationDTO(); dto.setScriptId(scriptIds.get(location.getScript())); dto.setLineNumber(location.getLine()); diff --git a/tools/chrome-rdp/src/main/java/org/teavm/chromerdp/ChromeRDPRunner.java b/tools/chrome-rdp/src/main/java/org/teavm/chromerdp/ChromeRDPRunner.java index de15c0ac4..07815bc69 100644 --- a/tools/chrome-rdp/src/main/java/org/teavm/chromerdp/ChromeRDPRunner.java +++ b/tools/chrome-rdp/src/main/java/org/teavm/chromerdp/ChromeRDPRunner.java @@ -67,12 +67,15 @@ public final class ChromeRDPRunner { } @Override - public void paused() { + public void paused(Breakpoint breakpoint) { CallFrame[] stack = debugger.getCallStack(); if (stack.length > 0) { System.out.println(); System.out.println("Suspended at " + stack[0].getLocation()); } + if (breakpoint != null) { + System.out.println("Breakpoint #" + breakpointIds.get(breakpoint) + " hit"); + } currentFrame = 0; if (suspendListener != null) { suspendListener.run(); diff --git a/tools/chrome-rdp/src/main/java/org/teavm/chromerdp/messages/SuspendedNotification.java b/tools/chrome-rdp/src/main/java/org/teavm/chromerdp/messages/SuspendedNotification.java index 5a59a9fd9..0f562f41e 100644 --- a/tools/chrome-rdp/src/main/java/org/teavm/chromerdp/messages/SuspendedNotification.java +++ b/tools/chrome-rdp/src/main/java/org/teavm/chromerdp/messages/SuspendedNotification.java @@ -15,6 +15,7 @@ */ package org.teavm.chromerdp.messages; +import java.util.List; import org.codehaus.jackson.JsonNode; import org.codehaus.jackson.annotate.JsonIgnoreProperties; import org.teavm.chromerdp.data.CallFrameDTO; @@ -24,6 +25,7 @@ public class SuspendedNotification { private CallFrameDTO[] callFrames; private String reason; private JsonNode data; + private List hitBreakpoints; public CallFrameDTO[] getCallFrames() { return callFrames; @@ -48,4 +50,12 @@ public class SuspendedNotification { public void setData(JsonNode data) { this.data = data; } + + public List getHitBreakpoints() { + return hitBreakpoints; + } + + public void setHitBreakpoints(List hitBreakpoints) { + this.hitBreakpoints = hitBreakpoints; + } } diff --git a/tools/idea/plugin/src/main/java/org/teavm/idea/debug/TeaVMDebugProcess.java b/tools/idea/plugin/src/main/java/org/teavm/idea/debug/TeaVMDebugProcess.java index 4407ff06e..f3e0e50e4 100644 --- a/tools/idea/plugin/src/main/java/org/teavm/idea/debug/TeaVMDebugProcess.java +++ b/tools/idea/plugin/src/main/java/org/teavm/idea/debug/TeaVMDebugProcess.java @@ -22,11 +22,16 @@ import com.intellij.openapi.util.Key; import com.intellij.xdebugger.XDebugProcess; import com.intellij.xdebugger.XDebugSession; import com.intellij.xdebugger.XSourcePosition; +import com.intellij.xdebugger.breakpoints.XBreakpoint; import com.intellij.xdebugger.breakpoints.XBreakpointHandler; import com.intellij.xdebugger.evaluation.XDebuggerEditorsProvider; +import com.intellij.xdebugger.frame.XSuspendContext; import java.util.ArrayList; import java.util.List; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.teavm.chromerdp.ChromeRDPDebugger; import org.teavm.chromerdp.ChromeRDPServer; import org.teavm.debugging.Breakpoint; @@ -41,6 +46,7 @@ public class TeaVMDebugProcess extends XDebugProcess { private final List> breakpointHandlers = new ArrayList<>(); private final int port; private ChromeRDPServer debugServer; + ConcurrentMap> breakpointMap = new ConcurrentHashMap<>(); public TeaVMDebugProcess(@NotNull XDebugSession session, int port) { super(session); @@ -52,8 +58,14 @@ public class TeaVMDebugProcess extends XDebugProcess { } @Override - public void paused() { - handlePaused(); + public void paused(Breakpoint breakpoint) { + XBreakpoint xBreakpoint = breakpoint != null ? breakpointMap.get(breakpoint) : null; + if (xBreakpoint != null) { + getSession().breakpointReached(xBreakpoint, null, + new TeaVMSuspendContext(innerDebugger, getSession().getProject())); + } else { + handlePaused(); + } } @Override @@ -70,14 +82,14 @@ public class TeaVMDebugProcess extends XDebugProcess { }); breakpointHandlers.add(new TeaVMLineBreakpointHandler<>(JavaLineBreakpointType.class, session.getProject(), - innerDebugger)); + innerDebugger, this)); ExtensionPoint> breakpointProvider = Extensions.getArea( session.getProject()).getExtensionPoint("org.teavm.extensions.breakpointProvider"); if (breakpointProvider != null) { for (TeaVMBreakpointProvider provider : breakpointProvider.getExtensions()) { breakpointHandlers.add(new TeaVMLineBreakpointHandler<>(provider.getBreakpointType(), - session.getProject(), innerDebugger)); + session.getProject(), innerDebugger, this)); } } } @@ -100,22 +112,22 @@ public class TeaVMDebugProcess extends XDebugProcess { } @Override - public void startStepOver() { + public void startStepOver(@Nullable XSuspendContext context) { innerDebugger.stepOver(); } @Override - public void startStepInto() { + public void startStepInto(@Nullable XSuspendContext context) { innerDebugger.stepInto(); } @Override - public void startStepOut() { + public void startStepOut(@Nullable XSuspendContext context) { innerDebugger.stepOut(); } @Override - public void resume() { + public void resume(@Nullable XSuspendContext context) { innerDebugger.resume(); } @@ -125,7 +137,7 @@ public class TeaVMDebugProcess extends XDebugProcess { } @Override - public void runToPosition(@NotNull XSourcePosition position) { + public void runToPosition(@NotNull XSourcePosition position, @Nullable XSuspendContext context) { innerDebugger.continueToLocation(position.getFile().getPath(), position.getLine()); } diff --git a/tools/idea/plugin/src/main/java/org/teavm/idea/debug/TeaVMLineBreakpointHandler.java b/tools/idea/plugin/src/main/java/org/teavm/idea/debug/TeaVMLineBreakpointHandler.java index a2a5b7f42..3aab58474 100644 --- a/tools/idea/plugin/src/main/java/org/teavm/idea/debug/TeaVMLineBreakpointHandler.java +++ b/tools/idea/plugin/src/main/java/org/teavm/idea/debug/TeaVMLineBreakpointHandler.java @@ -36,14 +36,16 @@ public class TeaVMLineBreakpointHandler> extends XB private Debugger innerDebugger; private VirtualFileManager vfs; private ProjectFileIndex fileIndex; + private TeaVMDebugProcess debugProcess; @SuppressWarnings("unchecked") public TeaVMLineBreakpointHandler(Class> breakpointType, - Project project, Debugger innerDebugger) { + Project project, Debugger innerDebugger, TeaVMDebugProcess debugProcess) { super(breakpointType); this.innerDebugger = innerDebugger; vfs = VirtualFileManager.getInstance(); fileIndex = ProjectRootManager.getInstance(project).getFileIndex(); + this.debugProcess = debugProcess; } @Override @@ -63,6 +65,7 @@ public class TeaVMLineBreakpointHandler> extends XB Breakpoint innerBreakpoint = innerDebugger.createBreakpoint(path, breakpoint.getLine() + 1); breakpoint.putUserData(TeaVMDebugProcess.INNER_BREAKPOINT_KEY, innerBreakpoint); + debugProcess.breakpointMap.put(innerBreakpoint, breakpoint); } @Nullable @@ -86,6 +89,7 @@ public class TeaVMLineBreakpointHandler> extends XB if (innerBreakpoint != null) { breakpoint.putUserData(TeaVMDebugProcess.INNER_BREAKPOINT_KEY, null); innerBreakpoint.destroy(); + debugProcess.breakpointMap.remove(innerBreakpoint); } } }