in modules/jpda/src/main/native/jdwp/common/agent/core/ThreadManager.cpp [879:1000]
void ThreadManager::PerformPopFrames(JNIEnv* jni, jint framesToPop, jthread thread)
throw(AgentException)
{
JDWP_TRACE_ENTRY("PerformPopFrames(" << jni << ',' << framesToPop << ',' << thread << ')');
MonitorAutoLock thrdmgrMonitorLock(m_thrdmgrMonitor JDWP_FILE_LINE);
// thread should be suspended
if (!GetThreadManager().IsSuspended(thread)) {
throw AgentException(JDWP_ERROR_THREAD_NOT_SUSPENDED);
}
// The following check is disabled, because JVMTI and JDWP specifications
// are unclear if PopFrames should be invoked only for thread on an event.
// Current algorithm supports PopFrames command for any suspended thread.
/*
if (!GetThreadManager().IsSuspendedOnEvent(jni, thread)) {
throw AgentException(JDWP_ERROR_THREAD_NOT_SUSPENDED);
}
*/
jvmtiError err;
char* threadName = 0;
#ifndef NDEBUG
if (JDWP_TRACE_ENABLED(LOG_KIND_THREAD)) {
jvmtiThreadInfo threadInfo;
JVMTI_TRACE(err, GetJvmtiEnv()->GetThreadInfo(thread, &threadInfo));
threadName = threadInfo.name;
}
#endif // NDEBUG
JvmtiAutoFree af(threadName);
// The following check is just for sure.
// This algorithm supposes that there are no invoke method handlers registered.
// Otherwise, active invoke handlers could break popFrame process.
{
MonitorAutoLock lockExecList(m_execMonitor JDWP_FILE_LINE);
if (!m_execList.empty()) {
throw AgentException(JDWP_ERROR_THREAD_NOT_SUSPENDED);
}
}
jint frameCount;
JVMTI_TRACE(err, GetJvmtiEnv()->GetFrameCount(thread, &frameCount));
if (err != JVMTI_ERROR_NONE) {
throw AgentException(err);
}
if (frameCount <= framesToPop) {
throw AgentException(JDWP_ERROR_INVALID_FRAMEID);
}
// if there is native frame, pop frame can't be performed
CheckNativeFrameExistence(thread, framesToPop);
MonitorAutoLock popFramesMonitorLock(m_popFramesMonitor JDWP_FILE_LINE);
try {
m_popFramesThread = thread;
// enabling step request on thread where PopFrame command is performed
JDWP_TRACE_THREAD("PerformPopFrames: enable internal step: thread="
<< JDWP_CHECK_NULL(threadName));
GetRequestManager().EnableInternalStepRequest(jni, m_popFramesThread);
// cycle where topmost frames are popped one after one
for (int i = 0; i < framesToPop; i++) {
// pop topmost frame, thread is already suspended on event
JDWP_TRACE_THREAD("PerformPopFrames: pop: frame#=" << i
<< ", thread=" << JDWP_CHECK_NULL(threadName));
JVMTI_TRACE(err, GetJvmtiEnv()->PopFrame(m_popFramesThread));
if (err != JVMTI_ERROR_NONE) {
throw AgentException(err);
}
// resume thread
JDWP_TRACE_THREAD("PerformPopFrames: resume: thread="
<< JDWP_CHECK_NULL(threadName));
JVMTI_TRACE(err, GetJvmtiEnv()->ResumeThread(m_popFramesThread));
JDWP_ASSERT(err != JVMTI_ERROR_THREAD_NOT_SUSPENDED);
if (err != JVMTI_ERROR_NONE)
throw AgentException(err);
// wait for thread to achieve suspention point in InternalSingleStep handler
JDWP_TRACE_THREAD("PerformPopFrames: wait for step: thread="
<< JDWP_CHECK_NULL(threadName));
m_popFramesMonitorReleased = false;
while (!m_popFramesMonitorReleased) {
m_popFramesMonitor->Wait();
}
{
// suspend thread on suspention point
MonitorAutoLock stepMonitorLock(m_stepMonitor JDWP_FILE_LINE);
JDWP_TRACE_THREAD("PerformPopFrames: suspend: thread="
<< JDWP_CHECK_NULL(threadName));
JVMTI_TRACE(err, GetJvmtiEnv()->SuspendThread(m_popFramesThread));
JDWP_ASSERT(err != JVMTI_ERROR_THREAD_SUSPENDED);
if (err != JVMTI_ERROR_NONE)
throw AgentException(err);
// notify suspended thread on suspention point
m_stepMonitorReleased = true;
m_stepMonitor->NotifyAll();
JDWP_TRACE_THREAD("PerformPopFrames: notify: thread="
<< JDWP_CHECK_NULL(threadName));
}
}
GetObjectManager().DeleteFrameIDs(jni, m_popFramesThread);
JDWP_TRACE_THREAD("PerformPopFrames: disable internal step: thread="
<< JDWP_CHECK_NULL(threadName));
GetRequestManager().DisableInternalStepRequest(jni, m_popFramesThread);
m_popFramesThread = 0;
} catch (AgentException& e) {
JDWP_INFO("JDWP error: " << e.what() << " [" << e.ErrCode() << "]");
JDWP_TRACE_THREAD("PerformPopFrames: disable internal step: thread="
<< JDWP_CHECK_NULL(threadName));
GetRequestManager().DisableInternalStepRequest(jni, m_popFramesThread);
m_popFramesThread = 0;
throw(e);
}
}