This is an automated email from the ASF dual-hosted git repository. entl pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/netbeans.git
The following commit(s) were added to refs/heads/master by this push: new 1b12ab7 Step and Continue after breakpoint suspends at wrong place after eval. [NETBEANS-6123] 1b12ab7 is described below commit 1b12ab7eebf06b7264161e8f19a90b5142103a03 Author: Martin Entlicher <martin.entlic...@oracle.com> AuthorDate: Mon Oct 11 20:23:41 2021 +0200 Step and Continue after breakpoint suspends at wrong place after eval. [NETBEANS-6123] --- .../modules/debugger/jpda/JPDAStepImpl.java | 6 ++ .../debugger/jpda/actions/StepActionProvider.java | 3 + .../debugger/jpda/actions/StepIntoNextMethod.java | 2 + .../modules/debugger/jpda/impl/StepUtils.java | 67 ++++++++++++++++++++ .../debugger/jpda/models/JPDAThreadImpl.java | 42 ++++++++++++- .../org/netbeans/api/debugger/jpda/StepTest.java | 71 ++++++++++++++++++++++ .../debugger/jpda/testapps/StepAndContinueApp.java | 53 ++++++++++++++++ 7 files changed, 241 insertions(+), 3 deletions(-) diff --git a/java/debugger.jpda/src/org/netbeans/modules/debugger/jpda/JPDAStepImpl.java b/java/debugger.jpda/src/org/netbeans/modules/debugger/jpda/JPDAStepImpl.java index e762f6f..2a3706f 100644 --- a/java/debugger.jpda/src/org/netbeans/modules/debugger/jpda/JPDAStepImpl.java +++ b/java/debugger.jpda/src/org/netbeans/modules/debugger/jpda/JPDAStepImpl.java @@ -62,6 +62,7 @@ import org.netbeans.api.debugger.jpda.event.JPDABreakpointListener; import org.netbeans.modules.debugger.jpda.actions.CompoundSmartSteppingListener; import org.netbeans.modules.debugger.jpda.actions.SmartSteppingFilterImpl; import org.netbeans.modules.debugger.jpda.actions.StepIntoActionProvider; +import org.netbeans.modules.debugger.jpda.impl.StepUtils; import org.netbeans.modules.debugger.jpda.jdi.ClassNotPreparedExceptionWrapper; import org.netbeans.modules.debugger.jpda.jdi.ClassTypeWrapper; import org.netbeans.modules.debugger.jpda.jdi.IllegalThreadStateExceptionWrapper; @@ -225,6 +226,7 @@ public class JPDAStepImpl extends JPDAStep implements Executor { size, getDepth() ); + StepUtils.markOriginalStepDepth(stepRequest, trImpl.getThreadReference()); //stepRequest.addCountFilter(1); - works bad with exclusion filters! String[] exclusionPatterns = applyExclusionPatterns(stepRequest); debuggerImpl.getOperator().register(stepRequest, this); @@ -468,6 +470,7 @@ public class JPDAStepImpl extends JPDAStep implements Executor { StepRequest.STEP_LINE, StepRequest.STEP_OVER ); + StepUtils.markOriginalStepDepth(boundaryStepRequest, trRef); if (isNextOperationFromDifferentExpression) { EventRequestWrapper.addCountFilter(boundaryStepRequest, 2); } else { @@ -632,6 +635,7 @@ public class JPDAStepImpl extends JPDAStep implements Executor { StepRequest.STEP_LINE, StepRequest.STEP_OUT ); + StepUtils.markOriginalStepDepth(stepRequest, tr.getThreadReference()); EventRequestWrapper.addCountFilter(stepRequest, 1); String[] exclusionPatterns = getCurrentExclusionPatterns(); // JDI is inconsistent!!! Step into steps *through* filters, but step out does *NOT* @@ -946,6 +950,7 @@ public class JPDAStepImpl extends JPDAStep implements Executor { doStepSize, doStepDepth ); + StepUtils.markOriginalStepDepth(stepRequest, tr); //EventRequestWrapper.addCountFilter(stepRequest, 1); String[] exclusionPatterns = applyExclusionPatterns(stepRequest); debuggerImpl.getOperator ().register (stepRequest, this); @@ -1002,6 +1007,7 @@ public class JPDAStepImpl extends JPDAStep implements Executor { doStepSize, depth ); + StepUtils.markOriginalStepDepth(stepRequest, tr); if (logger.isLoggable(Level.FINE)) { try { logger.fine("Can not stop at " + ThreadReferenceWrapper.frame(tr, 0) + ", smart-stepping. Submitting step = " + stepRequest + "; depth = " + depth); diff --git a/java/debugger.jpda/src/org/netbeans/modules/debugger/jpda/actions/StepActionProvider.java b/java/debugger.jpda/src/org/netbeans/modules/debugger/jpda/actions/StepActionProvider.java index a770ea5..6cff450 100644 --- a/java/debugger.jpda/src/org/netbeans/modules/debugger/jpda/actions/StepActionProvider.java +++ b/java/debugger.jpda/src/org/netbeans/modules/debugger/jpda/actions/StepActionProvider.java @@ -54,6 +54,7 @@ import org.netbeans.modules.debugger.jpda.JPDADebuggerImpl; import org.netbeans.modules.debugger.jpda.JPDAStepImpl; import org.netbeans.modules.debugger.jpda.JPDAStepImpl.MethodExitBreakpointListener; import org.netbeans.modules.debugger.jpda.SourcePath; +import org.netbeans.modules.debugger.jpda.impl.StepUtils; import org.netbeans.modules.debugger.jpda.jdi.IllegalThreadStateExceptionWrapper; import org.netbeans.modules.debugger.jpda.jdi.InternalExceptionWrapper; import org.netbeans.modules.debugger.jpda.jdi.InvalidRequestStateExceptionWrapper; @@ -221,6 +222,7 @@ implements Executor { stepSize, stepDepth ); + StepUtils.markOriginalStepDepth(stepRequest, tr); EventRequestWrapper.addCountFilter (stepRequest, 1); getDebuggerImpl ().getOperator ().register (stepRequest, StepActionProvider.this); EventRequestWrapper.setSuspendPolicy (stepRequest, suspendPolicy); @@ -416,6 +418,7 @@ implements Executor { StepRequest.STEP_LINE, step ); + StepUtils.markOriginalStepDepth(stepRequest, tr); EventRequestWrapper.addCountFilter(stepRequest, 1); getDebuggerImpl ().getOperator ().register (stepRequest, this); EventRequestWrapper.setSuspendPolicy(stepRequest, suspendPolicy); diff --git a/java/debugger.jpda/src/org/netbeans/modules/debugger/jpda/actions/StepIntoNextMethod.java b/java/debugger.jpda/src/org/netbeans/modules/debugger/jpda/actions/StepIntoNextMethod.java index 4499e7f..4f7ed77 100644 --- a/java/debugger.jpda/src/org/netbeans/modules/debugger/jpda/actions/StepIntoNextMethod.java +++ b/java/debugger.jpda/src/org/netbeans/modules/debugger/jpda/actions/StepIntoNextMethod.java @@ -46,6 +46,7 @@ import org.netbeans.modules.debugger.jpda.JPDADebuggerImpl; import org.netbeans.modules.debugger.jpda.JPDAStepImpl; import org.netbeans.modules.debugger.jpda.SourcePath; import static org.netbeans.modules.debugger.jpda.actions.StepActionProvider.getTopFrame; +import org.netbeans.modules.debugger.jpda.impl.StepUtils; import org.netbeans.modules.debugger.jpda.jdi.IllegalThreadStateExceptionWrapper; import org.netbeans.modules.debugger.jpda.jdi.InternalExceptionWrapper; import org.netbeans.modules.debugger.jpda.jdi.InvalidRequestStateExceptionWrapper; @@ -509,6 +510,7 @@ public class StepIntoNextMethod implements Executor, PropertyChangeListener { tr, stepSize, step); + StepUtils.markOriginalStepDepth(stepRequest, tr); getDebuggerImpl ().getOperator ().register (stepRequest, this); suspendPolicy = getDebuggerImpl().getSuspend(); EventRequestWrapper.setSuspendPolicy (stepRequest, suspendPolicy); diff --git a/java/debugger.jpda/src/org/netbeans/modules/debugger/jpda/impl/StepUtils.java b/java/debugger.jpda/src/org/netbeans/modules/debugger/jpda/impl/StepUtils.java new file mode 100644 index 0000000..9fed504 --- /dev/null +++ b/java/debugger.jpda/src/org/netbeans/modules/debugger/jpda/impl/StepUtils.java @@ -0,0 +1,67 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.debugger.jpda.impl; + +import com.sun.jdi.IncompatibleThreadStateException; +import com.sun.jdi.ThreadReference; +import com.sun.jdi.request.StepRequest; +import org.netbeans.modules.debugger.jpda.jdi.IllegalThreadStateExceptionWrapper; + +import org.netbeans.modules.debugger.jpda.jdi.InternalExceptionWrapper; +import org.netbeans.modules.debugger.jpda.jdi.InvalidStackFrameExceptionWrapper; +import org.netbeans.modules.debugger.jpda.jdi.ObjectCollectedExceptionWrapper; +import org.netbeans.modules.debugger.jpda.jdi.ThreadReferenceWrapper; +import org.netbeans.modules.debugger.jpda.jdi.VMDisconnectedExceptionWrapper; +import org.netbeans.modules.debugger.jpda.jdi.request.EventRequestWrapper; + +public final class StepUtils { + + private static final String STEP_PROP_DEPTH = "originalThreadDepth"; // NOI18N + + private StepUtils() {} + + /** + * Mark the frame depth of the thread when the step is created. It's to be retrieved + * by {@link #getOriginalStepDepth(com.sun.jdi.request.StepRequest)}. + */ + public static void markOriginalStepDepth(StepRequest stepRequest, ThreadReference threadReference) { + try { + EventRequestWrapper.putProperty(stepRequest, STEP_PROP_DEPTH, ThreadReferenceWrapper.frameCount(threadReference)); + } catch (IllegalThreadStateExceptionWrapper | IncompatibleThreadStateException | InternalExceptionWrapper | + InvalidStackFrameExceptionWrapper | ObjectCollectedExceptionWrapper | VMDisconnectedExceptionWrapper ex) { + // Not successful, ignore. + } + } + + /** + * Get the frame depth of the thread when the step was submitted, or <code>-1</code> when unknown. + */ + public static int getOriginalStepDepth(StepRequest stepRequest) { + Object depth; + try { + depth = EventRequestWrapper.getProperty(stepRequest, STEP_PROP_DEPTH); + } catch (InternalExceptionWrapper | VMDisconnectedExceptionWrapper ex) { + return -1; + } + if (depth instanceof Integer) { + return (Integer) depth; + } + return -1; + } +} diff --git a/java/debugger.jpda/src/org/netbeans/modules/debugger/jpda/models/JPDAThreadImpl.java b/java/debugger.jpda/src/org/netbeans/modules/debugger/jpda/models/JPDAThreadImpl.java index c430d9b..757efd6 100644 --- a/java/debugger.jpda/src/org/netbeans/modules/debugger/jpda/models/JPDAThreadImpl.java +++ b/java/debugger.jpda/src/org/netbeans/modules/debugger/jpda/models/JPDAThreadImpl.java @@ -75,6 +75,7 @@ import org.netbeans.api.debugger.jpda.Variable; import org.netbeans.api.debugger.jpda.event.JPDABreakpointEvent; import org.netbeans.modules.debugger.jpda.JPDADebuggerImpl; import org.netbeans.modules.debugger.jpda.SingleThreadWatcher; +import org.netbeans.modules.debugger.jpda.impl.StepUtils; import org.netbeans.modules.debugger.jpda.jdi.IllegalThreadStateExceptionWrapper; import org.netbeans.modules.debugger.jpda.jdi.InternalExceptionWrapper; import org.netbeans.modules.debugger.jpda.jdi.InvalidRequestStateExceptionWrapper; @@ -128,8 +129,8 @@ public final class JPDAThreadImpl implements JPDAThread, Customizer, BeanContext private static final Logger logger = Logger.getLogger(JPDAThreadImpl.class.getName()); // NOI18N private static final Logger loggerS = Logger.getLogger(JPDAThreadImpl.class.getName()+".suspend"); // NOI18N - private ThreadReference threadReference; - private JPDADebuggerImpl debugger; + private final ThreadReference threadReference; + private final JPDADebuggerImpl debugger; /** Thread is suspended and everybody know about this. */ private boolean suspended; private boolean suspendedOnAnEvent; // Suspended by an event that occured in this thread @@ -1357,7 +1358,9 @@ public final class JPDAThreadImpl implements JPDAThread, Customizer, BeanContext if (stepsToDelete == null) { stepsToDelete = new ArrayList<StepRequest>(); } - stepsToDelete.add(sr); + if (checkToDisableStep(sr, t)) { + stepsToDelete.add(sr); + } } } if (stepsToDelete != null) { @@ -1404,6 +1407,39 @@ public final class JPDAThreadImpl implements JPDAThread, Customizer, BeanContext } } + private static boolean checkToDisableStep(StepRequest sr, ThreadReference t) { + int stepKind; + try { + stepKind = StepRequestWrapper.depth(sr); + } catch (InternalExceptionWrapper | VMDisconnectedExceptionWrapper ex) { + // A wrong state, do nothing + return false; + } + if (stepKind == StepRequest.STEP_INTO) { + // Disable step into as method invocation will suspend on it + return true; + } + int threadDepth; + try { + threadDepth = ThreadReferenceWrapper.frameCount(t); + } catch (IllegalThreadStateExceptionWrapper | IncompatibleThreadStateException | + InternalExceptionWrapper | InvalidStackFrameExceptionWrapper ex) { + // We can not retrieve the frame depth + return true; + } catch (ObjectCollectedExceptionWrapper | VMDisconnectedExceptionWrapper ex) { + // A wrong state, do nothing + return false; + } + int stepDepth = StepUtils.getOriginalStepDepth(sr); + if (stepDepth > 0) { + // If the depth at which the step was submitted is less than the current depth, + // do not disable the step as it will not interfere with the method invocation. + // The invocation will not go up the stack. + return stepDepth >= threadDepth; + } + return true; + } + public void notifyMethodInvokeDone() { synchronized (suspendToCheckForMonitorsLock) { canSuspendToCheckForMonitors = false; diff --git a/java/debugger.jpda/test/unit/src/org/netbeans/api/debugger/jpda/StepTest.java b/java/debugger.jpda/test/unit/src/org/netbeans/api/debugger/jpda/StepTest.java index 636430f..792de78 100644 --- a/java/debugger.jpda/test/unit/src/org/netbeans/api/debugger/jpda/StepTest.java +++ b/java/debugger.jpda/test/unit/src/org/netbeans/api/debugger/jpda/StepTest.java @@ -229,6 +229,56 @@ public class StepTest extends NbTestCase { } } + public void testStepAndContinueOnBP() throws Exception { + String app = "org.netbeans.api.debugger.jpda.testapps.StepAndContinueApp"; + try { + JPDASupport.removeAllBreakpoints(); + Utils.BreakPositions bp = Utils.getBreakPositions(sourceRoot + app.replace('.', '/') + ".java"); + LineBreakpoint lb = bp.getLineBreakpoints().get(0); + dm.addBreakpoint(lb); + support = JPDASupport.attach(app); + support.waitState (JPDADebugger.STATE_STOPPED); + dm.removeBreakpoint(lb); + assertEquals ( + "Execution stopped in wrong class", + support.getDebugger().getCurrentCallStackFrame().getClassName(), + app + ); + assertEquals ( + "Execution stopped at wrong line", + lb.getLineNumber(), + support.getDebugger().getCurrentCallStackFrame().getLineNumber(null) + ); + lb = bp.getLineBreakpoints().get(1); + dm.addBreakpoint(lb); + support.stepOver(); + suspendedLineCheck(bp.getStopLine("Over1")); + support.stepOver(); + breakpointCheckEvalCont(lb.getLineNumber()); + suspendedLineCheck(bp.getStopLine("Over2")); + support.stepOver(); + breakpointCheckEvalCont(lb.getLineNumber()); + suspendedLineCheck(bp.getStopLine("Over3")); + support.stepOver(); + suspendedLineCheck(bp.getStopLine("Over4")); + support.stepOver(); + suspendedLineCheck(bp.getStopLine("Over5")); + support.stepInto(); + suspendedLineCheck(bp.getStopLine("Into6")); + support.stepOut(); + breakpointCheckEvalCont(lb.getLineNumber()); + support.stepOver(); + suspendedLineCheck(bp.getStopLine("Out7")); + support.stepInto(); + suspendedLineCheck(bp.getStopLine("Into8")); + support.stepOut(); + breakpointCheckEvalCont(lb.getLineNumber()); + suspendedLineCheck(bp.getStopLine("Out7")); + } finally { + support.doFinish (); + } + } + private void stepCheck ( Object stepType, String clsExpected, @@ -247,4 +297,25 @@ public class StepTest extends NbTestCase { getLineNumber (null) ); } + + private void breakpointCheckEvalCont(int lineExpected) { + suspendedLineCheck(lineExpected); + // We invoke a method: + try { + assertEquals("10", support.getDebugger().evaluate("m1()").getValue()); + } catch (InvalidExpressionException ex) { + throw new AssertionError(ex); + } + // Then we do Continue to finish the original step: + support.doContinue(); + support.waitState(JPDADebugger.STATE_STOPPED); + } + + private void suspendedLineCheck(int lineExpected) { + assertEquals ( + "Execution stopped at wrong line", + lineExpected, + support.getDebugger().getCurrentCallStackFrame().getLineNumber(null) + ); + } } diff --git a/java/debugger.jpda/test/unit/src/org/netbeans/api/debugger/jpda/testapps/StepAndContinueApp.java b/java/debugger.jpda/test/unit/src/org/netbeans/api/debugger/jpda/testapps/StepAndContinueApp.java new file mode 100644 index 0000000..453df94 --- /dev/null +++ b/java/debugger.jpda/test/unit/src/org/netbeans/api/debugger/jpda/testapps/StepAndContinueApp.java @@ -0,0 +1,53 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.api.debugger.jpda.testapps; + +/** + * A sample application where we combine stepping and breakpoints with continue. + * + * @author Martin Entlicher + */ +public class StepAndContinueApp { + + public static void main(String[] args) { + StepAndContinueApp sa = new StepAndContinueApp(); + int x = sa.m1(); // STOP Over4 + x += sa.m2(); // STOP Over5 + x += sa.m3(); // STOP Out7 + } + + private int m1() { + int im1 = 10; // LBREAKPOINT + m2(); // STOP Over1 + m3(); // STOP Over2 + return im1; // STOP Over3 + } + + private int m2() { + int im2 = 20; // STOP Into6 + m3(); + return im2; + } + + private int m3() { + int im3 = 30; // STOP Into8 + return im3; // LBREAKPOINT + } + +} --------------------------------------------------------------------- To unsubscribe, e-mail: commits-unsubscr...@netbeans.apache.org For additional commands, e-mail: commits-h...@netbeans.apache.org For further information about the NetBeans mailing lists, visit: https://cwiki.apache.org/confluence/display/NETBEANS/Mailing+lists