diff --git a/src/jdk.jdwp.agent/share/native/libjdwp/stepControl.c b/src/jdk.jdwp.agent/share/native/libjdwp/stepControl.c index 0611e8fc213..4e672556449 100644 --- a/src/jdk.jdwp.agent/share/native/libjdwp/stepControl.c +++ b/src/jdk.jdwp.agent/share/native/libjdwp/stepControl.c @@ -166,6 +166,7 @@ static jvmtiError initState(JNIEnv *env, jthread thread, StepRequest *step) { jvmtiError error; + jboolean needFramePopHandler = JNI_FALSE; /* * Initial values that may be changed below @@ -186,33 +187,29 @@ initState(JNIEnv *env, jthread thread, StepRequest *step) return JVMTI_ERROR_NONE; } - /* - * Try to get a notification on frame pop. If we're in an opaque frame - * we won't be able to, but we can use other methods to detect that - * a native frame has exited. - * - * TO DO: explain the need for this notification. - */ - error = JVMTI_FUNC_PTR(gdata->jvmti,NotifyFramePop) - (gdata->jvmti, thread, 0); - if (error == JVMTI_ERROR_OPAQUE_FRAME) { - step->fromNative = JNI_TRUE; - error = JVMTI_ERROR_NONE; - /* continue without error */ - } else if (error == JVMTI_ERROR_DUPLICATE) { - error = JVMTI_ERROR_NONE; - /* Already being notified, continue without error */ - } else if (error != JVMTI_ERROR_NONE) { - return error; - } - LOG_STEP(("initState(): frame=%d", step->fromStackDepth)); /* - * Note: we can't undo the frame pop notify, so - * we'll just have to let the handler ignore it if - * there are any errors below. + * See if this is a native frame. */ + jmethodID method; + WITH_LOCAL_REFS(env, 1) { + jclass clazz; + jlocation location; + error = getFrameLocation(thread, &clazz, &method, &location); + } END_WITH_LOCAL_REFS(env); + if (error != JVMTI_ERROR_NONE) { + return error; + } + jint modifiers; + error = methodModifiers(method, &modifiers); + if (error != JVMTI_ERROR_NONE) { + return error; + } + if ((modifiers & MOD_NATIVE) != 0) { + step->fromNative = JNI_TRUE; + return JVMTI_ERROR_NONE; + } if (step->granularity == JDWP_STEP_SIZE(LINE) ) { @@ -241,12 +238,53 @@ initState(JNIEnv *env, jthread thread, StepRequest *step) &step->lineEntryCount, &step->lineEntries); } } - step->fromLine = findLineNumber(thread, location, - step->lineEntries, step->lineEntryCount); + step->fromLine = + findLineNumber(thread, location, step->lineEntries, step->lineEntryCount); + + jlocation startLocation, endLocation; + error = methodLocation(method, &startLocation, &endLocation); + if (error == JVMTI_ERROR_NONE) { + jint lastLine = + findLineNumber(thread, endLocation, step->lineEntries, step->lineEntryCount); + if (step->fromLine == lastLine) { + // We'll need the FramePop handler if this is the last line of the method, + // and we are stepping OVER (we already know we are LINE stepping). This + // is because the next single step event will be in the callee, and we need + // to mark this step event as completed. + if (step->depth == JDWP_STEP_DEPTH(OVER)) { + needFramePopHandler = JNI_TRUE; + } + } + } + } } END_WITH_LOCAL_REFS(env); + } else { + JDI_ASSERT(step->granularity == JDWP_STEP_SIZE(MIN)); + // We'll need the FramePop handler if we are bytecode stepping. Why??? + needFramePopHandler = JNI_TRUE; + } + + if (step->depth == JDWP_STEP_DEPTH(OUT)) { + // We'll need the FramePop handler if we are stepping out because JVMTI + // single stepping will not be enabled, so the FramePop is the only way + // we'll know when the step out completed. + needFramePopHandler = JNI_TRUE; + } + /* + * Try to get a notification on frame pop. If we're in an opaque frame + * we won't be able to, but we can use other methods to detect that + * a native frame has exited. + */ + error = JVMTI_FUNC_PTR(gdata->jvmti,NotifyFramePop) + (gdata->jvmti, thread, 0); + JDI_ASSERT(error != JVMTI_ERROR_OPAQUE_FRAME); // native frame checked for ealier + if (error == JVMTI_ERROR_DUPLICATE) { + error = JVMTI_ERROR_NONE; /* Already being notified, continue without error */ + } else if (error != JVMTI_ERROR_NONE) { + return error; } return error; @@ -669,7 +707,7 @@ stepControl_handleStep(JNIEnv *env, jthread thread, * the original native method returned to another * native method which, in turn, invoked a Java method. * - * Since the original frame was native, we were unable + * Since the original frame was native, we were unable * to ask for a frame pop event, and, thus, could not * set the step->frameExited flag when the original * method was done. Instead we end up here