From 258c9009a2f0b89c07f959ce51ec164733b050d4 Mon Sep 17 00:00:00 2001 From: Nipuna Ranasinghe Date: Wed, 13 Nov 2024 11:23:09 +0530 Subject: [PATCH 1/6] Fix slowness while loading stack frames during debug hits --- .../ballerinalang/debugadapter/JDIEventProcessor.java | 10 +++++----- .../debugadapter/jdi/StackFrameProxyImpl.java | 8 +------- 2 files changed, 6 insertions(+), 12 deletions(-) diff --git a/misc/debug-adapter/modules/debug-adapter-core/src/main/java/org/ballerinalang/debugadapter/JDIEventProcessor.java b/misc/debug-adapter/modules/debug-adapter-core/src/main/java/org/ballerinalang/debugadapter/JDIEventProcessor.java index e1e32101cbc8..bdb6c6ddacc0 100755 --- a/misc/debug-adapter/modules/debug-adapter-core/src/main/java/org/ballerinalang/debugadapter/JDIEventProcessor.java +++ b/misc/debug-adapter/modules/debug-adapter-core/src/main/java/org/ballerinalang/debugadapter/JDIEventProcessor.java @@ -126,12 +126,12 @@ private void processEvent(EventSet eventSet, Event event) { void enableBreakpoints(String qualifiedClassName, LinkedHashMap breakpoints) { breakpointProcessor.addSourceBreakpoints(qualifiedClassName, breakpoints); - if (context.getDebuggeeVM() != null) { - // Setting breakpoints to a already running debug session. - context.getEventManager().deleteAllBreakpoints(); - context.getDebuggeeVM().allClasses().forEach(referenceType -> - breakpointProcessor.activateUserBreakPoints(referenceType, false)); + if (context.getDebuggeeVM() == null) { + return; } + // Setting breakpoints to an already running debug session. + context.getEventManager().deleteAllBreakpoints(); + context.getDebuggeeVM().allClasses().forEach(ref -> breakpointProcessor.activateUserBreakPoints(ref, false)); } void sendStepRequest(int threadId, int stepType) { diff --git a/misc/debug-adapter/modules/debug-adapter-core/src/main/java/org/ballerinalang/debugadapter/jdi/StackFrameProxyImpl.java b/misc/debug-adapter/modules/debug-adapter-core/src/main/java/org/ballerinalang/debugadapter/jdi/StackFrameProxyImpl.java index 79181b0655ce..9e23483315eb 100644 --- a/misc/debug-adapter/modules/debug-adapter-core/src/main/java/org/ballerinalang/debugadapter/jdi/StackFrameProxyImpl.java +++ b/misc/debug-adapter/modules/debug-adapter-core/src/main/java/org/ballerinalang/debugadapter/jdi/StackFrameProxyImpl.java @@ -286,13 +286,7 @@ public Value getValue(LocalVariableProxyImpl localVariable) throws JdiProxyExcep Exception error = null; for (int attempt = 0; attempt < RETRY_COUNT; attempt++) { try { - Map values = getAllValues(); - LocalVariable variable = localVariable.getVariable(); - if (values.containsKey(variable)) { - return values.get(variable); - } else { // try direct get - return getStackFrame().getValue(variable); - } + return getStackFrame().getValue(localVariable.getVariable()); } catch (InvalidStackFrameException e) { error = e; clearCaches(); From 56348e3b08ceba7256dfaad5ecc88098519450d5 Mon Sep 17 00:00:00 2001 From: Nipuna Ranasinghe Date: Wed, 13 Nov 2024 11:43:28 +0530 Subject: [PATCH 2/6] Optimize user breakpoints processing logic --- .../ballerinalang/debugadapter/BreakpointProcessor.java | 8 ++++++-- .../ballerinalang/debugadapter/JDIEventProcessor.java | 9 +++++---- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/misc/debug-adapter/modules/debug-adapter-core/src/main/java/org/ballerinalang/debugadapter/BreakpointProcessor.java b/misc/debug-adapter/modules/debug-adapter-core/src/main/java/org/ballerinalang/debugadapter/BreakpointProcessor.java index 8cb6dd0d22cc..ae2713e294fc 100644 --- a/misc/debug-adapter/modules/debug-adapter-core/src/main/java/org/ballerinalang/debugadapter/BreakpointProcessor.java +++ b/misc/debug-adapter/modules/debug-adapter-core/src/main/java/org/ballerinalang/debugadapter/BreakpointProcessor.java @@ -173,8 +173,12 @@ void restoreUserBreakpoints() { if (context.getDebuggeeVM() == null) { return; } + context.getEventManager().deleteAllBreakpoints(); - context.getDebuggeeVM().allClasses().forEach(classRef -> activateUserBreakPoints(classRef, false)); + for (Map.Entry> entry : userBreakpoints.entrySet()) { + String qClassName = entry.getKey(); + context.getDebuggeeVM().classesByName(qClassName).forEach(ref -> activateUserBreakPoints(ref, false)); + } } /** @@ -210,7 +214,7 @@ void activateUserBreakPoints(ReferenceType referenceType, boolean shouldNotify) } catch (AbsentInformationException ignored) { // classes with no line number information can be ignored. } catch (Exception e) { - LOGGER.error(e.getMessage(), e); + LOGGER.error("Error while activating user breakpoints:" + e.getMessage(), e); } } diff --git a/misc/debug-adapter/modules/debug-adapter-core/src/main/java/org/ballerinalang/debugadapter/JDIEventProcessor.java b/misc/debug-adapter/modules/debug-adapter-core/src/main/java/org/ballerinalang/debugadapter/JDIEventProcessor.java index bdb6c6ddacc0..8d0762b3a4de 100755 --- a/misc/debug-adapter/modules/debug-adapter-core/src/main/java/org/ballerinalang/debugadapter/JDIEventProcessor.java +++ b/misc/debug-adapter/modules/debug-adapter-core/src/main/java/org/ballerinalang/debugadapter/JDIEventProcessor.java @@ -123,15 +123,16 @@ private void processEvent(EventSet eventSet, Event event) { } } - void enableBreakpoints(String qualifiedClassName, LinkedHashMap breakpoints) { - breakpointProcessor.addSourceBreakpoints(qualifiedClassName, breakpoints); - + void enableBreakpoints(String qClassName, LinkedHashMap breakpoints) { + breakpointProcessor.addSourceBreakpoints(qClassName, breakpoints); if (context.getDebuggeeVM() == null) { return; } + // Setting breakpoints to an already running debug session. context.getEventManager().deleteAllBreakpoints(); - context.getDebuggeeVM().allClasses().forEach(ref -> breakpointProcessor.activateUserBreakPoints(ref, false)); + context.getDebuggeeVM().classesByName(qClassName) + .forEach(ref -> breakpointProcessor.activateUserBreakPoints(ref, false)); } void sendStepRequest(int threadId, int stepType) { From 74a1b436c12a0c48310b94535cfd19e82b723861 Mon Sep 17 00:00:00 2001 From: Nipuna Ranasinghe Date: Wed, 13 Nov 2024 11:53:37 +0530 Subject: [PATCH 3/6] Fix error handling for dynamic breakpoint failures --- .../org/ballerinalang/debugadapter/BreakpointProcessor.java | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/misc/debug-adapter/modules/debug-adapter-core/src/main/java/org/ballerinalang/debugadapter/BreakpointProcessor.java b/misc/debug-adapter/modules/debug-adapter-core/src/main/java/org/ballerinalang/debugadapter/BreakpointProcessor.java index ae2713e294fc..5fc936b8f248 100644 --- a/misc/debug-adapter/modules/debug-adapter-core/src/main/java/org/ballerinalang/debugadapter/BreakpointProcessor.java +++ b/misc/debug-adapter/modules/debug-adapter-core/src/main/java/org/ballerinalang/debugadapter/BreakpointProcessor.java @@ -256,11 +256,7 @@ void activateDynamicBreakPoints(int threadId, DynamicBreakpointMode mode, boolea context.setPrevLocation(validFrames.get(0).getJStackFrame().location()); } } catch (JdiProxyException e) { - LOGGER.error(e.getMessage()); - if (!jdiEventProcessor.getStepRequests().isEmpty()) { - int stepType = ((StepRequest) jdiEventProcessor.getStepRequests().get(0)).depth(); - jdiEventProcessor.sendStepRequest(threadId, stepType); - } + LOGGER.error("Error while activating dynamic breakpoints:" + e.getMessage(), e); } } From 8f7fe104b0c78d40a8221d1cc8658f5f198bcc75 Mon Sep 17 00:00:00 2001 From: Nipuna Ranasinghe Date: Wed, 13 Nov 2024 14:13:28 +0530 Subject: [PATCH 4/6] Fix spotbugs and checkstyle --- .../org/ballerinalang/debugadapter/BreakpointProcessor.java | 1 - .../ballerinalang/debugadapter/jdi/StackFrameProxyImpl.java | 4 +++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/misc/debug-adapter/modules/debug-adapter-core/src/main/java/org/ballerinalang/debugadapter/BreakpointProcessor.java b/misc/debug-adapter/modules/debug-adapter-core/src/main/java/org/ballerinalang/debugadapter/BreakpointProcessor.java index 5fc936b8f248..4ccb5c2e3c14 100644 --- a/misc/debug-adapter/modules/debug-adapter-core/src/main/java/org/ballerinalang/debugadapter/BreakpointProcessor.java +++ b/misc/debug-adapter/modules/debug-adapter-core/src/main/java/org/ballerinalang/debugadapter/BreakpointProcessor.java @@ -22,7 +22,6 @@ import com.sun.jdi.ThreadReference; import com.sun.jdi.event.BreakpointEvent; import com.sun.jdi.request.BreakpointRequest; -import com.sun.jdi.request.StepRequest; import org.ballerinalang.debugadapter.breakpoint.BalBreakpoint; import org.ballerinalang.debugadapter.breakpoint.LogMessage; import org.ballerinalang.debugadapter.breakpoint.TemplateLogMessage; diff --git a/misc/debug-adapter/modules/debug-adapter-core/src/main/java/org/ballerinalang/debugadapter/jdi/StackFrameProxyImpl.java b/misc/debug-adapter/modules/debug-adapter-core/src/main/java/org/ballerinalang/debugadapter/jdi/StackFrameProxyImpl.java index 9e23483315eb..71188b93dea2 100644 --- a/misc/debug-adapter/modules/debug-adapter-core/src/main/java/org/ballerinalang/debugadapter/jdi/StackFrameProxyImpl.java +++ b/misc/debug-adapter/modules/debug-adapter-core/src/main/java/org/ballerinalang/debugadapter/jdi/StackFrameProxyImpl.java @@ -311,7 +311,8 @@ public Value getValue(LocalVariableProxyImpl localVariable) throws JdiProxyExcep throw new JdiProxyException(error.getMessage(), error); } - private Map getAllValues() throws JdiProxyException { + @SuppressWarnings("unused") + public Map getAllValues() throws JdiProxyException { checkValid(); if (myAllValues == null) { try { @@ -339,6 +340,7 @@ private Map getAllValues() throws JdiProxyException { return myAllValues; } + @SuppressWarnings("unused") public void setValue(LocalVariableProxyImpl localVariable, Value value) throws JdiProxyException, ClassNotLoadedException, InvalidTypeException { InvalidStackFrameException error = null; From a52c4785f69d79f5940114237cf5641561397205 Mon Sep 17 00:00:00 2001 From: Nipuna Ranasinghe Date: Fri, 15 Nov 2024 09:51:07 +0530 Subject: [PATCH 5/6] Fix intermittent failure when fetching local variables --- .../debugadapter/JBallerinaDebugServer.java | 10 ++++------ .../org/ballerinalang/debugadapter/jdi/JDIUtils.java | 12 ++++++++++++ .../debugadapter/jdi/StackFrameProxyImpl.java | 8 +++----- .../debugadapter/variable/VariableUtils.java | 6 ++---- 4 files changed, 21 insertions(+), 15 deletions(-) diff --git a/misc/debug-adapter/modules/debug-adapter-core/src/main/java/org/ballerinalang/debugadapter/JBallerinaDebugServer.java b/misc/debug-adapter/modules/debug-adapter-core/src/main/java/org/ballerinalang/debugadapter/JBallerinaDebugServer.java index 552d5d9577c0..bd26e9ac5e7d 100755 --- a/misc/debug-adapter/modules/debug-adapter-core/src/main/java/org/ballerinalang/debugadapter/JBallerinaDebugServer.java +++ b/misc/debug-adapter/modules/debug-adapter-core/src/main/java/org/ballerinalang/debugadapter/JBallerinaDebugServer.java @@ -42,6 +42,7 @@ import org.ballerinalang.debugadapter.evaluation.DebugExpressionEvaluator; import org.ballerinalang.debugadapter.evaluation.EvaluationException; import org.ballerinalang.debugadapter.evaluation.EvaluationExceptionKind; +import org.ballerinalang.debugadapter.jdi.JDIUtils; import org.ballerinalang.debugadapter.jdi.JdiProxyException; import org.ballerinalang.debugadapter.jdi.LocalVariableProxyImpl; import org.ballerinalang.debugadapter.jdi.StackFrameProxyImpl; @@ -590,11 +591,11 @@ public CompletableFuture runInTerminal(RunInTerminalReque // attach to target VM while (context.getDebuggeeVM() == null && tryCounter < 10) { try { - TimeUnit.SECONDS.sleep(3); + JDIUtils.sleepMillis(3000); attachToRemoteVM("", clientConfigHolder.getDebuggePort()); } catch (IOException ignored) { tryCounter++; - } catch (IllegalConnectorArgumentsException | ClientConfigurationException | InterruptedException e) { + } catch (IllegalConnectorArgumentsException | ClientConfigurationException e) { throw new RuntimeException(e); } } @@ -680,10 +681,7 @@ void terminateDebugServer(boolean terminateDebuggee, boolean logsEnabled) { // Exits from the debug server VM. new java.lang.Thread(() -> { - try { - java.lang.Thread.sleep(500); - } catch (InterruptedException ignored) { - } + JDIUtils.sleepMillis(500); System.exit(0); }).start(); } diff --git a/misc/debug-adapter/modules/debug-adapter-core/src/main/java/org/ballerinalang/debugadapter/jdi/JDIUtils.java b/misc/debug-adapter/modules/debug-adapter-core/src/main/java/org/ballerinalang/debugadapter/jdi/JDIUtils.java index 412279b549e3..c985d4d41cfe 100644 --- a/misc/debug-adapter/modules/debug-adapter-core/src/main/java/org/ballerinalang/debugadapter/jdi/JDIUtils.java +++ b/misc/debug-adapter/modules/debug-adapter-core/src/main/java/org/ballerinalang/debugadapter/jdi/JDIUtils.java @@ -47,4 +47,16 @@ public static void enableJDIRequests(ExecutionContext context) { EventRequestManager eventManager = context.getEventManager(); eventManager.breakpointRequests().forEach(EventRequest::enable); } + + /** + * Sleep for the given number of milliseconds. + * + * @param millis number of milliseconds to sleep + */ + public static void sleepMillis(long millis) { + try { + Thread.sleep(millis); + } catch (InterruptedException ignored) { + } + } } diff --git a/misc/debug-adapter/modules/debug-adapter-core/src/main/java/org/ballerinalang/debugadapter/jdi/StackFrameProxyImpl.java b/misc/debug-adapter/modules/debug-adapter-core/src/main/java/org/ballerinalang/debugadapter/jdi/StackFrameProxyImpl.java index 71188b93dea2..4ee2864b4518 100644 --- a/misc/debug-adapter/modules/debug-adapter-core/src/main/java/org/ballerinalang/debugadapter/jdi/StackFrameProxyImpl.java +++ b/misc/debug-adapter/modules/debug-adapter-core/src/main/java/org/ballerinalang/debugadapter/jdi/StackFrameProxyImpl.java @@ -141,10 +141,7 @@ public StackFrame getStackFrame() throws JdiProxyException { } catch (IncompatibleThreadStateException e) { error = e; clearCaches(); - try { - Thread.sleep(10); - } catch (InterruptedException ignored) { - } + JDIUtils.sleepMillis(10); } catch (IndexOutOfBoundsException e) { throw new JdiProxyException(e.getMessage(), e); } catch (ObjectCollectedException ignored) { @@ -287,7 +284,7 @@ public Value getValue(LocalVariableProxyImpl localVariable) throws JdiProxyExcep for (int attempt = 0; attempt < RETRY_COUNT; attempt++) { try { return getStackFrame().getValue(localVariable.getVariable()); - } catch (InvalidStackFrameException e) { + } catch (InvalidStackFrameException | IllegalArgumentException e) { error = e; clearCaches(); } catch (InconsistentDebugInfoException ignored) { @@ -307,6 +304,7 @@ public Value getValue(LocalVariableProxyImpl localVariable) throws JdiProxyExcep throw e; } } + JDIUtils.sleepMillis(1); } throw new JdiProxyException(error.getMessage(), error); } diff --git a/misc/debug-adapter/modules/debug-adapter-core/src/main/java/org/ballerinalang/debugadapter/variable/VariableUtils.java b/misc/debug-adapter/modules/debug-adapter-core/src/main/java/org/ballerinalang/debugadapter/variable/VariableUtils.java index d953c1c5a8fd..a71a118619bf 100644 --- a/misc/debug-adapter/modules/debug-adapter-core/src/main/java/org/ballerinalang/debugadapter/variable/VariableUtils.java +++ b/misc/debug-adapter/modules/debug-adapter-core/src/main/java/org/ballerinalang/debugadapter/variable/VariableUtils.java @@ -23,6 +23,7 @@ import com.sun.jdi.Value; import org.ballerinalang.debugadapter.SuspendedContext; import org.ballerinalang.debugadapter.evaluation.EvaluationException; +import org.ballerinalang.debugadapter.jdi.JDIUtils; import org.ballerinalang.debugadapter.jdi.LocalVariableProxyImpl; import java.util.AbstractMap; @@ -212,10 +213,7 @@ public static Value invokeRemoteVMMethod(SuspendedContext context, Value jvmObje return ((ObjectReference) jvmObject).invokeMethod(context.getOwningThread() .getThreadReference(), method, arguments, ObjectReference.INVOKE_SINGLE_THREADED); } catch (Exception e) { - try { - Thread.sleep(10); - } catch (InterruptedException ignored) { - } + JDIUtils.sleepMillis(10); } } throw new DebugVariableException("Failed to invoke remote VM method as the invocation thread is busy"); From e8b5bc50c28cd5c87760d15f4026395d2842ea9a Mon Sep 17 00:00:00 2001 From: Nipuna Ranasinghe Date: Sat, 16 Nov 2024 17:06:12 +0530 Subject: [PATCH 6/6] Fix build failure --- .../org/ballerinalang/debugadapter/JBallerinaDebugServer.java | 1 - 1 file changed, 1 deletion(-) diff --git a/misc/debug-adapter/modules/debug-adapter-core/src/main/java/org/ballerinalang/debugadapter/JBallerinaDebugServer.java b/misc/debug-adapter/modules/debug-adapter-core/src/main/java/org/ballerinalang/debugadapter/JBallerinaDebugServer.java index bd26e9ac5e7d..8ed4fb6046a9 100755 --- a/misc/debug-adapter/modules/debug-adapter-core/src/main/java/org/ballerinalang/debugadapter/JBallerinaDebugServer.java +++ b/misc/debug-adapter/modules/debug-adapter-core/src/main/java/org/ballerinalang/debugadapter/JBallerinaDebugServer.java @@ -124,7 +124,6 @@ import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; -import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; import static org.ballerinalang.debugadapter.DebugExecutionManager.LOCAL_HOST;