Skip to content

Commit a66fa77

Browse files
committed
fix issues with single stepping during method exit event
1 parent c73f05b commit a66fa77

File tree

2 files changed

+25
-24
lines changed

2 files changed

+25
-24
lines changed

src/jdk.jdwp.agent/share/native/libjdwp/stepControl.c

Lines changed: 23 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 1998, 2025, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 1998, 2026, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -171,18 +171,16 @@ initState(JNIEnv *env, jthread thread, StepRequest *step)
171171
* Initial values that may be changed below
172172
*/
173173
step->fromLine = -1;
174-
step->fromNative = JNI_FALSE;
174+
step->notifyFramePopFailed = JNI_FALSE;
175175
step->frameExited = JNI_FALSE;
176176
step->fromStackDepth = getFrameCount(thread);
177177

178178
if (step->fromStackDepth <= 0) {
179179
/*
180-
* If there are no stack frames, treat the step as though
181-
* from a native frame. This is most likely to occur at the
182-
* beginning of a debug session, right after the VM_INIT event,
183-
* so we need to do something intelligent.
180+
* If there are no stack frames, there is nothing more to do here. If we are
181+
* doing a step INTO, initEvents() will enable stepping. Otherwise it is
182+
* not enabled because there is nothing to step OVER or OUT of.
184183
*/
185-
step->fromNative = JNI_TRUE;
186184
return JVMTI_ERROR_NONE;
187185
}
188186

@@ -196,7 +194,13 @@ initState(JNIEnv *env, jthread thread, StepRequest *step)
196194
error = JVMTI_FUNC_PTR(gdata->jvmti,NotifyFramePop)
197195
(gdata->jvmti, thread, 0);
198196
if (error == JVMTI_ERROR_OPAQUE_FRAME) {
199-
step->fromNative = JNI_TRUE;
197+
// OPAQUE_FRAME doesn't always mean native method. It's rare that it doesn't, and
198+
// means that there is something about the frame's statw that prevents setting up
199+
// a NotifyFramePop. One example is a frame that is in the process of returning,
200+
// which can happen if we start single stepping after getting a MethodExit event.
201+
// In either any case, we need to be aware that there will be no FramePop event
202+
// when this frame exits.
203+
step->notifyFramePopFailed = JNI_TRUE;
200204
error = JVMTI_ERROR_NONE;
201205
/* continue without error */
202206
} else if (error == JVMTI_ERROR_DUPLICATE) {
@@ -761,31 +765,28 @@ initEvents(jthread thread, StepRequest *step)
761765
}
762766

763767
}
768+
764769
/*
765-
* Initially enable stepping:
766-
* 1) For step into, always
767-
* 2) For step over, unless right after the VM_INIT.
768-
* Enable stepping for STEP_MIN or STEP_LINE with or without line numbers.
769-
* If the class is redefined then non EMCP methods may not have line
770-
* number info. So enable line stepping for non line number so that it
771-
* behaves like STEP_MIN/STEP_OVER.
772-
* 3) For step out, only if stepping from native, except right after VM_INIT
773-
*
774-
* (right after VM_INIT, a step->over or out is identical to running
775-
* forever)
770+
* Enable step events if necessary. Note that right after VM_INIT, a
771+
* step OVER or OUT is identical to running forever, so we only enable
772+
* step events if fromStackDepth > 0.
776773
*/
777774
switch (step->depth) {
778775
case JDWP_STEP_DEPTH(INTO):
779776
enableStepping(thread);
780777
break;
781778
case JDWP_STEP_DEPTH(OVER):
782-
if (step->fromStackDepth > 0 && !step->fromNative ) {
779+
// We need to always enable for OVER (except right after VM_INIT).
780+
// If we are in a native method, that is the only way to find out
781+
// that we have returned to a java method.
782+
if (step->fromStackDepth > 0) {
783783
enableStepping(thread);
784784
}
785785
break;
786786
case JDWP_STEP_DEPTH(OUT):
787-
if (step->fromNative &&
788-
(step->fromStackDepth > 0)) {
787+
// We rely on the FramePop event to tell us when we exit the current frame.
788+
// If NotifyFramePop failed, then we need to enable stepping.
789+
if (step->notifyFramePopFailed && (step->fromStackDepth > 0)) {
789790
enableStepping(thread);
790791
}
791792
break;

src/jdk.jdwp.agent/share/native/libjdwp/stepControl.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 1998, 2005, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 1998, 2026, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -37,7 +37,7 @@ typedef struct {
3737
/* State */
3838
jboolean pending;
3939
jboolean frameExited; /* for depth == STEP_OVER or STEP_OUT */
40-
jboolean fromNative;
40+
jboolean notifyFramePopFailed;
4141
jint fromStackDepth; /* for all but STEP_INTO STEP_INSTRUCTION */
4242
jint fromLine; /* for granularity == STEP_LINE */
4343
jmethodID method; /* Where line table came from. */

0 commit comments

Comments
 (0)