Properly report breakpoint hit event

This commit is contained in:
Alexey Andreev 2017-07-04 06:37:17 +03:00
parent b5fcd22a39
commit 1581345e17
8 changed files with 70 additions and 29 deletions

View File

@ -432,10 +432,14 @@ public class Debugger {
} }
@Override @Override
public void paused() { public void paused(JavaScriptBreakpoint breakpoint) {
callStack = null; callStack = null;
Breakpoint javaBreakpoint = null;
if (breakpoint != null && !temporaryBreakpoints.contains(breakpoint)) {
javaBreakpoint = breakpointMap.get(breakpoint);
}
for (DebuggerListener listener : getListeners()) { for (DebuggerListener listener : getListeners()) {
listener.paused(); listener.paused(javaBreakpoint);
} }
} }

View File

@ -18,7 +18,7 @@ package org.teavm.debugging;
public interface DebuggerListener { public interface DebuggerListener {
void resumed(); void resumed();
void paused(); void paused(Breakpoint breakpoint);
void breakpointStatusChanged(Breakpoint breakpoint); void breakpointStatusChanged(Breakpoint breakpoint);

View File

@ -16,7 +16,7 @@
package org.teavm.debugging.javascript; package org.teavm.debugging.javascript;
public interface JavaScriptDebuggerListener { public interface JavaScriptDebuggerListener {
void paused(); void paused(JavaScriptBreakpoint breakpoint);
void resumed(); void resumed();

View File

@ -64,6 +64,7 @@ public class ChromeRDPDebugger implements JavaScriptDebugger, ChromeRDPExchangeC
private ConcurrentMap<JavaScriptDebuggerListener, Object> listeners = new ConcurrentHashMap<>(); private ConcurrentMap<JavaScriptDebuggerListener, Object> listeners = new ConcurrentHashMap<>();
private ConcurrentMap<JavaScriptLocation, RDPBreakpoint> breakpointLocationMap = new ConcurrentHashMap<>(); private ConcurrentMap<JavaScriptLocation, RDPBreakpoint> breakpointLocationMap = new ConcurrentHashMap<>();
private ConcurrentMap<RDPBreakpoint, Object> breakpoints = new ConcurrentHashMap<>(); private ConcurrentMap<RDPBreakpoint, Object> breakpoints = new ConcurrentHashMap<>();
private ConcurrentMap<String, RDPBreakpoint> breakpointsByChromeId = new ConcurrentHashMap<>();
private volatile RDPCallFrame[] callStack = new RDPCallFrame[0]; private volatile RDPCallFrame[] callStack = new RDPCallFrame[0];
private ConcurrentMap<String, String> scripts = new ConcurrentHashMap<>(); private ConcurrentMap<String, String> scripts = new ConcurrentHashMap<>();
private ConcurrentMap<String, String> scriptIds = new ConcurrentHashMap<>(); private ConcurrentMap<String, String> 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) { private void receiveMessage(final String messageText) {
new Thread(() -> { new Thread(() -> {
@ -160,8 +161,14 @@ public class ChromeRDPDebugger implements JavaScriptDebugger, ChromeRDPExchangeC
callStack[i] = map(callFrameDTOs[i]); callStack[i] = map(callFrameDTOs[i]);
} }
this.callStack = callStack; this.callStack = callStack;
RDPBreakpoint breakpoint = null;
if (params.getHitBreakpoints() != null && !params.getHitBreakpoints().isEmpty()) {
breakpoint = breakpointsByChromeId.get(params.getHitBreakpoints().get(0));
}
for (JavaScriptDebuggerListener listener : getListeners()) { for (JavaScriptDebuggerListener listener : getListeners()) {
listener.paused(); listener.paused(breakpoint);
} }
} }
@ -316,6 +323,7 @@ public class ChromeRDPDebugger implements JavaScriptDebugger, ChromeRDPExchangeC
breakpointLocationMap.remove(breakpoint.getLocation()); breakpointLocationMap.remove(breakpoint.getLocation());
breakpoints.remove(breakpoint); breakpoints.remove(breakpoint);
if (breakpoint.chromeId != null) { if (breakpoint.chromeId != null) {
breakpointsByChromeId.remove(breakpoint.chromeId);
if (logger.isInfoEnabled()) { if (logger.isInfoEnabled()) {
logger.info("Removing breakpoint at {}", breakpoint.getLocation()); logger.info("Removing breakpoint at {}", breakpoint.getLocation());
} }
@ -333,13 +341,7 @@ public class ChromeRDPDebugger implements JavaScriptDebugger, ChromeRDPExchangeC
} }
} }
void fireScriptAdded(String script) { private void updateBreakpoint(final RDPBreakpoint breakpoint) {
for (JavaScriptDebuggerListener listener : getListeners()) {
listener.scriptAdded(script);
}
}
void updateBreakpoint(final RDPBreakpoint breakpoint) {
if (exchange == null || breakpoint.chromeId != null) { if (exchange == null || breakpoint.chromeId != null) {
return; return;
} }
@ -353,9 +355,15 @@ public class ChromeRDPDebugger implements JavaScriptDebugger, ChromeRDPExchangeC
logger.info("Setting breakpoint at {}, message id is ", breakpoint.getLocation(), message.getId()); logger.info("Setting breakpoint at {}, message id is ", breakpoint.getLocation(), message.getId());
} }
setResponseHandler(message.getId(), (node, out) -> { setResponseHandler(message.getId(), (node, out) -> {
if (breakpoint.chromeId != null) {
breakpointsByChromeId.remove(breakpoint.chromeId);
}
if (node != null) { if (node != null) {
SetBreakpointResponse response = mapper.reader(SetBreakpointResponse.class).readValue(node); SetBreakpointResponse response = mapper.reader(SetBreakpointResponse.class).readValue(node);
breakpoint.chromeId = response.getBreakpointId(); breakpoint.chromeId = response.getBreakpointId();
if (breakpoint.chromeId != null) {
breakpointsByChromeId.put(breakpoint.chromeId, breakpoint);
}
} else { } else {
if (logger.isWarnEnabled()) { if (logger.isWarnEnabled()) {
logger.warn("Error setting breakpoint at {}, message id is {}", 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; String repr;
public RepresentationWrapper(String repr) { RepresentationWrapper(String repr) {
super(); super();
this.repr = repr; 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; String scopeId = null;
RDPValue thisObject = null; RDPValue thisObject = null;
RDPValue closure = null; RDPValue closure = null;
@ -546,11 +554,11 @@ public class ChromeRDPDebugger implements JavaScriptDebugger, ChromeRDPExchangeC
thisObject, closure); thisObject, closure);
} }
JavaScriptLocation map(LocationDTO dto) { private JavaScriptLocation map(LocationDTO dto) {
return new JavaScriptLocation(scripts.get(dto.getScriptId()), dto.getLineNumber(), dto.getColumnNumber()); return new JavaScriptLocation(scripts.get(dto.getScriptId()), dto.getLineNumber(), dto.getColumnNumber());
} }
LocationDTO unmap(JavaScriptLocation location) { private LocationDTO unmap(JavaScriptLocation location) {
LocationDTO dto = new LocationDTO(); LocationDTO dto = new LocationDTO();
dto.setScriptId(scriptIds.get(location.getScript())); dto.setScriptId(scriptIds.get(location.getScript()));
dto.setLineNumber(location.getLine()); dto.setLineNumber(location.getLine());

View File

@ -67,12 +67,15 @@ public final class ChromeRDPRunner {
} }
@Override @Override
public void paused() { public void paused(Breakpoint breakpoint) {
CallFrame[] stack = debugger.getCallStack(); CallFrame[] stack = debugger.getCallStack();
if (stack.length > 0) { if (stack.length > 0) {
System.out.println(); System.out.println();
System.out.println("Suspended at " + stack[0].getLocation()); System.out.println("Suspended at " + stack[0].getLocation());
} }
if (breakpoint != null) {
System.out.println("Breakpoint #" + breakpointIds.get(breakpoint) + " hit");
}
currentFrame = 0; currentFrame = 0;
if (suspendListener != null) { if (suspendListener != null) {
suspendListener.run(); suspendListener.run();

View File

@ -15,6 +15,7 @@
*/ */
package org.teavm.chromerdp.messages; package org.teavm.chromerdp.messages;
import java.util.List;
import org.codehaus.jackson.JsonNode; import org.codehaus.jackson.JsonNode;
import org.codehaus.jackson.annotate.JsonIgnoreProperties; import org.codehaus.jackson.annotate.JsonIgnoreProperties;
import org.teavm.chromerdp.data.CallFrameDTO; import org.teavm.chromerdp.data.CallFrameDTO;
@ -24,6 +25,7 @@ public class SuspendedNotification {
private CallFrameDTO[] callFrames; private CallFrameDTO[] callFrames;
private String reason; private String reason;
private JsonNode data; private JsonNode data;
private List<String> hitBreakpoints;
public CallFrameDTO[] getCallFrames() { public CallFrameDTO[] getCallFrames() {
return callFrames; return callFrames;
@ -48,4 +50,12 @@ public class SuspendedNotification {
public void setData(JsonNode data) { public void setData(JsonNode data) {
this.data = data; this.data = data;
} }
public List<String> getHitBreakpoints() {
return hitBreakpoints;
}
public void setHitBreakpoints(List<String> hitBreakpoints) {
this.hitBreakpoints = hitBreakpoints;
}
} }

View File

@ -22,11 +22,16 @@ import com.intellij.openapi.util.Key;
import com.intellij.xdebugger.XDebugProcess; import com.intellij.xdebugger.XDebugProcess;
import com.intellij.xdebugger.XDebugSession; import com.intellij.xdebugger.XDebugSession;
import com.intellij.xdebugger.XSourcePosition; import com.intellij.xdebugger.XSourcePosition;
import com.intellij.xdebugger.breakpoints.XBreakpoint;
import com.intellij.xdebugger.breakpoints.XBreakpointHandler; import com.intellij.xdebugger.breakpoints.XBreakpointHandler;
import com.intellij.xdebugger.evaluation.XDebuggerEditorsProvider; import com.intellij.xdebugger.evaluation.XDebuggerEditorsProvider;
import com.intellij.xdebugger.frame.XSuspendContext;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.teavm.chromerdp.ChromeRDPDebugger; import org.teavm.chromerdp.ChromeRDPDebugger;
import org.teavm.chromerdp.ChromeRDPServer; import org.teavm.chromerdp.ChromeRDPServer;
import org.teavm.debugging.Breakpoint; import org.teavm.debugging.Breakpoint;
@ -41,6 +46,7 @@ public class TeaVMDebugProcess extends XDebugProcess {
private final List<TeaVMLineBreakpointHandler<?>> breakpointHandlers = new ArrayList<>(); private final List<TeaVMLineBreakpointHandler<?>> breakpointHandlers = new ArrayList<>();
private final int port; private final int port;
private ChromeRDPServer debugServer; private ChromeRDPServer debugServer;
ConcurrentMap<Breakpoint, XBreakpoint<?>> breakpointMap = new ConcurrentHashMap<>();
public TeaVMDebugProcess(@NotNull XDebugSession session, int port) { public TeaVMDebugProcess(@NotNull XDebugSession session, int port) {
super(session); super(session);
@ -52,8 +58,14 @@ public class TeaVMDebugProcess extends XDebugProcess {
} }
@Override @Override
public void paused() { public void paused(Breakpoint breakpoint) {
handlePaused(); XBreakpoint<?> xBreakpoint = breakpoint != null ? breakpointMap.get(breakpoint) : null;
if (xBreakpoint != null) {
getSession().breakpointReached(xBreakpoint, null,
new TeaVMSuspendContext(innerDebugger, getSession().getProject()));
} else {
handlePaused();
}
} }
@Override @Override
@ -70,14 +82,14 @@ public class TeaVMDebugProcess extends XDebugProcess {
}); });
breakpointHandlers.add(new TeaVMLineBreakpointHandler<>(JavaLineBreakpointType.class, session.getProject(), breakpointHandlers.add(new TeaVMLineBreakpointHandler<>(JavaLineBreakpointType.class, session.getProject(),
innerDebugger)); innerDebugger, this));
ExtensionPoint<TeaVMBreakpointProvider<?>> breakpointProvider = Extensions.getArea( ExtensionPoint<TeaVMBreakpointProvider<?>> breakpointProvider = Extensions.getArea(
session.getProject()).getExtensionPoint("org.teavm.extensions.breakpointProvider"); session.getProject()).getExtensionPoint("org.teavm.extensions.breakpointProvider");
if (breakpointProvider != null) { if (breakpointProvider != null) {
for (TeaVMBreakpointProvider<?> provider : breakpointProvider.getExtensions()) { for (TeaVMBreakpointProvider<?> provider : breakpointProvider.getExtensions()) {
breakpointHandlers.add(new TeaVMLineBreakpointHandler<>(provider.getBreakpointType(), breakpointHandlers.add(new TeaVMLineBreakpointHandler<>(provider.getBreakpointType(),
session.getProject(), innerDebugger)); session.getProject(), innerDebugger, this));
} }
} }
} }
@ -100,22 +112,22 @@ public class TeaVMDebugProcess extends XDebugProcess {
} }
@Override @Override
public void startStepOver() { public void startStepOver(@Nullable XSuspendContext context) {
innerDebugger.stepOver(); innerDebugger.stepOver();
} }
@Override @Override
public void startStepInto() { public void startStepInto(@Nullable XSuspendContext context) {
innerDebugger.stepInto(); innerDebugger.stepInto();
} }
@Override @Override
public void startStepOut() { public void startStepOut(@Nullable XSuspendContext context) {
innerDebugger.stepOut(); innerDebugger.stepOut();
} }
@Override @Override
public void resume() { public void resume(@Nullable XSuspendContext context) {
innerDebugger.resume(); innerDebugger.resume();
} }
@ -125,7 +137,7 @@ public class TeaVMDebugProcess extends XDebugProcess {
} }
@Override @Override
public void runToPosition(@NotNull XSourcePosition position) { public void runToPosition(@NotNull XSourcePosition position, @Nullable XSuspendContext context) {
innerDebugger.continueToLocation(position.getFile().getPath(), position.getLine()); innerDebugger.continueToLocation(position.getFile().getPath(), position.getLine());
} }

View File

@ -36,14 +36,16 @@ public class TeaVMLineBreakpointHandler<B extends XLineBreakpoint<?>> extends XB
private Debugger innerDebugger; private Debugger innerDebugger;
private VirtualFileManager vfs; private VirtualFileManager vfs;
private ProjectFileIndex fileIndex; private ProjectFileIndex fileIndex;
private TeaVMDebugProcess debugProcess;
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public TeaVMLineBreakpointHandler(Class<? extends XBreakpointType<B, ?>> breakpointType, public TeaVMLineBreakpointHandler(Class<? extends XBreakpointType<B, ?>> breakpointType,
Project project, Debugger innerDebugger) { Project project, Debugger innerDebugger, TeaVMDebugProcess debugProcess) {
super(breakpointType); super(breakpointType);
this.innerDebugger = innerDebugger; this.innerDebugger = innerDebugger;
vfs = VirtualFileManager.getInstance(); vfs = VirtualFileManager.getInstance();
fileIndex = ProjectRootManager.getInstance(project).getFileIndex(); fileIndex = ProjectRootManager.getInstance(project).getFileIndex();
this.debugProcess = debugProcess;
} }
@Override @Override
@ -63,6 +65,7 @@ public class TeaVMLineBreakpointHandler<B extends XLineBreakpoint<?>> extends XB
Breakpoint innerBreakpoint = innerDebugger.createBreakpoint(path, breakpoint.getLine() + 1); Breakpoint innerBreakpoint = innerDebugger.createBreakpoint(path, breakpoint.getLine() + 1);
breakpoint.putUserData(TeaVMDebugProcess.INNER_BREAKPOINT_KEY, innerBreakpoint); breakpoint.putUserData(TeaVMDebugProcess.INNER_BREAKPOINT_KEY, innerBreakpoint);
debugProcess.breakpointMap.put(innerBreakpoint, breakpoint);
} }
@Nullable @Nullable
@ -86,6 +89,7 @@ public class TeaVMLineBreakpointHandler<B extends XLineBreakpoint<?>> extends XB
if (innerBreakpoint != null) { if (innerBreakpoint != null) {
breakpoint.putUserData(TeaVMDebugProcess.INNER_BREAKPOINT_KEY, null); breakpoint.putUserData(TeaVMDebugProcess.INNER_BREAKPOINT_KEY, null);
innerBreakpoint.destroy(); innerBreakpoint.destroy();
debugProcess.breakpointMap.remove(innerBreakpoint);
} }
} }
} }