Skip to content

Commit 075fbff

Browse files
authored
PR1 of conditional BP (#153)
* Add basic impl of conditional BP * remove an empty line. * change a better var name
1 parent 0156e64 commit 075fbff

File tree

3 files changed

+67
-14
lines changed

3 files changed

+67
-14
lines changed

com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/ConfigurationDoneRequestHandler.java

Lines changed: 1 addition & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@
2323
import com.microsoft.java.debug.core.adapter.ErrorCode;
2424
import com.microsoft.java.debug.core.adapter.IDebugAdapterContext;
2525
import com.microsoft.java.debug.core.adapter.IDebugRequestHandler;
26-
import com.microsoft.java.debug.core.adapter.IEvaluationProvider;
2726
import com.microsoft.java.debug.core.protocol.Events;
2827
import com.microsoft.java.debug.core.protocol.Messages.Response;
2928
import com.microsoft.java.debug.core.protocol.Requests.Arguments;
@@ -32,7 +31,6 @@
3231
import com.sun.jdi.event.BreakpointEvent;
3332
import com.sun.jdi.event.Event;
3433
import com.sun.jdi.event.ExceptionEvent;
35-
import com.sun.jdi.event.StepEvent;
3634
import com.sun.jdi.event.ThreadDeathEvent;
3735
import com.sun.jdi.event.ThreadStartEvent;
3836
import com.sun.jdi.event.VMDeathEvent;
@@ -93,18 +91,7 @@ private void handleDebugEvent(DebugEvent debugEvent, IDebugSession debugSession,
9391
Events.ThreadEvent threadDeathEvent = new Events.ThreadEvent("exited", deathThread.uniqueID());
9492
context.getProtocolServer().sendEvent(threadDeathEvent);
9593
} else if (event instanceof BreakpointEvent) {
96-
if (debugEvent.eventSet.size() > 1 && debugEvent.eventSet.stream().anyMatch(t -> t instanceof StepEvent)) {
97-
// The StepEvent and BreakpointEvent are grouped in the same event set only if they occurs at the same location and in the same thread.
98-
// In order to avoid two duplicated StoppedEvents, the debugger will skip the BreakpointEvent.
99-
} else {
100-
ThreadReference bpThread = ((BreakpointEvent) event).thread();
101-
IEvaluationProvider engine = context.getProvider(IEvaluationProvider.class);
102-
if (engine.isInEvaluation(bpThread)) {
103-
return;
104-
}
105-
context.getProtocolServer().sendEvent(new Events.StoppedEvent("breakpoint", bpThread.uniqueID()));
106-
debugEvent.shouldResume = false;
107-
}
94+
// ignore since SetBreakpointsRequestHandler has already handled
10895
} else if (event instanceof ExceptionEvent) {
10996
ThreadReference thread = ((ExceptionEvent) event).thread();
11097
context.getProtocolServer().sendEvent(new Events.StoppedEvent("exception", thread.uniqueID()));

com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/InitializeRequestHandler.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ public CompletableFuture<Messages.Response> handle(Requests.Command command, Req
4747
Types.Capabilities caps = new Types.Capabilities();
4848
caps.supportsConfigurationDoneRequest = true;
4949
caps.supportsHitConditionalBreakpoints = true;
50+
caps.supportsConditionalBreakpoints = true;
5051
caps.supportsSetVariable = true;
5152
caps.supportTerminateDebuggee = true;
5253
Types.ExceptionBreakpointFilter[] exceptionFilters = {

com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/SetBreakpointsRequestHandler.java

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
import java.util.Arrays;
1616
import java.util.List;
1717
import java.util.concurrent.CompletableFuture;
18+
import java.util.concurrent.ExecutionException;
1819
import java.util.logging.Level;
1920
import java.util.logging.Logger;
2021

@@ -24,12 +25,14 @@
2425
import com.microsoft.java.debug.core.Configuration;
2526
import com.microsoft.java.debug.core.DebugException;
2627
import com.microsoft.java.debug.core.IBreakpoint;
28+
import com.microsoft.java.debug.core.IDebugSession;
2729
import com.microsoft.java.debug.core.adapter.AdapterUtils;
2830
import com.microsoft.java.debug.core.adapter.BreakpointManager;
2931
import com.microsoft.java.debug.core.adapter.ErrorCode;
3032
import com.microsoft.java.debug.core.adapter.HotCodeReplaceEvent.EventType;
3133
import com.microsoft.java.debug.core.adapter.IDebugAdapterContext;
3234
import com.microsoft.java.debug.core.adapter.IDebugRequestHandler;
35+
import com.microsoft.java.debug.core.adapter.IEvaluationProvider;
3336
import com.microsoft.java.debug.core.adapter.IHotCodeReplaceProvider;
3437
import com.microsoft.java.debug.core.adapter.ISourceLookUpProvider;
3538
import com.microsoft.java.debug.core.protocol.Events;
@@ -39,13 +42,21 @@
3942
import com.microsoft.java.debug.core.protocol.Requests.SetBreakpointArguments;
4043
import com.microsoft.java.debug.core.protocol.Responses;
4144
import com.microsoft.java.debug.core.protocol.Types;
45+
import com.sun.jdi.PrimitiveValue;
46+
import com.sun.jdi.ThreadReference;
47+
import com.sun.jdi.Value;
48+
import com.sun.jdi.event.BreakpointEvent;
49+
import com.sun.jdi.event.Event;
50+
import com.sun.jdi.event.StepEvent;
4251

4352
public class SetBreakpointsRequestHandler implements IDebugRequestHandler {
4453

4554
private static final Logger logger = Logger.getLogger(Configuration.LOGGER_NAME);
4655

4756
private BreakpointManager manager = new BreakpointManager();
4857

58+
private boolean registered = false;
59+
4960
@Override
5061
public List<Command> getTargetCommands() {
5162
return Arrays.asList(Command.SETBREAKPOINTS);
@@ -73,6 +84,11 @@ public CompletableFuture<Response> handle(Command command, Arguments arguments,
7384
return AdapterUtils.createAsyncErrorResponse(response, ErrorCode.EMPTY_DEBUG_SESSION, "Empty debug session.");
7485
}
7586

87+
if (!registered) {
88+
registered = true;
89+
registerBreakpointHandler(context);
90+
}
91+
7692
SetBreakpointArguments bpArguments = (SetBreakpointArguments) arguments;
7793
String clientPath = bpArguments.source.path;
7894
if (AdapterUtils.isWindows()) {
@@ -130,6 +146,55 @@ public CompletableFuture<Response> handle(Command command, Arguments arguments,
130146
}
131147
}
132148

149+
private void registerBreakpointHandler(IDebugAdapterContext context) {
150+
IDebugSession debugSession = context.getDebugSession();
151+
if (debugSession != null) {
152+
debugSession.getEventHub().events().subscribe(debugEvent -> {
153+
if (!(debugEvent.event instanceof BreakpointEvent)) {
154+
return;
155+
}
156+
Event event = debugEvent.event;
157+
if (debugEvent.eventSet.size() > 1 && debugEvent.eventSet.stream().anyMatch(t -> t instanceof StepEvent)) {
158+
// The StepEvent and BreakpointEvent are grouped in the same event set only if they occurs at the same location and in the same thread.
159+
// In order to avoid two duplicated StoppedEvents, the debugger will skip the BreakpointEvent.
160+
} else {
161+
ThreadReference bpThread = ((BreakpointEvent) event).thread();
162+
IEvaluationProvider engine = context.getProvider(IEvaluationProvider.class);
163+
if (engine.isInEvaluation(bpThread)) {
164+
return;
165+
}
166+
167+
// find the breakpoint related to this breakpoint event
168+
IBreakpoint conditionalBP = Arrays.asList(manager.getBreakpoints()).stream().filter(bp -> StringUtils.isNotBlank(bp.getCondition())
169+
&& bp.requests().contains(((BreakpointEvent) event).request())
170+
).findFirst().get();
171+
if (conditionalBP != null) {
172+
CompletableFuture.runAsync(() -> {
173+
Value value;
174+
try {
175+
value = engine.evaluate(conditionalBP.getCondition(), bpThread, 0).get();
176+
if (value instanceof PrimitiveValue) {
177+
boolean evaluationResultAsBool = ((PrimitiveValue) value).booleanValue();
178+
if (!evaluationResultAsBool) {
179+
debugEvent.eventSet.resume();
180+
return;
181+
}
182+
}
183+
} catch (InterruptedException | ExecutionException e) {
184+
// TODO: notify user about evaluation failure
185+
}
186+
context.getProtocolServer().sendEvent(new Events.StoppedEvent("breakpoint", bpThread.uniqueID()));
187+
188+
});
189+
} else {
190+
context.getProtocolServer().sendEvent(new Events.StoppedEvent("breakpoint", bpThread.uniqueID()));
191+
}
192+
debugEvent.shouldResume = false;
193+
}
194+
});
195+
}
196+
}
197+
133198
private Types.Breakpoint convertDebuggerBreakpointToClient(IBreakpoint breakpoint, IDebugAdapterContext context) {
134199
int id = (int) breakpoint.getProperty("id");
135200
boolean verified = breakpoint.getProperty("verified") != null && (boolean) breakpoint.getProperty("verified");

0 commit comments

Comments
 (0)