-
Notifications
You must be signed in to change notification settings - Fork 204
PR1 of conditional BP #153
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -15,6 +15,7 @@ | |
| import java.util.Arrays; | ||
| import java.util.List; | ||
| import java.util.concurrent.CompletableFuture; | ||
| import java.util.concurrent.ExecutionException; | ||
| import java.util.logging.Level; | ||
| import java.util.logging.Logger; | ||
|
|
||
|
|
@@ -24,12 +25,14 @@ | |
| import com.microsoft.java.debug.core.Configuration; | ||
| import com.microsoft.java.debug.core.DebugException; | ||
| import com.microsoft.java.debug.core.IBreakpoint; | ||
| import com.microsoft.java.debug.core.IDebugSession; | ||
| import com.microsoft.java.debug.core.adapter.AdapterUtils; | ||
| import com.microsoft.java.debug.core.adapter.BreakpointManager; | ||
| import com.microsoft.java.debug.core.adapter.ErrorCode; | ||
| import com.microsoft.java.debug.core.adapter.HotCodeReplaceEvent.EventType; | ||
| import com.microsoft.java.debug.core.adapter.IDebugAdapterContext; | ||
| import com.microsoft.java.debug.core.adapter.IDebugRequestHandler; | ||
| import com.microsoft.java.debug.core.adapter.IEvaluationProvider; | ||
| import com.microsoft.java.debug.core.adapter.IHotCodeReplaceProvider; | ||
| import com.microsoft.java.debug.core.adapter.ISourceLookUpProvider; | ||
| import com.microsoft.java.debug.core.protocol.Events; | ||
|
|
@@ -39,13 +42,21 @@ | |
| import com.microsoft.java.debug.core.protocol.Requests.SetBreakpointArguments; | ||
| import com.microsoft.java.debug.core.protocol.Responses; | ||
| import com.microsoft.java.debug.core.protocol.Types; | ||
| import com.sun.jdi.PrimitiveValue; | ||
| import com.sun.jdi.ThreadReference; | ||
| import com.sun.jdi.Value; | ||
| import com.sun.jdi.event.BreakpointEvent; | ||
| import com.sun.jdi.event.Event; | ||
| import com.sun.jdi.event.StepEvent; | ||
|
|
||
| public class SetBreakpointsRequestHandler implements IDebugRequestHandler { | ||
|
|
||
| private static final Logger logger = Logger.getLogger(Configuration.LOGGER_NAME); | ||
|
|
||
| private BreakpointManager manager = new BreakpointManager(); | ||
|
|
||
| private boolean registered = false; | ||
|
|
||
| @Override | ||
| public List<Command> getTargetCommands() { | ||
| return Arrays.asList(Command.SETBREAKPOINTS); | ||
|
|
@@ -73,6 +84,11 @@ public CompletableFuture<Response> handle(Command command, Arguments arguments, | |
| return AdapterUtils.createAsyncErrorResponse(response, ErrorCode.EMPTY_DEBUG_SESSION, "Empty debug session."); | ||
| } | ||
|
|
||
| if (!registered) { | ||
| registered = true; | ||
| registerBreakpointHandler(context); | ||
| } | ||
|
|
||
| SetBreakpointArguments bpArguments = (SetBreakpointArguments) arguments; | ||
| String clientPath = bpArguments.source.path; | ||
| if (AdapterUtils.isWindows()) { | ||
|
|
@@ -130,6 +146,55 @@ public CompletableFuture<Response> handle(Command command, Arguments arguments, | |
| } | ||
| } | ||
|
|
||
| private void registerBreakpointHandler(IDebugAdapterContext context) { | ||
| IDebugSession debugSession = context.getDebugSession(); | ||
| if (debugSession != null) { | ||
| debugSession.getEventHub().events().subscribe(debugEvent -> { | ||
| if (!(debugEvent.event instanceof BreakpointEvent)) { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. use observable.filter to only process BreakpointEvent.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done in PR2 |
||
| return; | ||
| } | ||
| Event event = debugEvent.event; | ||
| if (debugEvent.eventSet.size() > 1 && debugEvent.eventSet.stream().anyMatch(t -> t instanceof StepEvent)) { | ||
| // The StepEvent and BreakpointEvent are grouped in the same event set only if they occurs at the same location and in the same thread. | ||
| // In order to avoid two duplicated StoppedEvents, the debugger will skip the BreakpointEvent. | ||
| } else { | ||
| ThreadReference bpThread = ((BreakpointEvent) event).thread(); | ||
| IEvaluationProvider engine = context.getProvider(IEvaluationProvider.class); | ||
| if (engine.isInEvaluation(bpThread)) { | ||
| return; | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If early return, what is the expected value of debugEvent.shouldResume?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. shouldResume is default true, that is expected. |
||
| } | ||
|
|
||
| // find the breakpoint related to this breakpoint event | ||
| IBreakpoint conditionalBP = Arrays.asList(manager.getBreakpoints()).stream().filter(bp -> StringUtils.isNotBlank(bp.getCondition()) | ||
| && bp.requests().contains(((BreakpointEvent) event).request()) | ||
| ).findFirst().get(); | ||
| if (conditionalBP != null) { | ||
| CompletableFuture.runAsync(() -> { | ||
| Value value; | ||
| try { | ||
| value = engine.evaluate(conditionalBP.getCondition(), bpThread, 0).get(); | ||
| if (value instanceof PrimitiveValue) { | ||
| boolean evaluationResultAsBool = ((PrimitiveValue) value).booleanValue(); | ||
| if (!evaluationResultAsBool) { | ||
| debugEvent.eventSet.resume(); | ||
| return; | ||
| } | ||
| } | ||
| } catch (InterruptedException | ExecutionException e) { | ||
| // TODO: notify user about evaluation failure | ||
| } | ||
| context.getProtocolServer().sendEvent(new Events.StoppedEvent("breakpoint", bpThread.uniqueID())); | ||
|
|
||
| }); | ||
| } else { | ||
| context.getProtocolServer().sendEvent(new Events.StoppedEvent("breakpoint", bpThread.uniqueID())); | ||
| } | ||
| debugEvent.shouldResume = false; | ||
| } | ||
| }); | ||
| } | ||
| } | ||
|
|
||
| private Types.Breakpoint convertDebuggerBreakpointToClient(IBreakpoint breakpoint, IDebugAdapterContext context) { | ||
| int id = (int) breakpoint.getProperty("id"); | ||
| boolean verified = breakpoint.getProperty("verified") != null && (boolean) breakpoint.getProperty("verified"); | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should synchronize the register behavior.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should register behavior happen on the initialization?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
on initialization, the debug session is not ready, always null in initialize method
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is a initialize member of IDebugRequestHandler to handle the initialization. This logic should be there.