--- old/src/share/vm/prims/jvmtiEnv.cpp Thu Feb 27 02:37:15 2014 +++ new/src/share/vm/prims/jvmtiEnv.cpp Thu Feb 27 02:37:14 2014 @@ -1464,7 +1464,19 @@ // It's fine to update the thread state here because no JVMTI events // shall be posted for this PopFrame. - state->update_for_pop_top_frame(); + // It is only safe to perform the direct operation on the current + // thread. All other usage needs to use a vm-safepoint-op for safety. + if (java_thread == JavaThread::current()) { + state->update_for_pop_top_frame(); + } else { + VM_UpdateForPopTopFrame op(state); + VMThread::execute(&op); + jvmtiError err = op.result(); + if (err != JVMTI_ERROR_NONE) { + return err; + } + } + java_thread->set_popframe_condition(JavaThread::popframe_pending_bit); // Set pending step flag for this popframe and it is cleared when next // step event is posted. @@ -1505,6 +1517,7 @@ // depth - pre-checked as non-negative jvmtiError JvmtiEnv::NotifyFramePop(JavaThread* java_thread, jint depth) { + jvmtiError err = JVMTI_ERROR_NONE; ResourceMark rm; uint32_t debug_bits = 0; @@ -1532,10 +1545,17 @@ assert(vf->frame_pointer() != NULL, "frame pointer mustn't be NULL"); - int frame_number = state->count_frames() - depth; - state->env_thread_state(this)->set_frame_pop(frame_number); - - return JVMTI_ERROR_NONE; + // It is only safe to perform the direct operation on the current + // thread. All other usage needs to use a vm-safepoint-op for safety. + if (java_thread == JavaThread::current()) { + int frame_number = state->count_frames() - depth; + state->env_thread_state(this)->set_frame_pop(frame_number); + } else { + VM_SetFramePop op(this, state, depth); + VMThread::execute(&op); + err = op.result(); + } + return err; } /* end NotifyFramePop */ --- old/src/share/vm/prims/jvmtiEnvBase.hpp Thu Feb 27 02:37:18 2014 +++ new/src/share/vm/prims/jvmtiEnvBase.hpp Thu Feb 27 02:37:17 2014 @@ -334,7 +334,59 @@ JvmtiEnv* next(JvmtiEnvBase* env) { return env->next_environment(); } }; +// VM operation to update for pop top frame. +class VM_UpdateForPopTopFrame : public VM_Operation { +private: + JvmtiThreadState* _state; + jvmtiError _result; +public: + VM_UpdateForPopTopFrame(JvmtiThreadState* state) { + _state = state; + _result = JVMTI_ERROR_NONE; + } + VMOp_Type type() const { return VMOp_UpdateForPopTopFrame; } + jvmtiError result() { return _result; } + void doit() { + JavaThread* jt = _state->get_thread(); + if (Threads::includes(jt) && !jt->is_exiting() && jt->threadObj() != NULL) { + _state->update_for_pop_top_frame(); + } else { + _result = JVMTI_ERROR_THREAD_NOT_ALIVE; + } + } +}; + +// VM operation to set frame pop. +class VM_SetFramePop : public VM_Operation { +private: + JvmtiEnv *_env; + JvmtiThreadState* _state; + jint _depth; + jvmtiError _result; + +public: + VM_SetFramePop(JvmtiEnv *env, JvmtiThreadState* state, jint depth) { + _env = env; + _state = state; + _depth = depth; + _result = JVMTI_ERROR_NONE; + } + bool allow_nested_vm_operations() const { return true; } + VMOp_Type type() const { return VMOp_SetFramePop; } + jvmtiError result() { return _result; } + void doit() { + JavaThread* jt = _state->get_thread(); + if (Threads::includes(jt) && !jt->is_exiting() && jt->threadObj() != NULL) { + int frame_number = _state->count_frames() - _depth; + _state->env_thread_state((JvmtiEnvBase*)_env)->set_frame_pop(frame_number); + } else { + _result = JVMTI_ERROR_THREAD_NOT_ALIVE; + } + } +}; + + // VM operation to get monitor information with stack depth. class VM_GetOwnedMonitorInfo : public VM_Operation { private: --- old/src/share/vm/prims/jvmtiEnvThreadState.cpp Thu Feb 27 02:37:20 2014 +++ new/src/share/vm/prims/jvmtiEnvThreadState.cpp Thu Feb 27 02:37:20 2014 @@ -191,11 +191,10 @@ JvmtiFramePops* JvmtiEnvThreadState::get_frame_pops() { #ifdef ASSERT - uint32_t debug_bits = 0; + Thread* cur = Thread::current(); #endif - assert(get_thread() == Thread::current() || JvmtiEnv::is_thread_fully_suspended(get_thread(), false, &debug_bits), - "frame pop data only accessible from same thread or while suspended"); - + assert(get_thread() == cur || (cur->is_VM_thread() && SafepointSynchronize::is_at_safepoint()), + "frame pop data only accessible from same thread or at safepoint"); if (_frame_pops == NULL) { _frame_pops = new JvmtiFramePops(); assert(_frame_pops != NULL, "_frame_pops != NULL"); @@ -210,10 +209,10 @@ void JvmtiEnvThreadState::set_frame_pop(int frame_number) { #ifdef ASSERT - uint32_t debug_bits = 0; + Thread* cur = Thread::current(); #endif - assert(get_thread() == Thread::current() || JvmtiEnv::is_thread_fully_suspended(get_thread(), false, &debug_bits), - "frame pop data only accessible from same thread or while suspended"); + assert(get_thread() == cur || (cur->is_VM_thread() && SafepointSynchronize::is_at_safepoint()), + "frame pop data only accessible from same thread or at safepoint"); JvmtiFramePop fpop(frame_number); JvmtiEventController::set_frame_pop(this, fpop); } @@ -221,10 +220,10 @@ void JvmtiEnvThreadState::clear_frame_pop(int frame_number) { #ifdef ASSERT - uint32_t debug_bits = 0; + Thread* cur = Thread::current(); #endif - assert(get_thread() == Thread::current() || JvmtiEnv::is_thread_fully_suspended(get_thread(), false, &debug_bits), - "frame pop data only accessible from same thread or while suspended"); + assert(get_thread() == cur || (cur->is_VM_thread() && SafepointSynchronize::is_at_safepoint()), + "frame pop data only accessible from same thread or at safepoint"); JvmtiFramePop fpop(frame_number); JvmtiEventController::clear_frame_pop(this, fpop); } @@ -232,10 +231,10 @@ void JvmtiEnvThreadState::clear_to_frame_pop(int frame_number) { #ifdef ASSERT - uint32_t debug_bits = 0; + Thread* cur = Thread::current(); #endif - assert(get_thread() == Thread::current() || JvmtiEnv::is_thread_fully_suspended(get_thread(), false, &debug_bits), - "frame pop data only accessible from same thread or while suspended"); + assert(get_thread() == cur || (cur->is_VM_thread() && SafepointSynchronize::is_at_safepoint()), + "frame pop data only accessible from same thread or at safepoint"); JvmtiFramePop fpop(frame_number); JvmtiEventController::clear_to_frame_pop(this, fpop); } @@ -243,10 +242,10 @@ bool JvmtiEnvThreadState::is_frame_pop(int cur_frame_number) { #ifdef ASSERT - uint32_t debug_bits = 0; + Thread* cur = Thread::current(); #endif - assert(get_thread() == Thread::current() || JvmtiEnv::is_thread_fully_suspended(get_thread(), false, &debug_bits), - "frame pop data only accessible from same thread or while suspended"); + assert(get_thread() == cur || (cur->is_VM_thread() && SafepointSynchronize::is_at_safepoint()), + "frame pop data only accessible from same thread or at safepoint"); if (!get_thread()->is_interp_only_mode() || _frame_pops == NULL) { return false; } --- old/src/share/vm/prims/jvmtiEventController.cpp Thu Feb 27 02:37:23 2014 +++ new/src/share/vm/prims/jvmtiEventController.cpp Thu Feb 27 02:37:22 2014 @@ -989,7 +989,6 @@ void JvmtiEventController::set_frame_pop(JvmtiEnvThreadState *ets, JvmtiFramePop fpop) { - MutexLocker mu(JvmtiThreadState_lock); JvmtiEventControllerPrivate::set_frame_pop(ets, fpop); } @@ -996,7 +995,6 @@ void JvmtiEventController::clear_frame_pop(JvmtiEnvThreadState *ets, JvmtiFramePop fpop) { - MutexLocker mu(JvmtiThreadState_lock); JvmtiEventControllerPrivate::clear_frame_pop(ets, fpop); } @@ -1003,7 +1001,6 @@ void JvmtiEventController::clear_to_frame_pop(JvmtiEnvThreadState *ets, JvmtiFramePop fpop) { - MutexLocker mu(JvmtiThreadState_lock); JvmtiEventControllerPrivate::clear_to_frame_pop(ets, fpop); } --- old/src/share/vm/prims/jvmtiThreadState.cpp Thu Feb 27 02:37:26 2014 +++ new/src/share/vm/prims/jvmtiThreadState.cpp Thu Feb 27 02:37:25 2014 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -63,6 +63,7 @@ _vm_object_alloc_event_collector = NULL; _the_class_for_redefinition_verification = NULL; _scratch_class_for_redefinition_verification = NULL; + _cur_stack_depth = UNKNOWN_STACK_DEPTH; // JVMTI ForceEarlyReturn support _pending_step_for_earlyret = false; @@ -214,9 +215,10 @@ // Helper routine used in several places int JvmtiThreadState::count_frames() { #ifdef ASSERT + Thread *cur = Thread::current(); uint32_t debug_bits = 0; #endif - assert(SafepointSynchronize::is_at_safepoint() || + assert((cur->is_VM_thread() && SafepointSynchronize::is_at_safepoint()) || JvmtiEnv::is_thread_fully_suspended(get_thread(), false, &debug_bits), "at safepoint or must be suspended"); @@ -244,14 +246,10 @@ void JvmtiThreadState::invalidate_cur_stack_depth() { Thread *cur = Thread::current(); - uint32_t debug_bits = 0; - // The caller can be the VMThread at a safepoint, the current thread - // or the target thread must be suspended. guarantee((cur->is_VM_thread() && SafepointSynchronize::is_at_safepoint()) || - (JavaThread *)cur == get_thread() || - JvmtiEnv::is_thread_fully_suspended(get_thread(), false, &debug_bits), - "sanity check"); + (JavaThread *)cur == get_thread(), + "must be current thread or at safepoint"); _cur_stack_depth = UNKNOWN_STACK_DEPTH; } @@ -280,11 +278,12 @@ } int JvmtiThreadState::cur_stack_depth() { - uint32_t debug_bits = 0; - guarantee(JavaThread::current() == get_thread() || - JvmtiEnv::is_thread_fully_suspended(get_thread(), false, &debug_bits), - "must be current thread or suspended"); + Thread *cur = Thread::current(); + guarantee((cur->is_VM_thread() && SafepointSynchronize::is_at_safepoint()) || + (JavaThread *)cur == get_thread(), + "must be current thread or at safepoint"); + if (!is_interp_only_mode() || _cur_stack_depth == UNKNOWN_STACK_DEPTH) { _cur_stack_depth = count_frames(); } else { --- old/src/share/vm/runtime/vm_operations.hpp Thu Feb 27 02:37:29 2014 +++ new/src/share/vm/runtime/vm_operations.hpp Thu Feb 27 02:37:28 2014 @@ -74,6 +74,8 @@ template(PopulateDumpSharedSpace) \ template(JNIFunctionTableCopier) \ template(RedefineClasses) \ + template(UpdateForPopTopFrame) \ + template(SetFramePop) \ template(GetOwnedMonitorInfo) \ template(GetObjectMonitorUsage) \ template(GetCurrentContendedMonitor) \