From 247face213d9f24dec38ce947af9b458ef692eb3 Mon Sep 17 00:00:00 2001 From: Stan185 <57770977+Stan185@users.noreply.github.com> Date: Thu, 29 Jan 2026 16:27:18 +0100 Subject: [PATCH 1/3] Add suspend mode for source breakpoints --- .../microsoft/java/debug/core/Breakpoint.java | 54 +++---- .../java/debug/core/DebugSession.java | 74 +++++----- .../java/debug/core/IBreakpoint.java | 13 +- .../java/debug/core/IDebugSession.java | 20 +-- .../java/debug/core/adapter/AdapterUtils.java | 12 +- .../java/debug/core/adapter/Constants.java | 6 +- .../ConfigurationDoneRequestHandler.java | 9 +- .../handler/InitializeRequestHandler.java | 28 +++- .../handler/SetBreakpointsRequestHandler.java | 27 ++-- ...SetExceptionBreakpointsRequestHandler.java | 49 +++++-- .../java/debug/core/protocol/Requests.java | 17 ++- .../java/debug/core/protocol/Types.java | 136 +++++++++++++++++- .../java/debug/core/AbstractJdiTestCase.java | 5 +- 13 files changed, 324 insertions(+), 126 deletions(-) diff --git a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/Breakpoint.java b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/Breakpoint.java index d8316c2e3..c6f0506c2 100644 --- a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/Breakpoint.java +++ b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/Breakpoint.java @@ -41,29 +41,26 @@ public class Breakpoint implements IBreakpoint { private int hitCount = 0; private String condition = null; private String logMessage = null; + private int suspendPolicy = BreakpointRequest.SUSPEND_EVENT_THREAD; private HashMap propertyMap = new HashMap<>(); - private final boolean suspendAllThreads; private boolean async = false; - Breakpoint(VirtualMachine vm, IEventHub eventHub, String className, int lineNumber, boolean suspendAllThreads) { - this(vm, eventHub, className, lineNumber, 0, null, suspendAllThreads); + Breakpoint(VirtualMachine vm, IEventHub eventHub, String className, int lineNumber) { + this(vm, eventHub, className, lineNumber, 0, null); } - Breakpoint(VirtualMachine vm, IEventHub eventHub, String className, int lineNumber, int hitCount, boolean suspendAllThreads) { - this(vm, eventHub, className, lineNumber, hitCount, null, suspendAllThreads); + Breakpoint(VirtualMachine vm, IEventHub eventHub, String className, int lineNumber, int hitCount) { + this(vm, eventHub, className, lineNumber, hitCount, null); } - Breakpoint(VirtualMachine vm, IEventHub eventHub, String className, int lineNumber, int hitCount, - String condition, boolean suspendAllThreads) { - this(vm, eventHub, className, lineNumber, hitCount, condition, null, suspendAllThreads); + Breakpoint(VirtualMachine vm, IEventHub eventHub, String className, int lineNumber, int hitCount, String condition) { + this(vm, eventHub, className, lineNumber, hitCount, condition, null); } - Breakpoint(VirtualMachine vm, IEventHub eventHub, String className, int lineNumber, int hitCount, - String condition, String logMessage, boolean suspendAllThreads) { + Breakpoint(VirtualMachine vm, IEventHub eventHub, String className, int lineNumber, int hitCount, String condition, String logMessage) { this.vm = vm; this.eventHub = eventHub; - this.suspendAllThreads = suspendAllThreads; String contextClass = className; String methodName = null; String methodSignature = null; @@ -83,15 +80,13 @@ public class Breakpoint implements IBreakpoint { this.logMessage = logMessage; } - Breakpoint(VirtualMachine vm, IEventHub eventHub, JavaBreakpointLocation sourceLocation, int hitCount, - String condition, String logMessage, boolean suspendAllThreads) { + Breakpoint(VirtualMachine vm, IEventHub eventHub, JavaBreakpointLocation sourceLocation, int hitCount, String condition, String logMessage) { this.vm = vm; this.eventHub = eventHub; this.sourceLocation = sourceLocation; this.hitCount = hitCount; this.condition = condition; this.logMessage = logMessage; - this.suspendAllThreads = suspendAllThreads; } // IDebugResource @@ -209,19 +204,6 @@ public void setAsync(boolean async) { this.async = async; } - @Override - public void setSuspendPolicy(String policy) { - } - - @Override - public String getSuspendPolicy() { - return suspendAllThreads ? "SUSPEND_ALL" : "SUSPEND_EVENT_THREAD"; - } - - protected boolean suspendAllThreads() { - return suspendAllThreads; - } - @Override public CompletableFuture install() { // It's possible that different class loaders create new class with the same name. @@ -431,11 +413,7 @@ private CompletableFuture> createBreakpointRequests(List newLocations.forEach(location -> { BreakpointRequest request = vm.eventRequestManager().createBreakpointRequest(location); - if ("SUSPEND_ALL".equals(getSuspendPolicy())) { - request.setSuspendPolicy(BreakpointRequest.SUSPEND_ALL); - } else { - request.setSuspendPolicy(BreakpointRequest.SUSPEND_EVENT_THREAD); - } + request.setSuspendPolicy(suspendPolicy); if (hitCount > 0) { request.addCountFilter(hitCount); } @@ -491,4 +469,14 @@ public void putProperty(Object key, Object value) { public Object getProperty(Object key) { return propertyMap.get(key); } -} + + @Override + public int getSuspendPolicy() { + return this.suspendPolicy; + } + + @Override + public void setSuspendPolicy(int suspendPolicy) { + this.suspendPolicy = suspendPolicy; + } +} \ No newline at end of file diff --git a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/DebugSession.java b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/DebugSession.java index d5b8ceb47..7c400d2e8 100644 --- a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/DebugSession.java +++ b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/DebugSession.java @@ -36,12 +36,9 @@ public class DebugSession implements IDebugSession { private EventHub eventHub = new EventHub(); private List eventRequests = new ArrayList<>(); private List subscriptions = new ArrayList<>(); - private final boolean suspendAllThreads; public DebugSession(VirtualMachine virtualMachine) { vm = virtualMachine; - // Capture suspend policy at session start - this persists for the session lifetime - this.suspendAllThreads = DebugSettings.getCurrent().suspendAllThreads; } @Override @@ -130,32 +127,36 @@ public void terminate() { } @Override - public IBreakpoint createBreakpoint(JavaBreakpointLocation sourceLocation, int hitCount, String condition, String logMessage) { - return new EvaluatableBreakpoint(vm, this.getEventHub(), sourceLocation, hitCount, condition, logMessage, suspendAllThreads); + public IBreakpoint createBreakpoint(JavaBreakpointLocation sourceLocation, int hitCount, String condition, String logMessage, int suspendPolicy) { + EvaluatableBreakpoint breakpoint = new EvaluatableBreakpoint(vm, this.getEventHub(), sourceLocation, hitCount, condition, logMessage); + breakpoint.setSuspendPolicy(suspendPolicy); + return breakpoint; } @Override - public IBreakpoint createBreakpoint(String className, int lineNumber, int hitCount, String condition, String logMessage) { - return new EvaluatableBreakpoint(vm, this.getEventHub(), className, lineNumber, hitCount, condition, logMessage, suspendAllThreads); + public IBreakpoint createBreakpoint(String className, int lineNumber, int hitCount, String condition, String logMessage, int suspendPolicy) { + EvaluatableBreakpoint breakpoint = new EvaluatableBreakpoint(vm, this.getEventHub(), className, lineNumber, hitCount, condition, logMessage); + breakpoint.setSuspendPolicy(suspendPolicy); + return breakpoint; } @Override public IWatchpoint createWatchPoint(String className, String fieldName, String accessType, String condition, int hitCount) { - return new Watchpoint(vm, this.getEventHub(), className, fieldName, accessType, condition, hitCount, suspendAllThreads); + return new Watchpoint(vm, this.getEventHub(), className, fieldName, accessType, condition, hitCount); } @Override - public void setExceptionBreakpoints(boolean notifyCaught, boolean notifyUncaught) { - setExceptionBreakpoints(notifyCaught, notifyUncaught, null, null); + public void setExceptionBreakpoints(boolean notifyCaught, boolean notifyUncaught, int suspendModeOnCaught, int suspendModeOnUncaught) { + setExceptionBreakpoints(notifyCaught, notifyUncaught, suspendModeOnCaught, suspendModeOnUncaught, null, null); } @Override - public void setExceptionBreakpoints(boolean notifyCaught, boolean notifyUncaught, String[] classFilters, String[] classExclusionFilters) { - setExceptionBreakpoints(notifyCaught, notifyUncaught, null, classFilters, classExclusionFilters); + public void setExceptionBreakpoints(boolean notifyCaught, boolean notifyUncaught, int suspendModeOnCaught, int suspendModeOnUncaught, String[] classFilters, String[] classExclusionFilters) { + setExceptionBreakpoints(notifyCaught, notifyUncaught, suspendModeOnCaught, suspendModeOnUncaught, null, classFilters, classExclusionFilters); } @Override - public void setExceptionBreakpoints(boolean notifyCaught, boolean notifyUncaught, String[] exceptionTypes, + public void setExceptionBreakpoints(boolean notifyCaught, boolean notifyUncaught, int suspendModeOnCaught, int suspendModeOnUncaught, String[] exceptionTypes, String[] classFilters, String[] classExclusionFilters) { EventRequestManager manager = vm.eventRequestManager(); @@ -187,19 +188,7 @@ public void setExceptionBreakpoints(boolean notifyCaught, boolean notifyUncaught // See org.eclipse.debug.jdi.tests.AbstractJDITest for the example. if (exceptionTypes == null || exceptionTypes.length == 0) { - ExceptionRequest request = manager.createExceptionRequest(null, notifyCaught, notifyUncaught); - request.setSuspendPolicy(suspendAllThreads ? EventRequest.SUSPEND_ALL : EventRequest.SUSPEND_EVENT_THREAD); - if (classFilters != null) { - for (String classFilter : classFilters) { - request.addClassFilter(classFilter); - } - } - if (classExclusionFilters != null) { - for (String exclusionFilter : classExclusionFilters) { - request.addClassExclusionFilter(exclusionFilter); - } - } - request.enable(); + createExceptionBreakpoint(null, notifyCaught, notifyUncaught, suspendModeOnCaught, suspendModeOnUncaught, classFilters, classExclusionFilters); return; } @@ -219,27 +208,27 @@ public void setExceptionBreakpoints(boolean notifyCaught, boolean notifyUncaught && eventRequests.contains(debugEvent.event.request())) .subscribe(debugEvent -> { ClassPrepareEvent event = (ClassPrepareEvent) debugEvent.event; - createExceptionBreakpoint(event.referenceType(), notifyCaught, notifyUncaught, classFilters, classExclusionFilters); + createExceptionBreakpoint(event.referenceType(), notifyCaught, notifyUncaught, suspendModeOnCaught, suspendModeOnUncaught, classFilters, classExclusionFilters); }); subscriptions.add(subscription); // register exception breakpoint in the loaded classes. for (ReferenceType refType : vm.classesByName(exceptionType)) { - createExceptionBreakpoint(refType, notifyCaught, notifyUncaught, classFilters, classExclusionFilters); + createExceptionBreakpoint(refType, notifyCaught, notifyUncaught, suspendModeOnCaught, suspendModeOnUncaught, classFilters, classExclusionFilters); } } } } @Override - public void setExceptionBreakpoints(boolean notifyCaught, boolean notifyUncaught, String[] exceptionTypes, + public void setExceptionBreakpoints(boolean notifyCaught, boolean notifyUncaught, int suspendModeOnCaught, int suspendModeOnUncaught, String[] exceptionTypes, String[] classFilters, String[] classExclusionFilters, boolean async) { if (async) { AsyncJdwpUtils.runAsync(() -> { - setExceptionBreakpoints(notifyCaught, notifyUncaught, exceptionTypes, classFilters, classExclusionFilters); + setExceptionBreakpoints(notifyCaught, notifyUncaught, suspendModeOnCaught, suspendModeOnUncaught, exceptionTypes, classFilters, classExclusionFilters); }); } else { - setExceptionBreakpoints(notifyCaught, notifyUncaught, exceptionTypes, classFilters, classExclusionFilters); + setExceptionBreakpoints(notifyCaught, notifyUncaught, suspendModeOnCaught, suspendModeOnUncaught, exceptionTypes, classFilters, classExclusionFilters); } } @@ -263,22 +252,27 @@ public VirtualMachine getVM() { return vm; } - @Override - public boolean shouldSuspendAllThreads() { - return suspendAllThreads; - } - @Override public IMethodBreakpoint createFunctionBreakpoint(String className, String functionName, String condition, int hitCount) { - return new MethodBreakpoint(vm, this.getEventHub(), className, functionName, condition, hitCount, suspendAllThreads); + return new MethodBreakpoint(vm, this.getEventHub(), className, functionName, condition, hitCount); + } + + private void createExceptionBreakpoint(ReferenceType refType, boolean notifyCaught, boolean notifyUncaught, + int suspendModeOnCaught, int suspendModeOnUncaught, String[] classFilters, String[] classExclusionFilters) { + if (suspendModeOnCaught == suspendModeOnUncaught) { + createExceptionBreakpoint(refType, notifyCaught, notifyUncaught, suspendModeOnCaught, classFilters, classExclusionFilters); + } else { + createExceptionBreakpoint(refType, notifyCaught, notifyUncaught, suspendModeOnCaught, classFilters, classExclusionFilters); + createExceptionBreakpoint(refType, notifyCaught, notifyUncaught, suspendModeOnUncaught, classFilters, classExclusionFilters); + } } private void createExceptionBreakpoint(ReferenceType refType, boolean notifyCaught, boolean notifyUncaught, - String[] classFilters, String[] classExclusionFilters) { + int suspendMode, String[] classFilters, String[] classExclusionFilters) { EventRequestManager manager = vm.eventRequestManager(); ExceptionRequest request = manager.createExceptionRequest(refType, notifyCaught, notifyUncaught); - request.setSuspendPolicy(suspendAllThreads ? EventRequest.SUSPEND_ALL : EventRequest.SUSPEND_EVENT_THREAD); + request.setSuspendPolicy(suspendMode); if (classFilters != null) { for (String classFilter : classFilters) { request.addClassFilter(classFilter); @@ -291,4 +285,4 @@ private void createExceptionBreakpoint(ReferenceType refType, boolean notifyCaug } request.enable(); } -} +} \ No newline at end of file diff --git a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/IBreakpoint.java b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/IBreakpoint.java index ec3ea818a..7a0a585b8 100644 --- a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/IBreakpoint.java +++ b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/IBreakpoint.java @@ -49,17 +49,14 @@ public interface IBreakpoint extends IDebugResource { void setLogMessage(String logMessage); + int getSuspendPolicy(); + + void setSuspendPolicy(int suspendPolicy); + default void setAsync(boolean async) { } default boolean async() { return false; } - - default void setSuspendPolicy(String policy) { - } - - default String getSuspendPolicy() { - return null; - } -} +} \ No newline at end of file diff --git a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/IDebugSession.java b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/IDebugSession.java index afc2283f0..a05589daf 100644 --- a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/IDebugSession.java +++ b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/IDebugSession.java @@ -28,19 +28,19 @@ public interface IDebugSession { void terminate(); // breakpoints - IBreakpoint createBreakpoint(String className, int lineNumber, int hitCount, String condition, String logMessage); + IBreakpoint createBreakpoint(String className, int lineNumber, int hitCount, String condition, String logMessage, int suspendPolicy); - IBreakpoint createBreakpoint(JavaBreakpointLocation sourceLocation, int hitCount, String condition, String logMessage); + IBreakpoint createBreakpoint(JavaBreakpointLocation sourceLocation, int hitCount, String condition, String logMessage, int suspendPolicy); IWatchpoint createWatchPoint(String className, String fieldName, String accessType, String condition, int hitCount); - void setExceptionBreakpoints(boolean notifyCaught, boolean notifyUncaught); + void setExceptionBreakpoints(boolean notifyCaught, boolean notifyUncaught, int suspendModeOnCaught, int suspendModeOnUncaught); - void setExceptionBreakpoints(boolean notifyCaught, boolean notifyUncaught, String[] classFilters, String[] classExclusionFilters); + void setExceptionBreakpoints(boolean notifyCaught, boolean notifyUncaught, int suspendModeOnCaught, int suspendModeOnUncaught, String[] classFilters, String[] classExclusionFilters); - void setExceptionBreakpoints(boolean notifyCaught, boolean notifyUncaught, String[] exceptionTypes, String[] classFilters, String[] classExclusionFilters); + void setExceptionBreakpoints(boolean notifyCaught, boolean notifyUncaught, int suspendModeOnCaught, int suspendModeOnUncaught, String[] exceptionTypes, String[] classFilters, String[] classExclusionFilters); - void setExceptionBreakpoints(boolean notifyCaught, boolean notifyUncaught, String[] exceptionTypes, String[] classFilters, String[] classExclusionFilters, + void setExceptionBreakpoints(boolean notifyCaught, boolean notifyUncaught, int suspendModeOnCaught, int suspendModeOnUncaught, String[] exceptionTypes, String[] classFilters, String[] classExclusionFilters, boolean async); IMethodBreakpoint createFunctionBreakpoint(String className, String functionName, String condition, int hitCount); @@ -52,10 +52,4 @@ void setExceptionBreakpoints(boolean notifyCaught, boolean notifyUncaught, Strin IEventHub getEventHub(); VirtualMachine getVM(); - - /** - * Returns whether breakpoints should suspend all threads or just the event thread. - * This value is captured at session start and persists for the session lifetime. - */ - boolean shouldSuspendAllThreads(); -} +} \ No newline at end of file diff --git a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/AdapterUtils.java b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/AdapterUtils.java index c30aa8742..b4e1c3b88 100644 --- a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/AdapterUtils.java +++ b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/AdapterUtils.java @@ -34,6 +34,7 @@ import com.microsoft.java.debug.core.DebugException; import com.microsoft.java.debug.core.protocol.Messages.Response; +import com.sun.jdi.request.EventRequest; import com.microsoft.java.debug.core.protocol.Responses; import com.microsoft.java.debug.core.protocol.Types; @@ -364,4 +365,13 @@ public static int[] binarySearchMappedLines(int[] lineMappings, int targetLine) return values; } -} + + public static int suspendPolicyFromBreakpointMode(String breakpointMode) { + if (Constants.SUSPEND_VM.equals(breakpointMode)) { + return EventRequest.SUSPEND_ALL; + } else if (Constants.SUSPEND_THREAD.equals(breakpointMode)) { + return EventRequest.SUSPEND_EVENT_THREAD; + } + return EventRequest.SUSPEND_EVENT_THREAD; + } +} \ No newline at end of file diff --git a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/Constants.java b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/Constants.java index 2e523aba2..99ea77fdb 100644 --- a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/Constants.java +++ b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/Constants.java @@ -15,4 +15,8 @@ public final class Constants { public static final String PROJECT_NAME = "projectName"; public static final String DEBUGGEE_ENCODING = "debuggeeEncoding"; public static final String MAIN_CLASS = "mainClass"; -} + + // Breakpoint suspend modes + public static final String SUSPEND_VM = "suspendVM"; + public static final String SUSPEND_THREAD = "suspendThread"; +} \ No newline at end of file diff --git a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/ConfigurationDoneRequestHandler.java b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/ConfigurationDoneRequestHandler.java index 308adddb6..8260fabb7 100644 --- a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/ConfigurationDoneRequestHandler.java +++ b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/ConfigurationDoneRequestHandler.java @@ -40,8 +40,8 @@ import com.sun.jdi.event.ThreadStartEvent; import com.sun.jdi.event.VMDeathEvent; import com.sun.jdi.event.VMDisconnectEvent; -import com.sun.jdi.request.EventRequest; import com.sun.jdi.event.VMStartEvent; +import com.sun.jdi.request.EventRequest; public class ConfigurationDoneRequestHandler implements IDebugRequestHandler { protected static final Logger logger = Logger.getLogger(Configuration.LOGGER_NAME); @@ -120,9 +120,8 @@ private void handleDebugEvent(DebugEvent debugEvent, IDebugSession debugSession, ((ExceptionEvent) event).catchLocation() == null); context.getExceptionManager().setException(thread.uniqueID(), jdiException); context.getThreadCache().addEventThread(thread, "exception"); - boolean allThreadsStopped = event.request() != null - && event.request().suspendPolicy() == EventRequest.SUSPEND_ALL; - context.getProtocolServer().sendEvent(new Events.StoppedEvent("exception", thread.uniqueID(), allThreadsStopped)); + boolean suspendAll = event.request() != null ? event.request().suspendPolicy() == EventRequest.SUSPEND_ALL : false; + context.getProtocolServer().sendEvent(new Events.StoppedEvent("exception", thread.uniqueID(), suspendAll)); debugEvent.shouldResume = false; } else { isImportantEvent = false; @@ -133,4 +132,4 @@ private void handleDebugEvent(DebugEvent debugEvent, IDebugSession debugSession, UsageDataSession.recordEvent(event); } } -} +} \ No newline at end of file diff --git a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/InitializeRequestHandler.java b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/InitializeRequestHandler.java index 6b9245166..f13f6aeec 100644 --- a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/InitializeRequestHandler.java +++ b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/InitializeRequestHandler.java @@ -15,6 +15,7 @@ import java.util.List; import java.util.concurrent.CompletableFuture; +import com.microsoft.java.debug.core.adapter.Constants; import com.microsoft.java.debug.core.adapter.IDebugAdapterContext; import com.microsoft.java.debug.core.adapter.IDebugRequestHandler; import com.microsoft.java.debug.core.protocol.Messages; @@ -22,6 +23,7 @@ import com.microsoft.java.debug.core.protocol.Types; public class InitializeRequestHandler implements IDebugRequestHandler { + @Override public List getTargetCommands() { return Arrays.asList(Requests.Command.INITIALIZE); @@ -66,8 +68,32 @@ public CompletableFuture handle(Requests.Command command, Req caps.supportsClipboardContext = true; caps.supportsBreakpointLocationsRequest = true; caps.supportsStepInTargetsRequest = true; + + // Add breakpoint modes for suspend behavior + Types.BreakpointMode[] breakpointModes = { + new Types.BreakpointMode ( + Constants.SUSPEND_THREAD, + "Suspend Thread", + "Suspends only the thread that hit the breakpoint", + new Types.BreakpointModeApplicability[] { + Types.BreakpointModeApplicability.SOURCE + // data and function breakpoints are not supported by VS Code + // instruction breakpoints are not supported by this adapter + } + ), + new Types.BreakpointMode( + Constants.SUSPEND_VM, + "Suspend VM", + "Suspends the entire virtual machine when breakpoint is hit", + new Types.BreakpointModeApplicability[] { + Types.BreakpointModeApplicability.SOURCE } + ) + + }; + caps.breakpointModes = breakpointModes; + response.body = caps; context.setInitialized(true); return CompletableFuture.completedFuture(response); } -} +} \ No newline at end of file diff --git a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/SetBreakpointsRequestHandler.java b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/SetBreakpointsRequestHandler.java index 0f171486e..ffb994878 100644 --- a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/SetBreakpointsRequestHandler.java +++ b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/SetBreakpointsRequestHandler.java @@ -134,6 +134,19 @@ public CompletableFuture handle(Command command, Arguments arguments, added[i].setCondition(toAdds[i].getCondition()); } + if (toAdds[i].getSuspendPolicy() != added[i].getSuspendPolicy()) { + added[i].setSuspendPolicy(toAdds[i].getSuspendPolicy()); + try { + added[i].close(); + added[i].install().thenAccept(bp -> { + Events.BreakpointEvent bpEvent = new Events.BreakpointEvent("changed", this.convertDebuggerBreakpointToClient(bp, context)); + context.getProtocolServer().sendEvent(bpEvent); + }); + } catch (Exception e) { + logger.log(Level.SEVERE, String.format("Close breakpoint exception: %s", e.toString()), e); + } + } + } res.add(this.convertDebuggerBreakpointToClient(added[i], context)); } @@ -200,6 +213,7 @@ private void registerBreakpointHandler(IDebugAdapterContext context) { // find the breakpoint related to this breakpoint event IBreakpoint expressionBP = getAssociatedEvaluatableBreakpoint(context, (BreakpointEvent) event); String breakpointName = computeBreakpointName(event.request()); + boolean suspendAll = event.request() != null ? event.request().suspendPolicy() == EventRequest.SUSPEND_ALL : false; if (expressionBP != null) { CompletableFuture.runAsync(() -> { @@ -212,19 +226,14 @@ private void registerBreakpointHandler(IDebugAdapterContext context) { debugEvent.eventSet.resume(); } else { context.getThreadCache().addEventThread(bpThread, breakpointName); - boolean allThreadsStopped = event.request() != null - && event.request().suspendPolicy() == EventRequest.SUSPEND_ALL; - context.getProtocolServer().sendEvent(new Events.StoppedEvent( - breakpointName, bpThread.uniqueID(), allThreadsStopped)); + context.getProtocolServer().sendEvent(new Events.StoppedEvent(breakpointName, bpThread.uniqueID(), suspendAll)); } }); }); } else { context.getThreadCache().addEventThread(bpThread, breakpointName); - boolean allThreadsStopped = event.request() != null - && event.request().suspendPolicy() == EventRequest.SUSPEND_ALL; context.getProtocolServer().sendEvent(new Events.StoppedEvent( - breakpointName, bpThread.uniqueID(), allThreadsStopped)); + breakpointName, bpThread.uniqueID(), suspendAll)); } debugEvent.shouldResume = false; } @@ -339,7 +348,7 @@ private IBreakpoint[] convertClientBreakpointsToDebugger(String sourceFile, Type } } breakpoints[i] = context.getDebugSession().createBreakpoint(locations[i], hitCount, sourceBreakpoints[i].condition, - sourceBreakpoints[i].logMessage); + sourceBreakpoints[i].logMessage, AdapterUtils.suspendPolicyFromBreakpointMode(sourceBreakpoints[i].mode)); if (sourceProvider.supportsRealtimeBreakpointVerification() && StringUtils.isNotBlank(locations[i].className())) { breakpoints[i].putProperty("verified", true); } @@ -367,4 +376,4 @@ private void reinstallBreakpoints(IDebugAdapterContext context, List typ } } } -} +} \ No newline at end of file diff --git a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/SetExceptionBreakpointsRequestHandler.java b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/SetExceptionBreakpointsRequestHandler.java index b51c5fe27..252f43504 100644 --- a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/SetExceptionBreakpointsRequestHandler.java +++ b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/SetExceptionBreakpointsRequestHandler.java @@ -14,9 +14,6 @@ import java.util.Arrays; import java.util.List; import java.util.concurrent.CompletableFuture; - -import org.apache.commons.lang3.ArrayUtils; - import com.microsoft.java.debug.core.DebugSettings; import com.microsoft.java.debug.core.IDebugSession; import com.microsoft.java.debug.core.DebugSettings.IDebugSettingChangeListener; @@ -29,9 +26,11 @@ import com.microsoft.java.debug.core.protocol.Requests.Command; import com.microsoft.java.debug.core.protocol.Requests.ExceptionFilters; import com.microsoft.java.debug.core.protocol.Requests.SetExceptionBreakpointsArguments; +import com.microsoft.java.debug.core.protocol.Types.ExceptionFilterOptions; import com.microsoft.java.debug.core.protocol.Types; import com.sun.jdi.event.VMDeathEvent; import com.sun.jdi.event.VMDisconnectEvent; +import com.sun.jdi.request.EventRequest; public class SetExceptionBreakpointsRequestHandler implements IDebugRequestHandler, IDebugSettingChangeListener { private IDebugSession debugSession = null; @@ -39,6 +38,8 @@ public class SetExceptionBreakpointsRequestHandler implements IDebugRequestHandl private boolean notifyCaught = false; private boolean notifyUncaught = false; private boolean asyncJDWP = false; + private int suspendModeOnCaught; + private int suspendModeOnUncaught; @Override public List getTargetCommands() { @@ -63,12 +64,38 @@ public synchronized CompletableFuture handle(Command command, Argument } }); } + + SetExceptionBreakpointsArguments requestArgs = (SetExceptionBreakpointsArguments)arguments; + String[] filters = requestArgs.filters; - String[] filters = ((SetExceptionBreakpointsArguments) arguments).filters; try { - this.notifyCaught = ArrayUtils.contains(filters, Types.ExceptionBreakpointFilter.CAUGHT_EXCEPTION_FILTER_NAME); - this.notifyUncaught = ArrayUtils.contains(filters, Types.ExceptionBreakpointFilter.UNCAUGHT_EXCEPTION_FILTER_NAME); - setExceptionBreakpoints(context.getDebugSession(), this.notifyCaught, this.notifyUncaught); + this.notifyCaught = false; + this.notifyUncaught = false; + if (filters != null) { + for (String filter : filters) { + if (filter.equals(Types.ExceptionBreakpointFilter.CAUGHT_EXCEPTION_FILTER_NAME)) { + this.notifyCaught = true; + } else if (filter.equals(Types.ExceptionBreakpointFilter.UNCAUGHT_EXCEPTION_FILTER_NAME)) { + this.notifyUncaught = true; + } + } + } + this.suspendModeOnCaught = EventRequest.SUSPEND_EVENT_THREAD; + this.suspendModeOnUncaught = EventRequest.SUSPEND_EVENT_THREAD; + + ExceptionFilterOptions[] filterOptions = requestArgs.filterOptions; + if (filterOptions != null) { + for (ExceptionFilterOptions filterOption : requestArgs.filterOptions) { + if (filterOption.filterId.equals(Types.ExceptionBreakpointFilter.CAUGHT_EXCEPTION_FILTER_NAME)) { + this.notifyCaught = true; + this.suspendModeOnCaught = AdapterUtils.suspendPolicyFromBreakpointMode(filterOption.mode); + } else if (filterOption.filterId.equals(Types.ExceptionBreakpointFilter.UNCAUGHT_EXCEPTION_FILTER_NAME)) { + this.notifyUncaught = true; + this.suspendModeOnUncaught = AdapterUtils.suspendPolicyFromBreakpointMode(filterOption.mode); + } + } + } + setExceptionBreakpoints(context.getDebugSession(), this.notifyCaught, this.notifyUncaught, suspendModeOnCaught, suspendModeOnUncaught); return CompletableFuture.completedFuture(response); } catch (Exception ex) { throw AdapterUtils.createCompletionException( @@ -78,22 +105,22 @@ public synchronized CompletableFuture handle(Command command, Argument } } - private void setExceptionBreakpoints(IDebugSession debugSession, boolean notifyCaught, boolean notifyUncaught) { + private void setExceptionBreakpoints(IDebugSession debugSession, boolean notifyCaught, boolean notifyUncaught, int suspendModeOnCaught, int suspendModeOnUncaught) { ExceptionFilters exceptionFilters = DebugSettings.getCurrent().exceptionFilters; String[] exceptionTypes = (exceptionFilters == null ? null : exceptionFilters.exceptionTypes); String[] classFilters = (exceptionFilters == null ? null : exceptionFilters.allowClasses); String[] classExclusionFilters = (exceptionFilters == null ? null : exceptionFilters.skipClasses); - debugSession.setExceptionBreakpoints(notifyCaught, notifyUncaught, exceptionTypes, classFilters, classExclusionFilters, this.asyncJDWP); + debugSession.setExceptionBreakpoints(notifyCaught, notifyUncaught, suspendModeOnCaught, suspendModeOnUncaught, exceptionTypes, classFilters, classExclusionFilters, this.asyncJDWP); } @Override public synchronized void update(DebugSettings oldSettings, DebugSettings newSettings) { try { if (newSettings != null && newSettings.exceptionFiltersUpdated) { - setExceptionBreakpoints(debugSession, notifyCaught, notifyUncaught); + setExceptionBreakpoints(debugSession, notifyCaught, notifyUncaught, suspendModeOnCaught, suspendModeOnUncaught); } } catch (Exception ex) { DebugSettings.removeDebugSettingChangeListener(this); } } -} +} \ No newline at end of file diff --git a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/protocol/Requests.java b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/protocol/Requests.java index 1129d230e..a517b48ec 100644 --- a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/protocol/Requests.java +++ b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/protocol/Requests.java @@ -17,6 +17,8 @@ import com.google.gson.annotations.SerializedName; import com.microsoft.java.debug.core.protocol.Types.DataBreakpoint; +import com.microsoft.java.debug.core.protocol.Types.ExceptionFilterOptions; +import com.microsoft.java.debug.core.protocol.Types.ExceptionOptions; import com.microsoft.java.debug.core.protocol.Types.Source; /** @@ -250,6 +252,19 @@ public static class SetFunctionBreakpointsArguments extends Arguments { public static class SetExceptionBreakpointsArguments extends Arguments { public String[] filters = new String[0]; + /** + * Set of exception filters and their options. The set of all possible + * exception filters is defined by the `exceptionBreakpointFilters` + * capability. This attribute is only honored by a debug adapter if the + * corresponding capability `supportsExceptionFilterOptions` is true. The + * `filter` and `filterOptions` sets are additive. + */ + public ExceptionFilterOptions[] filterOptions; + + /** + * Configuration options for selected exceptions. The attribute is only honored by a debug adapter if the corresponding capability `supportsExceptionOptions` is true. + */ + public ExceptionOptions[] exceptionOptions; } public static class ExceptionInfoArguments extends Arguments { @@ -515,4 +530,4 @@ public static Command parse(String command) { return UNSUPPORTED; } } -} +} \ No newline at end of file diff --git a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/protocol/Types.java b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/protocol/Types.java index 33308af6d..c2da98ae9 100644 --- a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/protocol/Types.java +++ b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/protocol/Types.java @@ -209,6 +209,7 @@ public static class SourceBreakpoint { public String hitCondition; public String condition; public String logMessage; + public String mode; public SourceBreakpoint(int line, int column) { this.line = line; @@ -233,6 +234,14 @@ public SourceBreakpoint(int line, String condition, String hitCondition, int col this.condition = condition; this.hitCondition = hitCondition; } + + public SourceBreakpoint(int line, String condition, String hitCondition, int column, String mode) { + this.line = line; + this.column = column; + this.condition = condition; + this.hitCondition = hitCondition; + this.mode = mode; + } } public static class FunctionBreakpoint { @@ -414,6 +423,130 @@ public VariablePresentationHint(boolean lazy) { } } + /** + * An ExceptionPathSegment represents a segment in a path that is used to match leafs or nodes in a tree of exceptions. + * If a segment consists of more than one name, it matches the names provided if negate is false or missing, + * or it matches anything except the names provided if negate is true. + */ + public static class ExceptionPathSegment { + /** + * If false or missing this segment matches the names provided, otherwise it matches anything except the names provided. + */ + public boolean negate; + + /** + * Depending on the value of negate the names that should match or not match. + */ + public String[] names; + + public ExceptionPathSegment() { + } + + public ExceptionPathSegment(boolean negate, String[] names) { + this.negate = negate; + this.names = names; + } + } + + /** + * An ExceptionOptions assigns configuration options to a set of exceptions. + */ + public static class ExceptionOptions { + /** + * A path that selects a single or multiple exceptions in a tree. If path is missing, the whole tree is selected. + * By convention the first segment of the path is a category that is used to group exceptions in the UI. + */ + public ExceptionPathSegment[] path; + + /** + * Condition when a thrown exception should result in a break. + */ + public ExceptionBreakMode breakMode; + + public ExceptionOptions() { + } + + public ExceptionOptions(ExceptionPathSegment[] path, ExceptionBreakMode breakMode) { + this.path = path; + this.breakMode = breakMode; + } + } + + /** + * An ExceptionFilterOptions is used to specify an exception filter together with its options. + */ + public static class ExceptionFilterOptions { + /** + * ID of an exception filter returned by the exceptionBreakpointFilters capability. + */ + public String filterId; + + /** + * An expression for conditional exceptions. The exception breaks into the debugger if the result of the condition is true. + */ + public String condition; + + /** + * The mode of this exception breakpoint. If defined, this must be one of the breakpointModes the debug adapter advertised in its Capabilities. + */ + public String mode; + + public ExceptionFilterOptions() { + } + + public ExceptionFilterOptions(String filterId) { + this.filterId = filterId; + } + + public ExceptionFilterOptions(String filterId, String condition, String mode) { + this.filterId = filterId; + this.condition = condition; + this.mode = mode; + } + } + + public static enum BreakpointModeApplicability { + @SerializedName("source") + SOURCE, + @SerializedName("exception") + EXCEPTION, + @SerializedName("data") + DATA, + @SerializedName("instruction") + INSTRUCTION, + } + + public static class BreakpointMode { + public BreakpointMode(String mode, String label, String description, BreakpointModeApplicability[] appliesTo) { + this.mode = mode; + this.label = label; + this.description = description; + this.appliesTo = appliesTo; + } + /** + * The internal ID of the mode. This value is passed to the `setBreakpoints` + * request. + */ + public String mode; + + /** + * The name of the breakpoint mode. This is shown in the UI. + */ + public String label; + + /** + * A help text providing additional information about the breakpoint mode. + * This string is typically shown as a hover and can be translated. + */ + public String description; + + /** + * Describes one or more type of breakpoint this mode applies to. + */ + public BreakpointModeApplicability[] appliesTo; + } + + public static class Capabilities { public boolean supportsConfigurationDoneRequest; public boolean supportsHitConditionalBreakpoints; @@ -434,6 +567,7 @@ public static class Capabilities { // https://microsoft.github.io/debug-adapter-protocol/specification#Requests_BreakpointLocations public boolean supportsBreakpointLocationsRequest; public boolean supportsStepInTargetsRequest; + public BreakpointMode[] breakpointModes; } public static class StepInTarget { @@ -450,4 +584,4 @@ public StepInTarget(int id, String label) { } } -} +} \ No newline at end of file diff --git a/com.microsoft.java.debug.core/src/test/java/com/microsoft/java/debug/core/AbstractJdiTestCase.java b/com.microsoft.java.debug.core/src/test/java/com/microsoft/java/debug/core/AbstractJdiTestCase.java index 4d0a122a5..596a619a7 100644 --- a/com.microsoft.java.debug.core/src/test/java/com/microsoft/java/debug/core/AbstractJdiTestCase.java +++ b/com.microsoft.java.debug.core/src/test/java/com/microsoft/java/debug/core/AbstractJdiTestCase.java @@ -22,6 +22,7 @@ import com.sun.jdi.Value; import com.sun.jdi.VirtualMachine; import com.sun.jdi.event.BreakpointEvent; +import com.sun.jdi.request.EventRequest; public abstract class AbstractJdiTestCase extends EasyMockSupport { private static int TEST_TIME_OUT = 1000 * 10; @@ -38,7 +39,7 @@ protected BreakpointEvent waitForBreakPointEvent(String breakpointAtClass, int l } IDebugSession debugSession = getCurrentDebugSession(); - IBreakpoint breakpointToAdd = debugSession.createBreakpoint(breakpointAtClass, line, 0, null, null); + IBreakpoint breakpointToAdd = debugSession.createBreakpoint(breakpointAtClass, line, 0, null, null, EventRequest.SUSPEND_EVENT_THREAD); breakpointToAdd.install().thenAccept(t -> { System.out.println("Breakpoint is accepted."); }); @@ -108,4 +109,4 @@ protected StackFrame getSecondLevelStackFrame() { } protected abstract IDebugSession getCurrentDebugSession(); -} +} \ No newline at end of file From b48a562d5023dfae26806b1e7ae0e1204e5d8405 Mon Sep 17 00:00:00 2001 From: Stan185 <57770977+Stan185@users.noreply.github.com> Date: Thu, 29 Jan 2026 16:28:50 +0100 Subject: [PATCH 2/3] Revert "Add suspend mode for source breakpoints" This reverts commit 247face213d9f24dec38ce947af9b458ef692eb3. --- .../microsoft/java/debug/core/Breakpoint.java | 54 ++++--- .../java/debug/core/DebugSession.java | 74 +++++----- .../java/debug/core/IBreakpoint.java | 13 +- .../java/debug/core/IDebugSession.java | 20 ++- .../java/debug/core/adapter/AdapterUtils.java | 12 +- .../java/debug/core/adapter/Constants.java | 6 +- .../ConfigurationDoneRequestHandler.java | 9 +- .../handler/InitializeRequestHandler.java | 28 +--- .../handler/SetBreakpointsRequestHandler.java | 27 ++-- ...SetExceptionBreakpointsRequestHandler.java | 49 ++----- .../java/debug/core/protocol/Requests.java | 17 +-- .../java/debug/core/protocol/Types.java | 136 +----------------- .../java/debug/core/AbstractJdiTestCase.java | 5 +- 13 files changed, 126 insertions(+), 324 deletions(-) diff --git a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/Breakpoint.java b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/Breakpoint.java index c6f0506c2..d8316c2e3 100644 --- a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/Breakpoint.java +++ b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/Breakpoint.java @@ -41,26 +41,29 @@ public class Breakpoint implements IBreakpoint { private int hitCount = 0; private String condition = null; private String logMessage = null; - private int suspendPolicy = BreakpointRequest.SUSPEND_EVENT_THREAD; private HashMap propertyMap = new HashMap<>(); + private final boolean suspendAllThreads; private boolean async = false; - Breakpoint(VirtualMachine vm, IEventHub eventHub, String className, int lineNumber) { - this(vm, eventHub, className, lineNumber, 0, null); + Breakpoint(VirtualMachine vm, IEventHub eventHub, String className, int lineNumber, boolean suspendAllThreads) { + this(vm, eventHub, className, lineNumber, 0, null, suspendAllThreads); } - Breakpoint(VirtualMachine vm, IEventHub eventHub, String className, int lineNumber, int hitCount) { - this(vm, eventHub, className, lineNumber, hitCount, null); + Breakpoint(VirtualMachine vm, IEventHub eventHub, String className, int lineNumber, int hitCount, boolean suspendAllThreads) { + this(vm, eventHub, className, lineNumber, hitCount, null, suspendAllThreads); } - Breakpoint(VirtualMachine vm, IEventHub eventHub, String className, int lineNumber, int hitCount, String condition) { - this(vm, eventHub, className, lineNumber, hitCount, condition, null); + Breakpoint(VirtualMachine vm, IEventHub eventHub, String className, int lineNumber, int hitCount, + String condition, boolean suspendAllThreads) { + this(vm, eventHub, className, lineNumber, hitCount, condition, null, suspendAllThreads); } - Breakpoint(VirtualMachine vm, IEventHub eventHub, String className, int lineNumber, int hitCount, String condition, String logMessage) { + Breakpoint(VirtualMachine vm, IEventHub eventHub, String className, int lineNumber, int hitCount, + String condition, String logMessage, boolean suspendAllThreads) { this.vm = vm; this.eventHub = eventHub; + this.suspendAllThreads = suspendAllThreads; String contextClass = className; String methodName = null; String methodSignature = null; @@ -80,13 +83,15 @@ public class Breakpoint implements IBreakpoint { this.logMessage = logMessage; } - Breakpoint(VirtualMachine vm, IEventHub eventHub, JavaBreakpointLocation sourceLocation, int hitCount, String condition, String logMessage) { + Breakpoint(VirtualMachine vm, IEventHub eventHub, JavaBreakpointLocation sourceLocation, int hitCount, + String condition, String logMessage, boolean suspendAllThreads) { this.vm = vm; this.eventHub = eventHub; this.sourceLocation = sourceLocation; this.hitCount = hitCount; this.condition = condition; this.logMessage = logMessage; + this.suspendAllThreads = suspendAllThreads; } // IDebugResource @@ -204,6 +209,19 @@ public void setAsync(boolean async) { this.async = async; } + @Override + public void setSuspendPolicy(String policy) { + } + + @Override + public String getSuspendPolicy() { + return suspendAllThreads ? "SUSPEND_ALL" : "SUSPEND_EVENT_THREAD"; + } + + protected boolean suspendAllThreads() { + return suspendAllThreads; + } + @Override public CompletableFuture install() { // It's possible that different class loaders create new class with the same name. @@ -413,7 +431,11 @@ private CompletableFuture> createBreakpointRequests(List newLocations.forEach(location -> { BreakpointRequest request = vm.eventRequestManager().createBreakpointRequest(location); - request.setSuspendPolicy(suspendPolicy); + if ("SUSPEND_ALL".equals(getSuspendPolicy())) { + request.setSuspendPolicy(BreakpointRequest.SUSPEND_ALL); + } else { + request.setSuspendPolicy(BreakpointRequest.SUSPEND_EVENT_THREAD); + } if (hitCount > 0) { request.addCountFilter(hitCount); } @@ -469,14 +491,4 @@ public void putProperty(Object key, Object value) { public Object getProperty(Object key) { return propertyMap.get(key); } - - @Override - public int getSuspendPolicy() { - return this.suspendPolicy; - } - - @Override - public void setSuspendPolicy(int suspendPolicy) { - this.suspendPolicy = suspendPolicy; - } -} \ No newline at end of file +} diff --git a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/DebugSession.java b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/DebugSession.java index 7c400d2e8..d5b8ceb47 100644 --- a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/DebugSession.java +++ b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/DebugSession.java @@ -36,9 +36,12 @@ public class DebugSession implements IDebugSession { private EventHub eventHub = new EventHub(); private List eventRequests = new ArrayList<>(); private List subscriptions = new ArrayList<>(); + private final boolean suspendAllThreads; public DebugSession(VirtualMachine virtualMachine) { vm = virtualMachine; + // Capture suspend policy at session start - this persists for the session lifetime + this.suspendAllThreads = DebugSettings.getCurrent().suspendAllThreads; } @Override @@ -127,36 +130,32 @@ public void terminate() { } @Override - public IBreakpoint createBreakpoint(JavaBreakpointLocation sourceLocation, int hitCount, String condition, String logMessage, int suspendPolicy) { - EvaluatableBreakpoint breakpoint = new EvaluatableBreakpoint(vm, this.getEventHub(), sourceLocation, hitCount, condition, logMessage); - breakpoint.setSuspendPolicy(suspendPolicy); - return breakpoint; + public IBreakpoint createBreakpoint(JavaBreakpointLocation sourceLocation, int hitCount, String condition, String logMessage) { + return new EvaluatableBreakpoint(vm, this.getEventHub(), sourceLocation, hitCount, condition, logMessage, suspendAllThreads); } @Override - public IBreakpoint createBreakpoint(String className, int lineNumber, int hitCount, String condition, String logMessage, int suspendPolicy) { - EvaluatableBreakpoint breakpoint = new EvaluatableBreakpoint(vm, this.getEventHub(), className, lineNumber, hitCount, condition, logMessage); - breakpoint.setSuspendPolicy(suspendPolicy); - return breakpoint; + public IBreakpoint createBreakpoint(String className, int lineNumber, int hitCount, String condition, String logMessage) { + return new EvaluatableBreakpoint(vm, this.getEventHub(), className, lineNumber, hitCount, condition, logMessage, suspendAllThreads); } @Override public IWatchpoint createWatchPoint(String className, String fieldName, String accessType, String condition, int hitCount) { - return new Watchpoint(vm, this.getEventHub(), className, fieldName, accessType, condition, hitCount); + return new Watchpoint(vm, this.getEventHub(), className, fieldName, accessType, condition, hitCount, suspendAllThreads); } @Override - public void setExceptionBreakpoints(boolean notifyCaught, boolean notifyUncaught, int suspendModeOnCaught, int suspendModeOnUncaught) { - setExceptionBreakpoints(notifyCaught, notifyUncaught, suspendModeOnCaught, suspendModeOnUncaught, null, null); + public void setExceptionBreakpoints(boolean notifyCaught, boolean notifyUncaught) { + setExceptionBreakpoints(notifyCaught, notifyUncaught, null, null); } @Override - public void setExceptionBreakpoints(boolean notifyCaught, boolean notifyUncaught, int suspendModeOnCaught, int suspendModeOnUncaught, String[] classFilters, String[] classExclusionFilters) { - setExceptionBreakpoints(notifyCaught, notifyUncaught, suspendModeOnCaught, suspendModeOnUncaught, null, classFilters, classExclusionFilters); + public void setExceptionBreakpoints(boolean notifyCaught, boolean notifyUncaught, String[] classFilters, String[] classExclusionFilters) { + setExceptionBreakpoints(notifyCaught, notifyUncaught, null, classFilters, classExclusionFilters); } @Override - public void setExceptionBreakpoints(boolean notifyCaught, boolean notifyUncaught, int suspendModeOnCaught, int suspendModeOnUncaught, String[] exceptionTypes, + public void setExceptionBreakpoints(boolean notifyCaught, boolean notifyUncaught, String[] exceptionTypes, String[] classFilters, String[] classExclusionFilters) { EventRequestManager manager = vm.eventRequestManager(); @@ -188,7 +187,19 @@ public void setExceptionBreakpoints(boolean notifyCaught, boolean notifyUncaught // See org.eclipse.debug.jdi.tests.AbstractJDITest for the example. if (exceptionTypes == null || exceptionTypes.length == 0) { - createExceptionBreakpoint(null, notifyCaught, notifyUncaught, suspendModeOnCaught, suspendModeOnUncaught, classFilters, classExclusionFilters); + ExceptionRequest request = manager.createExceptionRequest(null, notifyCaught, notifyUncaught); + request.setSuspendPolicy(suspendAllThreads ? EventRequest.SUSPEND_ALL : EventRequest.SUSPEND_EVENT_THREAD); + if (classFilters != null) { + for (String classFilter : classFilters) { + request.addClassFilter(classFilter); + } + } + if (classExclusionFilters != null) { + for (String exclusionFilter : classExclusionFilters) { + request.addClassExclusionFilter(exclusionFilter); + } + } + request.enable(); return; } @@ -208,27 +219,27 @@ public void setExceptionBreakpoints(boolean notifyCaught, boolean notifyUncaught && eventRequests.contains(debugEvent.event.request())) .subscribe(debugEvent -> { ClassPrepareEvent event = (ClassPrepareEvent) debugEvent.event; - createExceptionBreakpoint(event.referenceType(), notifyCaught, notifyUncaught, suspendModeOnCaught, suspendModeOnUncaught, classFilters, classExclusionFilters); + createExceptionBreakpoint(event.referenceType(), notifyCaught, notifyUncaught, classFilters, classExclusionFilters); }); subscriptions.add(subscription); // register exception breakpoint in the loaded classes. for (ReferenceType refType : vm.classesByName(exceptionType)) { - createExceptionBreakpoint(refType, notifyCaught, notifyUncaught, suspendModeOnCaught, suspendModeOnUncaught, classFilters, classExclusionFilters); + createExceptionBreakpoint(refType, notifyCaught, notifyUncaught, classFilters, classExclusionFilters); } } } } @Override - public void setExceptionBreakpoints(boolean notifyCaught, boolean notifyUncaught, int suspendModeOnCaught, int suspendModeOnUncaught, String[] exceptionTypes, + public void setExceptionBreakpoints(boolean notifyCaught, boolean notifyUncaught, String[] exceptionTypes, String[] classFilters, String[] classExclusionFilters, boolean async) { if (async) { AsyncJdwpUtils.runAsync(() -> { - setExceptionBreakpoints(notifyCaught, notifyUncaught, suspendModeOnCaught, suspendModeOnUncaught, exceptionTypes, classFilters, classExclusionFilters); + setExceptionBreakpoints(notifyCaught, notifyUncaught, exceptionTypes, classFilters, classExclusionFilters); }); } else { - setExceptionBreakpoints(notifyCaught, notifyUncaught, suspendModeOnCaught, suspendModeOnUncaught, exceptionTypes, classFilters, classExclusionFilters); + setExceptionBreakpoints(notifyCaught, notifyUncaught, exceptionTypes, classFilters, classExclusionFilters); } } @@ -253,26 +264,21 @@ public VirtualMachine getVM() { } @Override - public IMethodBreakpoint createFunctionBreakpoint(String className, String functionName, String condition, - int hitCount) { - return new MethodBreakpoint(vm, this.getEventHub(), className, functionName, condition, hitCount); + public boolean shouldSuspendAllThreads() { + return suspendAllThreads; } - private void createExceptionBreakpoint(ReferenceType refType, boolean notifyCaught, boolean notifyUncaught, - int suspendModeOnCaught, int suspendModeOnUncaught, String[] classFilters, String[] classExclusionFilters) { - if (suspendModeOnCaught == suspendModeOnUncaught) { - createExceptionBreakpoint(refType, notifyCaught, notifyUncaught, suspendModeOnCaught, classFilters, classExclusionFilters); - } else { - createExceptionBreakpoint(refType, notifyCaught, notifyUncaught, suspendModeOnCaught, classFilters, classExclusionFilters); - createExceptionBreakpoint(refType, notifyCaught, notifyUncaught, suspendModeOnUncaught, classFilters, classExclusionFilters); - } + @Override + public IMethodBreakpoint createFunctionBreakpoint(String className, String functionName, String condition, + int hitCount) { + return new MethodBreakpoint(vm, this.getEventHub(), className, functionName, condition, hitCount, suspendAllThreads); } private void createExceptionBreakpoint(ReferenceType refType, boolean notifyCaught, boolean notifyUncaught, - int suspendMode, String[] classFilters, String[] classExclusionFilters) { + String[] classFilters, String[] classExclusionFilters) { EventRequestManager manager = vm.eventRequestManager(); ExceptionRequest request = manager.createExceptionRequest(refType, notifyCaught, notifyUncaught); - request.setSuspendPolicy(suspendMode); + request.setSuspendPolicy(suspendAllThreads ? EventRequest.SUSPEND_ALL : EventRequest.SUSPEND_EVENT_THREAD); if (classFilters != null) { for (String classFilter : classFilters) { request.addClassFilter(classFilter); @@ -285,4 +291,4 @@ private void createExceptionBreakpoint(ReferenceType refType, boolean notifyCaug } request.enable(); } -} \ No newline at end of file +} diff --git a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/IBreakpoint.java b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/IBreakpoint.java index 7a0a585b8..ec3ea818a 100644 --- a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/IBreakpoint.java +++ b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/IBreakpoint.java @@ -49,14 +49,17 @@ public interface IBreakpoint extends IDebugResource { void setLogMessage(String logMessage); - int getSuspendPolicy(); - - void setSuspendPolicy(int suspendPolicy); - default void setAsync(boolean async) { } default boolean async() { return false; } -} \ No newline at end of file + + default void setSuspendPolicy(String policy) { + } + + default String getSuspendPolicy() { + return null; + } +} diff --git a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/IDebugSession.java b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/IDebugSession.java index a05589daf..afc2283f0 100644 --- a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/IDebugSession.java +++ b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/IDebugSession.java @@ -28,19 +28,19 @@ public interface IDebugSession { void terminate(); // breakpoints - IBreakpoint createBreakpoint(String className, int lineNumber, int hitCount, String condition, String logMessage, int suspendPolicy); + IBreakpoint createBreakpoint(String className, int lineNumber, int hitCount, String condition, String logMessage); - IBreakpoint createBreakpoint(JavaBreakpointLocation sourceLocation, int hitCount, String condition, String logMessage, int suspendPolicy); + IBreakpoint createBreakpoint(JavaBreakpointLocation sourceLocation, int hitCount, String condition, String logMessage); IWatchpoint createWatchPoint(String className, String fieldName, String accessType, String condition, int hitCount); - void setExceptionBreakpoints(boolean notifyCaught, boolean notifyUncaught, int suspendModeOnCaught, int suspendModeOnUncaught); + void setExceptionBreakpoints(boolean notifyCaught, boolean notifyUncaught); - void setExceptionBreakpoints(boolean notifyCaught, boolean notifyUncaught, int suspendModeOnCaught, int suspendModeOnUncaught, String[] classFilters, String[] classExclusionFilters); + void setExceptionBreakpoints(boolean notifyCaught, boolean notifyUncaught, String[] classFilters, String[] classExclusionFilters); - void setExceptionBreakpoints(boolean notifyCaught, boolean notifyUncaught, int suspendModeOnCaught, int suspendModeOnUncaught, String[] exceptionTypes, String[] classFilters, String[] classExclusionFilters); + void setExceptionBreakpoints(boolean notifyCaught, boolean notifyUncaught, String[] exceptionTypes, String[] classFilters, String[] classExclusionFilters); - void setExceptionBreakpoints(boolean notifyCaught, boolean notifyUncaught, int suspendModeOnCaught, int suspendModeOnUncaught, String[] exceptionTypes, String[] classFilters, String[] classExclusionFilters, + void setExceptionBreakpoints(boolean notifyCaught, boolean notifyUncaught, String[] exceptionTypes, String[] classFilters, String[] classExclusionFilters, boolean async); IMethodBreakpoint createFunctionBreakpoint(String className, String functionName, String condition, int hitCount); @@ -52,4 +52,10 @@ void setExceptionBreakpoints(boolean notifyCaught, boolean notifyUncaught, int s IEventHub getEventHub(); VirtualMachine getVM(); -} \ No newline at end of file + + /** + * Returns whether breakpoints should suspend all threads or just the event thread. + * This value is captured at session start and persists for the session lifetime. + */ + boolean shouldSuspendAllThreads(); +} diff --git a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/AdapterUtils.java b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/AdapterUtils.java index b4e1c3b88..c30aa8742 100644 --- a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/AdapterUtils.java +++ b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/AdapterUtils.java @@ -34,7 +34,6 @@ import com.microsoft.java.debug.core.DebugException; import com.microsoft.java.debug.core.protocol.Messages.Response; -import com.sun.jdi.request.EventRequest; import com.microsoft.java.debug.core.protocol.Responses; import com.microsoft.java.debug.core.protocol.Types; @@ -365,13 +364,4 @@ public static int[] binarySearchMappedLines(int[] lineMappings, int targetLine) return values; } - - public static int suspendPolicyFromBreakpointMode(String breakpointMode) { - if (Constants.SUSPEND_VM.equals(breakpointMode)) { - return EventRequest.SUSPEND_ALL; - } else if (Constants.SUSPEND_THREAD.equals(breakpointMode)) { - return EventRequest.SUSPEND_EVENT_THREAD; - } - return EventRequest.SUSPEND_EVENT_THREAD; - } -} \ No newline at end of file +} diff --git a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/Constants.java b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/Constants.java index 99ea77fdb..2e523aba2 100644 --- a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/Constants.java +++ b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/Constants.java @@ -15,8 +15,4 @@ public final class Constants { public static final String PROJECT_NAME = "projectName"; public static final String DEBUGGEE_ENCODING = "debuggeeEncoding"; public static final String MAIN_CLASS = "mainClass"; - - // Breakpoint suspend modes - public static final String SUSPEND_VM = "suspendVM"; - public static final String SUSPEND_THREAD = "suspendThread"; -} \ No newline at end of file +} diff --git a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/ConfigurationDoneRequestHandler.java b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/ConfigurationDoneRequestHandler.java index 8260fabb7..308adddb6 100644 --- a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/ConfigurationDoneRequestHandler.java +++ b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/ConfigurationDoneRequestHandler.java @@ -40,8 +40,8 @@ import com.sun.jdi.event.ThreadStartEvent; import com.sun.jdi.event.VMDeathEvent; import com.sun.jdi.event.VMDisconnectEvent; -import com.sun.jdi.event.VMStartEvent; import com.sun.jdi.request.EventRequest; +import com.sun.jdi.event.VMStartEvent; public class ConfigurationDoneRequestHandler implements IDebugRequestHandler { protected static final Logger logger = Logger.getLogger(Configuration.LOGGER_NAME); @@ -120,8 +120,9 @@ private void handleDebugEvent(DebugEvent debugEvent, IDebugSession debugSession, ((ExceptionEvent) event).catchLocation() == null); context.getExceptionManager().setException(thread.uniqueID(), jdiException); context.getThreadCache().addEventThread(thread, "exception"); - boolean suspendAll = event.request() != null ? event.request().suspendPolicy() == EventRequest.SUSPEND_ALL : false; - context.getProtocolServer().sendEvent(new Events.StoppedEvent("exception", thread.uniqueID(), suspendAll)); + boolean allThreadsStopped = event.request() != null + && event.request().suspendPolicy() == EventRequest.SUSPEND_ALL; + context.getProtocolServer().sendEvent(new Events.StoppedEvent("exception", thread.uniqueID(), allThreadsStopped)); debugEvent.shouldResume = false; } else { isImportantEvent = false; @@ -132,4 +133,4 @@ private void handleDebugEvent(DebugEvent debugEvent, IDebugSession debugSession, UsageDataSession.recordEvent(event); } } -} \ No newline at end of file +} diff --git a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/InitializeRequestHandler.java b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/InitializeRequestHandler.java index f13f6aeec..6b9245166 100644 --- a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/InitializeRequestHandler.java +++ b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/InitializeRequestHandler.java @@ -15,7 +15,6 @@ import java.util.List; import java.util.concurrent.CompletableFuture; -import com.microsoft.java.debug.core.adapter.Constants; import com.microsoft.java.debug.core.adapter.IDebugAdapterContext; import com.microsoft.java.debug.core.adapter.IDebugRequestHandler; import com.microsoft.java.debug.core.protocol.Messages; @@ -23,7 +22,6 @@ import com.microsoft.java.debug.core.protocol.Types; public class InitializeRequestHandler implements IDebugRequestHandler { - @Override public List getTargetCommands() { return Arrays.asList(Requests.Command.INITIALIZE); @@ -68,32 +66,8 @@ public CompletableFuture handle(Requests.Command command, Req caps.supportsClipboardContext = true; caps.supportsBreakpointLocationsRequest = true; caps.supportsStepInTargetsRequest = true; - - // Add breakpoint modes for suspend behavior - Types.BreakpointMode[] breakpointModes = { - new Types.BreakpointMode ( - Constants.SUSPEND_THREAD, - "Suspend Thread", - "Suspends only the thread that hit the breakpoint", - new Types.BreakpointModeApplicability[] { - Types.BreakpointModeApplicability.SOURCE - // data and function breakpoints are not supported by VS Code - // instruction breakpoints are not supported by this adapter - } - ), - new Types.BreakpointMode( - Constants.SUSPEND_VM, - "Suspend VM", - "Suspends the entire virtual machine when breakpoint is hit", - new Types.BreakpointModeApplicability[] { - Types.BreakpointModeApplicability.SOURCE } - ) - - }; - caps.breakpointModes = breakpointModes; - response.body = caps; context.setInitialized(true); return CompletableFuture.completedFuture(response); } -} \ No newline at end of file +} diff --git a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/SetBreakpointsRequestHandler.java b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/SetBreakpointsRequestHandler.java index ffb994878..0f171486e 100644 --- a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/SetBreakpointsRequestHandler.java +++ b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/SetBreakpointsRequestHandler.java @@ -134,19 +134,6 @@ public CompletableFuture handle(Command command, Arguments arguments, added[i].setCondition(toAdds[i].getCondition()); } - if (toAdds[i].getSuspendPolicy() != added[i].getSuspendPolicy()) { - added[i].setSuspendPolicy(toAdds[i].getSuspendPolicy()); - try { - added[i].close(); - added[i].install().thenAccept(bp -> { - Events.BreakpointEvent bpEvent = new Events.BreakpointEvent("changed", this.convertDebuggerBreakpointToClient(bp, context)); - context.getProtocolServer().sendEvent(bpEvent); - }); - } catch (Exception e) { - logger.log(Level.SEVERE, String.format("Close breakpoint exception: %s", e.toString()), e); - } - } - } res.add(this.convertDebuggerBreakpointToClient(added[i], context)); } @@ -213,7 +200,6 @@ private void registerBreakpointHandler(IDebugAdapterContext context) { // find the breakpoint related to this breakpoint event IBreakpoint expressionBP = getAssociatedEvaluatableBreakpoint(context, (BreakpointEvent) event); String breakpointName = computeBreakpointName(event.request()); - boolean suspendAll = event.request() != null ? event.request().suspendPolicy() == EventRequest.SUSPEND_ALL : false; if (expressionBP != null) { CompletableFuture.runAsync(() -> { @@ -226,14 +212,19 @@ private void registerBreakpointHandler(IDebugAdapterContext context) { debugEvent.eventSet.resume(); } else { context.getThreadCache().addEventThread(bpThread, breakpointName); - context.getProtocolServer().sendEvent(new Events.StoppedEvent(breakpointName, bpThread.uniqueID(), suspendAll)); + boolean allThreadsStopped = event.request() != null + && event.request().suspendPolicy() == EventRequest.SUSPEND_ALL; + context.getProtocolServer().sendEvent(new Events.StoppedEvent( + breakpointName, bpThread.uniqueID(), allThreadsStopped)); } }); }); } else { context.getThreadCache().addEventThread(bpThread, breakpointName); + boolean allThreadsStopped = event.request() != null + && event.request().suspendPolicy() == EventRequest.SUSPEND_ALL; context.getProtocolServer().sendEvent(new Events.StoppedEvent( - breakpointName, bpThread.uniqueID(), suspendAll)); + breakpointName, bpThread.uniqueID(), allThreadsStopped)); } debugEvent.shouldResume = false; } @@ -348,7 +339,7 @@ private IBreakpoint[] convertClientBreakpointsToDebugger(String sourceFile, Type } } breakpoints[i] = context.getDebugSession().createBreakpoint(locations[i], hitCount, sourceBreakpoints[i].condition, - sourceBreakpoints[i].logMessage, AdapterUtils.suspendPolicyFromBreakpointMode(sourceBreakpoints[i].mode)); + sourceBreakpoints[i].logMessage); if (sourceProvider.supportsRealtimeBreakpointVerification() && StringUtils.isNotBlank(locations[i].className())) { breakpoints[i].putProperty("verified", true); } @@ -376,4 +367,4 @@ private void reinstallBreakpoints(IDebugAdapterContext context, List typ } } } -} \ No newline at end of file +} diff --git a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/SetExceptionBreakpointsRequestHandler.java b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/SetExceptionBreakpointsRequestHandler.java index 252f43504..b51c5fe27 100644 --- a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/SetExceptionBreakpointsRequestHandler.java +++ b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/SetExceptionBreakpointsRequestHandler.java @@ -14,6 +14,9 @@ import java.util.Arrays; import java.util.List; import java.util.concurrent.CompletableFuture; + +import org.apache.commons.lang3.ArrayUtils; + import com.microsoft.java.debug.core.DebugSettings; import com.microsoft.java.debug.core.IDebugSession; import com.microsoft.java.debug.core.DebugSettings.IDebugSettingChangeListener; @@ -26,11 +29,9 @@ import com.microsoft.java.debug.core.protocol.Requests.Command; import com.microsoft.java.debug.core.protocol.Requests.ExceptionFilters; import com.microsoft.java.debug.core.protocol.Requests.SetExceptionBreakpointsArguments; -import com.microsoft.java.debug.core.protocol.Types.ExceptionFilterOptions; import com.microsoft.java.debug.core.protocol.Types; import com.sun.jdi.event.VMDeathEvent; import com.sun.jdi.event.VMDisconnectEvent; -import com.sun.jdi.request.EventRequest; public class SetExceptionBreakpointsRequestHandler implements IDebugRequestHandler, IDebugSettingChangeListener { private IDebugSession debugSession = null; @@ -38,8 +39,6 @@ public class SetExceptionBreakpointsRequestHandler implements IDebugRequestHandl private boolean notifyCaught = false; private boolean notifyUncaught = false; private boolean asyncJDWP = false; - private int suspendModeOnCaught; - private int suspendModeOnUncaught; @Override public List getTargetCommands() { @@ -64,38 +63,12 @@ public synchronized CompletableFuture handle(Command command, Argument } }); } - - SetExceptionBreakpointsArguments requestArgs = (SetExceptionBreakpointsArguments)arguments; - String[] filters = requestArgs.filters; + String[] filters = ((SetExceptionBreakpointsArguments) arguments).filters; try { - this.notifyCaught = false; - this.notifyUncaught = false; - if (filters != null) { - for (String filter : filters) { - if (filter.equals(Types.ExceptionBreakpointFilter.CAUGHT_EXCEPTION_FILTER_NAME)) { - this.notifyCaught = true; - } else if (filter.equals(Types.ExceptionBreakpointFilter.UNCAUGHT_EXCEPTION_FILTER_NAME)) { - this.notifyUncaught = true; - } - } - } - this.suspendModeOnCaught = EventRequest.SUSPEND_EVENT_THREAD; - this.suspendModeOnUncaught = EventRequest.SUSPEND_EVENT_THREAD; - - ExceptionFilterOptions[] filterOptions = requestArgs.filterOptions; - if (filterOptions != null) { - for (ExceptionFilterOptions filterOption : requestArgs.filterOptions) { - if (filterOption.filterId.equals(Types.ExceptionBreakpointFilter.CAUGHT_EXCEPTION_FILTER_NAME)) { - this.notifyCaught = true; - this.suspendModeOnCaught = AdapterUtils.suspendPolicyFromBreakpointMode(filterOption.mode); - } else if (filterOption.filterId.equals(Types.ExceptionBreakpointFilter.UNCAUGHT_EXCEPTION_FILTER_NAME)) { - this.notifyUncaught = true; - this.suspendModeOnUncaught = AdapterUtils.suspendPolicyFromBreakpointMode(filterOption.mode); - } - } - } - setExceptionBreakpoints(context.getDebugSession(), this.notifyCaught, this.notifyUncaught, suspendModeOnCaught, suspendModeOnUncaught); + this.notifyCaught = ArrayUtils.contains(filters, Types.ExceptionBreakpointFilter.CAUGHT_EXCEPTION_FILTER_NAME); + this.notifyUncaught = ArrayUtils.contains(filters, Types.ExceptionBreakpointFilter.UNCAUGHT_EXCEPTION_FILTER_NAME); + setExceptionBreakpoints(context.getDebugSession(), this.notifyCaught, this.notifyUncaught); return CompletableFuture.completedFuture(response); } catch (Exception ex) { throw AdapterUtils.createCompletionException( @@ -105,22 +78,22 @@ public synchronized CompletableFuture handle(Command command, Argument } } - private void setExceptionBreakpoints(IDebugSession debugSession, boolean notifyCaught, boolean notifyUncaught, int suspendModeOnCaught, int suspendModeOnUncaught) { + private void setExceptionBreakpoints(IDebugSession debugSession, boolean notifyCaught, boolean notifyUncaught) { ExceptionFilters exceptionFilters = DebugSettings.getCurrent().exceptionFilters; String[] exceptionTypes = (exceptionFilters == null ? null : exceptionFilters.exceptionTypes); String[] classFilters = (exceptionFilters == null ? null : exceptionFilters.allowClasses); String[] classExclusionFilters = (exceptionFilters == null ? null : exceptionFilters.skipClasses); - debugSession.setExceptionBreakpoints(notifyCaught, notifyUncaught, suspendModeOnCaught, suspendModeOnUncaught, exceptionTypes, classFilters, classExclusionFilters, this.asyncJDWP); + debugSession.setExceptionBreakpoints(notifyCaught, notifyUncaught, exceptionTypes, classFilters, classExclusionFilters, this.asyncJDWP); } @Override public synchronized void update(DebugSettings oldSettings, DebugSettings newSettings) { try { if (newSettings != null && newSettings.exceptionFiltersUpdated) { - setExceptionBreakpoints(debugSession, notifyCaught, notifyUncaught, suspendModeOnCaught, suspendModeOnUncaught); + setExceptionBreakpoints(debugSession, notifyCaught, notifyUncaught); } } catch (Exception ex) { DebugSettings.removeDebugSettingChangeListener(this); } } -} \ No newline at end of file +} diff --git a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/protocol/Requests.java b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/protocol/Requests.java index a517b48ec..1129d230e 100644 --- a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/protocol/Requests.java +++ b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/protocol/Requests.java @@ -17,8 +17,6 @@ import com.google.gson.annotations.SerializedName; import com.microsoft.java.debug.core.protocol.Types.DataBreakpoint; -import com.microsoft.java.debug.core.protocol.Types.ExceptionFilterOptions; -import com.microsoft.java.debug.core.protocol.Types.ExceptionOptions; import com.microsoft.java.debug.core.protocol.Types.Source; /** @@ -252,19 +250,6 @@ public static class SetFunctionBreakpointsArguments extends Arguments { public static class SetExceptionBreakpointsArguments extends Arguments { public String[] filters = new String[0]; - /** - * Set of exception filters and their options. The set of all possible - * exception filters is defined by the `exceptionBreakpointFilters` - * capability. This attribute is only honored by a debug adapter if the - * corresponding capability `supportsExceptionFilterOptions` is true. The - * `filter` and `filterOptions` sets are additive. - */ - public ExceptionFilterOptions[] filterOptions; - - /** - * Configuration options for selected exceptions. The attribute is only honored by a debug adapter if the corresponding capability `supportsExceptionOptions` is true. - */ - public ExceptionOptions[] exceptionOptions; } public static class ExceptionInfoArguments extends Arguments { @@ -530,4 +515,4 @@ public static Command parse(String command) { return UNSUPPORTED; } } -} \ No newline at end of file +} diff --git a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/protocol/Types.java b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/protocol/Types.java index c2da98ae9..33308af6d 100644 --- a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/protocol/Types.java +++ b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/protocol/Types.java @@ -209,7 +209,6 @@ public static class SourceBreakpoint { public String hitCondition; public String condition; public String logMessage; - public String mode; public SourceBreakpoint(int line, int column) { this.line = line; @@ -234,14 +233,6 @@ public SourceBreakpoint(int line, String condition, String hitCondition, int col this.condition = condition; this.hitCondition = hitCondition; } - - public SourceBreakpoint(int line, String condition, String hitCondition, int column, String mode) { - this.line = line; - this.column = column; - this.condition = condition; - this.hitCondition = hitCondition; - this.mode = mode; - } } public static class FunctionBreakpoint { @@ -423,130 +414,6 @@ public VariablePresentationHint(boolean lazy) { } } - /** - * An ExceptionPathSegment represents a segment in a path that is used to match leafs or nodes in a tree of exceptions. - * If a segment consists of more than one name, it matches the names provided if negate is false or missing, - * or it matches anything except the names provided if negate is true. - */ - public static class ExceptionPathSegment { - /** - * If false or missing this segment matches the names provided, otherwise it matches anything except the names provided. - */ - public boolean negate; - - /** - * Depending on the value of negate the names that should match or not match. - */ - public String[] names; - - public ExceptionPathSegment() { - } - - public ExceptionPathSegment(boolean negate, String[] names) { - this.negate = negate; - this.names = names; - } - } - - /** - * An ExceptionOptions assigns configuration options to a set of exceptions. - */ - public static class ExceptionOptions { - /** - * A path that selects a single or multiple exceptions in a tree. If path is missing, the whole tree is selected. - * By convention the first segment of the path is a category that is used to group exceptions in the UI. - */ - public ExceptionPathSegment[] path; - - /** - * Condition when a thrown exception should result in a break. - */ - public ExceptionBreakMode breakMode; - - public ExceptionOptions() { - } - - public ExceptionOptions(ExceptionPathSegment[] path, ExceptionBreakMode breakMode) { - this.path = path; - this.breakMode = breakMode; - } - } - - /** - * An ExceptionFilterOptions is used to specify an exception filter together with its options. - */ - public static class ExceptionFilterOptions { - /** - * ID of an exception filter returned by the exceptionBreakpointFilters capability. - */ - public String filterId; - - /** - * An expression for conditional exceptions. The exception breaks into the debugger if the result of the condition is true. - */ - public String condition; - - /** - * The mode of this exception breakpoint. If defined, this must be one of the breakpointModes the debug adapter advertised in its Capabilities. - */ - public String mode; - - public ExceptionFilterOptions() { - } - - public ExceptionFilterOptions(String filterId) { - this.filterId = filterId; - } - - public ExceptionFilterOptions(String filterId, String condition, String mode) { - this.filterId = filterId; - this.condition = condition; - this.mode = mode; - } - } - - public static enum BreakpointModeApplicability { - @SerializedName("source") - SOURCE, - @SerializedName("exception") - EXCEPTION, - @SerializedName("data") - DATA, - @SerializedName("instruction") - INSTRUCTION, - } - - public static class BreakpointMode { - public BreakpointMode(String mode, String label, String description, BreakpointModeApplicability[] appliesTo) { - this.mode = mode; - this.label = label; - this.description = description; - this.appliesTo = appliesTo; - } - /** - * The internal ID of the mode. This value is passed to the `setBreakpoints` - * request. - */ - public String mode; - - /** - * The name of the breakpoint mode. This is shown in the UI. - */ - public String label; - - /** - * A help text providing additional information about the breakpoint mode. - * This string is typically shown as a hover and can be translated. - */ - public String description; - - /** - * Describes one or more type of breakpoint this mode applies to. - */ - public BreakpointModeApplicability[] appliesTo; - } - - public static class Capabilities { public boolean supportsConfigurationDoneRequest; public boolean supportsHitConditionalBreakpoints; @@ -567,7 +434,6 @@ public static class Capabilities { // https://microsoft.github.io/debug-adapter-protocol/specification#Requests_BreakpointLocations public boolean supportsBreakpointLocationsRequest; public boolean supportsStepInTargetsRequest; - public BreakpointMode[] breakpointModes; } public static class StepInTarget { @@ -584,4 +450,4 @@ public StepInTarget(int id, String label) { } } -} \ No newline at end of file +} diff --git a/com.microsoft.java.debug.core/src/test/java/com/microsoft/java/debug/core/AbstractJdiTestCase.java b/com.microsoft.java.debug.core/src/test/java/com/microsoft/java/debug/core/AbstractJdiTestCase.java index 596a619a7..4d0a122a5 100644 --- a/com.microsoft.java.debug.core/src/test/java/com/microsoft/java/debug/core/AbstractJdiTestCase.java +++ b/com.microsoft.java.debug.core/src/test/java/com/microsoft/java/debug/core/AbstractJdiTestCase.java @@ -22,7 +22,6 @@ import com.sun.jdi.Value; import com.sun.jdi.VirtualMachine; import com.sun.jdi.event.BreakpointEvent; -import com.sun.jdi.request.EventRequest; public abstract class AbstractJdiTestCase extends EasyMockSupport { private static int TEST_TIME_OUT = 1000 * 10; @@ -39,7 +38,7 @@ protected BreakpointEvent waitForBreakPointEvent(String breakpointAtClass, int l } IDebugSession debugSession = getCurrentDebugSession(); - IBreakpoint breakpointToAdd = debugSession.createBreakpoint(breakpointAtClass, line, 0, null, null, EventRequest.SUSPEND_EVENT_THREAD); + IBreakpoint breakpointToAdd = debugSession.createBreakpoint(breakpointAtClass, line, 0, null, null); breakpointToAdd.install().thenAccept(t -> { System.out.println("Breakpoint is accepted."); }); @@ -109,4 +108,4 @@ protected StackFrame getSecondLevelStackFrame() { } protected abstract IDebugSession getCurrentDebugSession(); -} \ No newline at end of file +} From 02ea1e448169856bc90a4fd8114ec22d498ee43a Mon Sep 17 00:00:00 2001 From: Stan185 <57770977+Stan185@users.noreply.github.com> Date: Mon, 2 Feb 2026 14:54:44 +0100 Subject: [PATCH 3/3] Revert to previous state --- com.microsoft.java.debug.core/.classpath | 15 ++++++- .../microsoft/java/debug/core/Breakpoint.java | 41 ++++--------------- .../java/debug/core/DebugSession.java | 20 +++------ .../java/debug/core/DebugSettings.java | 1 - .../java/debug/core/DebugUtility.java | 3 +- .../debug/core/EvaluatableBreakpoint.java | 20 ++++----- .../java/debug/core/IBreakpoint.java | 7 ---- .../java/debug/core/IDebugSession.java | 6 --- .../java/debug/core/MethodBreakpoint.java | 6 +-- .../microsoft/java/debug/core/Watchpoint.java | 15 +++---- .../ConfigurationDoneRequestHandler.java | 5 +-- .../adapter/handler/RestartFrameHandler.java | 4 +- .../handler/SetBreakpointsRequestHandler.java | 8 +--- .../SetDataBreakpointsRequestHandler.java | 9 +--- .../SetFunctionBreakpointsRequestHandler.java | 9 +--- .../handler/ThreadsRequestHandler.java | 5 --- 16 files changed, 56 insertions(+), 118 deletions(-) diff --git a/com.microsoft.java.debug.core/.classpath b/com.microsoft.java.debug.core/.classpath index b6fe6b96c..b3a434205 100644 --- a/com.microsoft.java.debug.core/.classpath +++ b/com.microsoft.java.debug.core/.classpath @@ -13,7 +13,7 @@ - + @@ -31,6 +31,19 @@ + + + + + + + + + + + + + diff --git a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/Breakpoint.java b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/Breakpoint.java index d8316c2e3..82859b268 100644 --- a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/Breakpoint.java +++ b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/Breakpoint.java @@ -42,28 +42,24 @@ public class Breakpoint implements IBreakpoint { private String condition = null; private String logMessage = null; private HashMap propertyMap = new HashMap<>(); - private final boolean suspendAllThreads; private boolean async = false; - Breakpoint(VirtualMachine vm, IEventHub eventHub, String className, int lineNumber, boolean suspendAllThreads) { - this(vm, eventHub, className, lineNumber, 0, null, suspendAllThreads); + Breakpoint(VirtualMachine vm, IEventHub eventHub, String className, int lineNumber) { + this(vm, eventHub, className, lineNumber, 0, null); } - Breakpoint(VirtualMachine vm, IEventHub eventHub, String className, int lineNumber, int hitCount, boolean suspendAllThreads) { - this(vm, eventHub, className, lineNumber, hitCount, null, suspendAllThreads); + Breakpoint(VirtualMachine vm, IEventHub eventHub, String className, int lineNumber, int hitCount) { + this(vm, eventHub, className, lineNumber, hitCount, null); } - Breakpoint(VirtualMachine vm, IEventHub eventHub, String className, int lineNumber, int hitCount, - String condition, boolean suspendAllThreads) { - this(vm, eventHub, className, lineNumber, hitCount, condition, null, suspendAllThreads); + Breakpoint(VirtualMachine vm, IEventHub eventHub, String className, int lineNumber, int hitCount, String condition) { + this(vm, eventHub, className, lineNumber, hitCount, condition, null); } - Breakpoint(VirtualMachine vm, IEventHub eventHub, String className, int lineNumber, int hitCount, - String condition, String logMessage, boolean suspendAllThreads) { + Breakpoint(VirtualMachine vm, IEventHub eventHub, String className, int lineNumber, int hitCount, String condition, String logMessage) { this.vm = vm; this.eventHub = eventHub; - this.suspendAllThreads = suspendAllThreads; String contextClass = className; String methodName = null; String methodSignature = null; @@ -83,15 +79,13 @@ public class Breakpoint implements IBreakpoint { this.logMessage = logMessage; } - Breakpoint(VirtualMachine vm, IEventHub eventHub, JavaBreakpointLocation sourceLocation, int hitCount, - String condition, String logMessage, boolean suspendAllThreads) { + Breakpoint(VirtualMachine vm, IEventHub eventHub, JavaBreakpointLocation sourceLocation, int hitCount, String condition, String logMessage) { this.vm = vm; this.eventHub = eventHub; this.sourceLocation = sourceLocation; this.hitCount = hitCount; this.condition = condition; this.logMessage = logMessage; - this.suspendAllThreads = suspendAllThreads; } // IDebugResource @@ -209,19 +203,6 @@ public void setAsync(boolean async) { this.async = async; } - @Override - public void setSuspendPolicy(String policy) { - } - - @Override - public String getSuspendPolicy() { - return suspendAllThreads ? "SUSPEND_ALL" : "SUSPEND_EVENT_THREAD"; - } - - protected boolean suspendAllThreads() { - return suspendAllThreads; - } - @Override public CompletableFuture install() { // It's possible that different class loaders create new class with the same name. @@ -431,11 +412,7 @@ private CompletableFuture> createBreakpointRequests(List newLocations.forEach(location -> { BreakpointRequest request = vm.eventRequestManager().createBreakpointRequest(location); - if ("SUSPEND_ALL".equals(getSuspendPolicy())) { - request.setSuspendPolicy(BreakpointRequest.SUSPEND_ALL); - } else { - request.setSuspendPolicy(BreakpointRequest.SUSPEND_EVENT_THREAD); - } + request.setSuspendPolicy(BreakpointRequest.SUSPEND_EVENT_THREAD); if (hitCount > 0) { request.addCountFilter(hitCount); } diff --git a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/DebugSession.java b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/DebugSession.java index d5b8ceb47..38a234fa9 100644 --- a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/DebugSession.java +++ b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/DebugSession.java @@ -36,12 +36,9 @@ public class DebugSession implements IDebugSession { private EventHub eventHub = new EventHub(); private List eventRequests = new ArrayList<>(); private List subscriptions = new ArrayList<>(); - private final boolean suspendAllThreads; public DebugSession(VirtualMachine virtualMachine) { vm = virtualMachine; - // Capture suspend policy at session start - this persists for the session lifetime - this.suspendAllThreads = DebugSettings.getCurrent().suspendAllThreads; } @Override @@ -131,17 +128,17 @@ public void terminate() { @Override public IBreakpoint createBreakpoint(JavaBreakpointLocation sourceLocation, int hitCount, String condition, String logMessage) { - return new EvaluatableBreakpoint(vm, this.getEventHub(), sourceLocation, hitCount, condition, logMessage, suspendAllThreads); + return new EvaluatableBreakpoint(vm, this.getEventHub(), sourceLocation, hitCount, condition, logMessage); } @Override public IBreakpoint createBreakpoint(String className, int lineNumber, int hitCount, String condition, String logMessage) { - return new EvaluatableBreakpoint(vm, this.getEventHub(), className, lineNumber, hitCount, condition, logMessage, suspendAllThreads); + return new EvaluatableBreakpoint(vm, this.getEventHub(), className, lineNumber, hitCount, condition, logMessage); } @Override public IWatchpoint createWatchPoint(String className, String fieldName, String accessType, String condition, int hitCount) { - return new Watchpoint(vm, this.getEventHub(), className, fieldName, accessType, condition, hitCount, suspendAllThreads); + return new Watchpoint(vm, this.getEventHub(), className, fieldName, accessType, condition, hitCount); } @Override @@ -188,7 +185,7 @@ public void setExceptionBreakpoints(boolean notifyCaught, boolean notifyUncaught if (exceptionTypes == null || exceptionTypes.length == 0) { ExceptionRequest request = manager.createExceptionRequest(null, notifyCaught, notifyUncaught); - request.setSuspendPolicy(suspendAllThreads ? EventRequest.SUSPEND_ALL : EventRequest.SUSPEND_EVENT_THREAD); + request.setSuspendPolicy(EventRequest.SUSPEND_EVENT_THREAD); if (classFilters != null) { for (String classFilter : classFilters) { request.addClassFilter(classFilter); @@ -263,22 +260,17 @@ public VirtualMachine getVM() { return vm; } - @Override - public boolean shouldSuspendAllThreads() { - return suspendAllThreads; - } - @Override public IMethodBreakpoint createFunctionBreakpoint(String className, String functionName, String condition, int hitCount) { - return new MethodBreakpoint(vm, this.getEventHub(), className, functionName, condition, hitCount, suspendAllThreads); + return new MethodBreakpoint(vm, this.getEventHub(), className, functionName, condition, hitCount); } private void createExceptionBreakpoint(ReferenceType refType, boolean notifyCaught, boolean notifyUncaught, String[] classFilters, String[] classExclusionFilters) { EventRequestManager manager = vm.eventRequestManager(); ExceptionRequest request = manager.createExceptionRequest(refType, notifyCaught, notifyUncaught); - request.setSuspendPolicy(suspendAllThreads ? EventRequest.SUSPEND_ALL : EventRequest.SUSPEND_EVENT_THREAD); + request.setSuspendPolicy(EventRequest.SUSPEND_EVENT_THREAD); if (classFilters != null) { for (String classFilter : classFilters) { request.addClassFilter(classFilter); diff --git a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/DebugSettings.java b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/DebugSettings.java index b422f6801..0a3e05ec8 100644 --- a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/DebugSettings.java +++ b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/DebugSettings.java @@ -45,7 +45,6 @@ public final class DebugSettings { public int jdwpRequestTimeout = 3000; public AsyncMode asyncJDWP = AsyncMode.OFF; public Switch debugSupportOnDecompiledSource = Switch.OFF; - public boolean suspendAllThreads = false; public static DebugSettings getCurrent() { return current; diff --git a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/DebugUtility.java b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/DebugUtility.java index 8a31792f0..4a2a49e9b 100644 --- a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/DebugUtility.java +++ b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/DebugUtility.java @@ -394,7 +394,6 @@ private static StepRequest createStepRequest(ThreadReference thread, int stepSiz request.addClassExclusionFilter(exclusionFilter); } } - // Note: suspend policy will be set by the caller (StepRequestHandler) based on session settings request.setSuspendPolicy(EventRequest.SUSPEND_EVENT_THREAD); request.addCountFilter(1); @@ -416,7 +415,7 @@ public static CompletableFuture stopOnEntry(IDebugSession debugSession, St EventRequestManager manager = debugSession.getVM().eventRequestManager(); MethodEntryRequest request = manager.createMethodEntryRequest(); request.addClassFilter(mainClass); - request.setSuspendPolicy(debugSession.shouldSuspendAllThreads() ? EventRequest.SUSPEND_ALL : EventRequest.SUSPEND_EVENT_THREAD); + request.setSuspendPolicy(EventRequest.SUSPEND_EVENT_THREAD); debugSession.getEventHub().events().filter(debugEvent -> { return debugEvent.event instanceof MethodEntryEvent && request.equals(debugEvent.event.request()); diff --git a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/EvaluatableBreakpoint.java b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/EvaluatableBreakpoint.java index d5a909f0b..723e2cadf 100644 --- a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/EvaluatableBreakpoint.java +++ b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/EvaluatableBreakpoint.java @@ -29,28 +29,28 @@ public class EvaluatableBreakpoint extends Breakpoint implements IEvaluatableBre private Object compiledLogpointExpression = null; private Map compiledExpressions = new ConcurrentHashMap<>(); - EvaluatableBreakpoint(VirtualMachine vm, IEventHub eventHub, String className, int lineNumber, boolean suspendAllThreads) { - this(vm, eventHub, className, lineNumber, 0, null, suspendAllThreads); + EvaluatableBreakpoint(VirtualMachine vm, IEventHub eventHub, String className, int lineNumber) { + this(vm, eventHub, className, lineNumber, 0, null); } - EvaluatableBreakpoint(VirtualMachine vm, IEventHub eventHub, String className, int lineNumber, int hitCount, boolean suspendAllThreads) { - this(vm, eventHub, className, lineNumber, hitCount, null, suspendAllThreads); + EvaluatableBreakpoint(VirtualMachine vm, IEventHub eventHub, String className, int lineNumber, int hitCount) { + this(vm, eventHub, className, lineNumber, hitCount, null); } EvaluatableBreakpoint(VirtualMachine vm, IEventHub eventHub, String className, int lineNumber, int hitCount, - String condition, boolean suspendAllThreads) { - this(vm, eventHub, className, lineNumber, hitCount, condition, null, suspendAllThreads); + String condition) { + this(vm, eventHub, className, lineNumber, hitCount, condition, null); } EvaluatableBreakpoint(VirtualMachine vm, IEventHub eventHub, String className, int lineNumber, int hitCount, - String condition, String logMessage, boolean suspendAllThreads) { - super(vm, eventHub, className, lineNumber, hitCount, condition, logMessage, suspendAllThreads); + String condition, String logMessage) { + super(vm, eventHub, className, lineNumber, hitCount, condition, logMessage); this.eventHub = eventHub; } EvaluatableBreakpoint(VirtualMachine vm, IEventHub eventHub, JavaBreakpointLocation sourceLocation, int hitCount, - String condition, String logMessage, boolean suspendAllThreads) { - super(vm, eventHub, sourceLocation, hitCount, condition, logMessage, suspendAllThreads); + String condition, String logMessage) { + super(vm, eventHub, sourceLocation, hitCount, condition, logMessage); this.eventHub = eventHub; } diff --git a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/IBreakpoint.java b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/IBreakpoint.java index ec3ea818a..40995e9dd 100644 --- a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/IBreakpoint.java +++ b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/IBreakpoint.java @@ -55,11 +55,4 @@ default void setAsync(boolean async) { default boolean async() { return false; } - - default void setSuspendPolicy(String policy) { - } - - default String getSuspendPolicy() { - return null; - } } diff --git a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/IDebugSession.java b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/IDebugSession.java index afc2283f0..6cc3f3a46 100644 --- a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/IDebugSession.java +++ b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/IDebugSession.java @@ -52,10 +52,4 @@ void setExceptionBreakpoints(boolean notifyCaught, boolean notifyUncaught, Strin IEventHub getEventHub(); VirtualMachine getVM(); - - /** - * Returns whether breakpoints should suspend all threads or just the event thread. - * This value is captured at session start and persists for the session lifetime. - */ - boolean shouldSuspendAllThreads(); } diff --git a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/MethodBreakpoint.java b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/MethodBreakpoint.java index bc46fd96f..7a6e74c6b 100644 --- a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/MethodBreakpoint.java +++ b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/MethodBreakpoint.java @@ -44,7 +44,6 @@ public class MethodBreakpoint implements IMethodBreakpoint, IEvaluatableBreakpoi private String condition; private int hitCount; private boolean async = false; - private final boolean suspendAllThreads; private HashMap propertyMap = new HashMap<>(); private Object compiledConditionalExpression = null; @@ -54,7 +53,7 @@ public class MethodBreakpoint implements IMethodBreakpoint, IEvaluatableBreakpoi private List subscriptions = new ArrayList<>(); public MethodBreakpoint(VirtualMachine vm, IEventHub eventHub, String className, String functionName, - String condition, int hitCount, boolean suspendAllThreads) { + String condition, int hitCount) { Objects.requireNonNull(vm); Objects.requireNonNull(eventHub); Objects.requireNonNull(className); @@ -65,7 +64,6 @@ public MethodBreakpoint(VirtualMachine vm, IEventHub eventHub, String className, this.functionName = functionName; this.condition = condition; this.hitCount = hitCount; - this.suspendAllThreads = suspendAllThreads; } @Override @@ -264,7 +262,7 @@ private Optional createMethodEntryRequest0(ReferenceType typ MethodEntryRequest request = vm.eventRequestManager().createMethodEntryRequest(); request.addClassFilter(type); - request.setSuspendPolicy(suspendAllThreads ? EventRequest.SUSPEND_ALL : EventRequest.SUSPEND_EVENT_THREAD); + request.setSuspendPolicy(EventRequest.SUSPEND_EVENT_THREAD); if (hitCount > 0) { request.addCountFilter(hitCount); } diff --git a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/Watchpoint.java b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/Watchpoint.java index fdb2354a9..3de321ec8 100644 --- a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/Watchpoint.java +++ b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/Watchpoint.java @@ -46,22 +46,20 @@ public class Watchpoint implements IWatchpoint, IEvaluatableBreakpoint { private HashMap propertyMap = new HashMap<>(); private Object compiledConditionalExpression = null; private Map compiledExpressions = new ConcurrentHashMap<>(); - private final boolean suspendAllThreads; // IDebugResource private List requests = new ArrayList<>(); private List subscriptions = new ArrayList<>(); - Watchpoint(VirtualMachine vm, IEventHub eventHub, String className, String fieldName, boolean suspendAllThreads) { - this(vm, eventHub, className, fieldName, "write", suspendAllThreads); + Watchpoint(VirtualMachine vm, IEventHub eventHub, String className, String fieldName) { + this(vm, eventHub, className, fieldName, "write"); } - Watchpoint(VirtualMachine vm, IEventHub eventHub, String className, String fieldName, String accessType, boolean suspendAllThreads) { - this(vm, eventHub, className, fieldName, accessType, null, 0, suspendAllThreads); + Watchpoint(VirtualMachine vm, IEventHub eventHub, String className, String fieldName, String accessType) { + this(vm, eventHub, className, fieldName, accessType, null, 0); } - Watchpoint(VirtualMachine vm, IEventHub eventHub, String className, String fieldName, String accessType, - String condition, int hitCount, boolean suspendAllThreads) { + Watchpoint(VirtualMachine vm, IEventHub eventHub, String className, String fieldName, String accessType, String condition, int hitCount) { Objects.requireNonNull(vm); Objects.requireNonNull(eventHub); Objects.requireNonNull(className); @@ -73,7 +71,6 @@ public class Watchpoint implements IWatchpoint, IEvaluatableBreakpoint { this.accessType = accessType; this.condition = condition; this.hitCount = hitCount; - this.suspendAllThreads = suspendAllThreads; } @Override @@ -215,7 +212,7 @@ private List createWatchpointRequests(ReferenceType type) { } watchpointRequests.forEach(request -> { - request.setSuspendPolicy(suspendAllThreads ? EventRequest.SUSPEND_ALL : EventRequest.SUSPEND_EVENT_THREAD); + request.setSuspendPolicy(WatchpointRequest.SUSPEND_EVENT_THREAD); if (hitCount > 0) { request.addCountFilter(hitCount); } diff --git a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/ConfigurationDoneRequestHandler.java b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/ConfigurationDoneRequestHandler.java index 308adddb6..1c543bce4 100644 --- a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/ConfigurationDoneRequestHandler.java +++ b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/ConfigurationDoneRequestHandler.java @@ -40,7 +40,6 @@ import com.sun.jdi.event.ThreadStartEvent; import com.sun.jdi.event.VMDeathEvent; import com.sun.jdi.event.VMDisconnectEvent; -import com.sun.jdi.request.EventRequest; import com.sun.jdi.event.VMStartEvent; public class ConfigurationDoneRequestHandler implements IDebugRequestHandler { @@ -120,9 +119,7 @@ private void handleDebugEvent(DebugEvent debugEvent, IDebugSession debugSession, ((ExceptionEvent) event).catchLocation() == null); context.getExceptionManager().setException(thread.uniqueID(), jdiException); context.getThreadCache().addEventThread(thread, "exception"); - boolean allThreadsStopped = event.request() != null - && event.request().suspendPolicy() == EventRequest.SUSPEND_ALL; - context.getProtocolServer().sendEvent(new Events.StoppedEvent("exception", thread.uniqueID(), allThreadsStopped)); + context.getProtocolServer().sendEvent(new Events.StoppedEvent("exception", thread.uniqueID())); debugEvent.shouldResume = false; } else { isImportantEvent = false; diff --git a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/RestartFrameHandler.java b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/RestartFrameHandler.java index 26ebefaee..164909656 100644 --- a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/RestartFrameHandler.java +++ b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/RestartFrameHandler.java @@ -33,7 +33,6 @@ import com.sun.jdi.IncompatibleThreadStateException; import com.sun.jdi.StackFrame; import com.sun.jdi.ThreadReference; -import com.sun.jdi.request.EventRequest; import com.sun.jdi.request.StepRequest; /** @@ -122,8 +121,7 @@ private void stepInto(IDebugAdapterContext context, ThreadReference thread) { debugEvent.shouldResume = false; // Have to send two events to keep the UI sync with the step in operations: context.getProtocolServer().sendEvent(new Events.ContinuedEvent(thread.uniqueID())); - boolean allThreadsStopped = request.suspendPolicy() == EventRequest.SUSPEND_ALL; - context.getProtocolServer().sendEvent(new Events.StoppedEvent("restartframe", thread.uniqueID(), allThreadsStopped)); + context.getProtocolServer().sendEvent(new Events.StoppedEvent("restartframe", thread.uniqueID())); context.getThreadCache().setThreadStoppedReason(thread.uniqueID(), "restartframe"); }); request.enable(); diff --git a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/SetBreakpointsRequestHandler.java b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/SetBreakpointsRequestHandler.java index 0f171486e..09dafd1b0 100644 --- a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/SetBreakpointsRequestHandler.java +++ b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/SetBreakpointsRequestHandler.java @@ -212,19 +212,15 @@ private void registerBreakpointHandler(IDebugAdapterContext context) { debugEvent.eventSet.resume(); } else { context.getThreadCache().addEventThread(bpThread, breakpointName); - boolean allThreadsStopped = event.request() != null - && event.request().suspendPolicy() == EventRequest.SUSPEND_ALL; context.getProtocolServer().sendEvent(new Events.StoppedEvent( - breakpointName, bpThread.uniqueID(), allThreadsStopped)); + breakpointName, bpThread.uniqueID())); } }); }); } else { context.getThreadCache().addEventThread(bpThread, breakpointName); - boolean allThreadsStopped = event.request() != null - && event.request().suspendPolicy() == EventRequest.SUSPEND_ALL; context.getProtocolServer().sendEvent(new Events.StoppedEvent( - breakpointName, bpThread.uniqueID(), allThreadsStopped)); + breakpointName, bpThread.uniqueID())); } debugEvent.shouldResume = false; } diff --git a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/SetDataBreakpointsRequestHandler.java b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/SetDataBreakpointsRequestHandler.java index c7c0995fe..373b1c31b 100644 --- a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/SetDataBreakpointsRequestHandler.java +++ b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/SetDataBreakpointsRequestHandler.java @@ -41,7 +41,6 @@ import com.sun.jdi.ThreadReference; import com.sun.jdi.event.Event; import com.sun.jdi.event.WatchpointEvent; -import com.sun.jdi.request.EventRequest; public class SetDataBreakpointsRequestHandler implements IDebugRequestHandler { private boolean registered = false; @@ -153,17 +152,13 @@ private void registerWatchpointHandler(IDebugAdapterContext context) { debugEvent.eventSet.resume(); } else { context.getThreadCache().addEventThread(bpThread, "data breakpoint"); - boolean allThreadsStopped = event.request() != null - && event.request().suspendPolicy() == EventRequest.SUSPEND_ALL; - context.getProtocolServer().sendEvent(new Events.StoppedEvent("data breakpoint", bpThread.uniqueID(), allThreadsStopped)); + context.getProtocolServer().sendEvent(new Events.StoppedEvent("data breakpoint", bpThread.uniqueID())); } }); }); } else { context.getThreadCache().addEventThread(bpThread, "data breakpoint"); - boolean allThreadsStopped = event.request() != null - && event.request().suspendPolicy() == EventRequest.SUSPEND_ALL; - context.getProtocolServer().sendEvent(new Events.StoppedEvent("data breakpoint", bpThread.uniqueID(), allThreadsStopped)); + context.getProtocolServer().sendEvent(new Events.StoppedEvent("data breakpoint", bpThread.uniqueID())); } debugEvent.shouldResume = false; }); diff --git a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/SetFunctionBreakpointsRequestHandler.java b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/SetFunctionBreakpointsRequestHandler.java index 01b5e9619..96a0e395b 100644 --- a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/SetFunctionBreakpointsRequestHandler.java +++ b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/SetFunctionBreakpointsRequestHandler.java @@ -40,7 +40,6 @@ import com.microsoft.java.debug.core.protocol.Types.FunctionBreakpoint; import com.sun.jdi.ThreadReference; import com.sun.jdi.event.MethodEntryEvent; -import com.sun.jdi.request.EventRequest; public class SetFunctionBreakpointsRequestHandler implements IDebugRequestHandler { private boolean registered = false; @@ -167,20 +166,16 @@ private void registerMethodBreakpointHandler(IDebugAdapterContext context) { debugEvent.eventSet.resume(); } else { context.getThreadCache().addEventThread(bpThread, "function breakpoint"); - boolean allThreadsStopped = methodEntryEvent.request() != null - && methodEntryEvent.request().suspendPolicy() == EventRequest.SUSPEND_ALL; context.getProtocolServer().sendEvent(new Events.StoppedEvent( - "function breakpoint", bpThread.uniqueID(), allThreadsStopped)); + "function breakpoint", bpThread.uniqueID())); } }); }); } else { context.getThreadCache().addEventThread(bpThread, "function breakpoint"); - boolean allThreadsStopped = methodEntryEvent.request() != null - && methodEntryEvent.request().suspendPolicy() == EventRequest.SUSPEND_ALL; context.getProtocolServer() - .sendEvent(new Events.StoppedEvent("function breakpoint", bpThread.uniqueID(), allThreadsStopped)); + .sendEvent(new Events.StoppedEvent("function breakpoint", bpThread.uniqueID())); } debugEvent.shouldResume = false; diff --git a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/ThreadsRequestHandler.java b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/ThreadsRequestHandler.java index 5c4770391..6573f11da 100644 --- a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/ThreadsRequestHandler.java +++ b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/ThreadsRequestHandler.java @@ -149,11 +149,6 @@ private CompletableFuture resume(Requests.ContinueArguments arguments, if (thread == null) { thread = DebugUtility.getThread(context.getDebugSession(), arguments.threadId); } - - if (context.getDebugSession().shouldSuspendAllThreads()) { - thread = null; - } - /** * See the jdi doc https://docs.oracle.com/javase/7/docs/jdk/api/jpda/jdi/com/sun/jdi/ThreadReference.html#resume(), * suspends of both the virtual machine and individual threads are counted. Before a thread will run again, it must