diff --git a/src/share/vm/code/nmethod.cpp b/src/share/vm/code/nmethod.cpp index 089586bac66a5f3ccc4687b2b214b329f1513484..e6cc51aab5ad0dc5e53a5fdf96b26c5c57bf92de 100644 --- a/src/share/vm/code/nmethod.cpp +++ b/src/share/vm/code/nmethod.cpp @@ -619,8 +619,8 @@ nmethod::nmethod( OopMapSet* oop_maps ) : CodeBlob("native nmethod", code_buffer, sizeof(nmethod), nmethod_size, offsets->value(CodeOffsets::Frame_Complete), frame_size, oop_maps), - _compiled_synchronized_native_basic_lock_owner_sp_offset(basic_lock_owner_sp_offset), - _compiled_synchronized_native_basic_lock_sp_offset(basic_lock_sp_offset) + _native_receiver_sp_offset(basic_lock_owner_sp_offset), + _native_basic_lock_sp_offset(basic_lock_sp_offset) { { debug_only(No_Safepoint_Verifier nsv;) @@ -696,8 +696,8 @@ nmethod::nmethod( int frame_size) : CodeBlob("dtrace nmethod", code_buffer, sizeof(nmethod), nmethod_size, offsets->value(CodeOffsets::Frame_Complete), frame_size, NULL), - _compiled_synchronized_native_basic_lock_owner_sp_offset(in_ByteSize(-1)), - _compiled_synchronized_native_basic_lock_sp_offset(in_ByteSize(-1)) + _native_receiver_sp_offset(in_ByteSize(-1)), + _native_basic_lock_sp_offset(in_ByteSize(-1)) { { debug_only(No_Safepoint_Verifier nsv;) @@ -790,8 +790,8 @@ nmethod::nmethod( ) : CodeBlob("nmethod", code_buffer, sizeof(nmethod), nmethod_size, offsets->value(CodeOffsets::Frame_Complete), frame_size, oop_maps), - _compiled_synchronized_native_basic_lock_owner_sp_offset(in_ByteSize(-1)), - _compiled_synchronized_native_basic_lock_sp_offset(in_ByteSize(-1)) + _native_receiver_sp_offset(in_ByteSize(-1)), + _native_basic_lock_sp_offset(in_ByteSize(-1)) { assert(debug_info->oop_recorder() == code_buffer->oop_recorder(), "shared OR"); { diff --git a/src/share/vm/code/nmethod.hpp b/src/share/vm/code/nmethod.hpp index bd6b4a562e452a115955607e2beb0dfa55893193..5fa91f46f890a9b5577d50dd1ed87642d0cefd60 100644 --- a/src/share/vm/code/nmethod.hpp +++ b/src/share/vm/code/nmethod.hpp @@ -210,7 +210,7 @@ class nmethod : public CodeBlob { ExceptionCache *_exception_cache; PcDescCache _pc_desc_cache; - // These are only used for compiled synchronized native methods to + // These are used for compiled synchronized native methods to // locate the owner and stack slot for the BasicLock so that we can // properly revoke the bias of the owner if necessary. They are // needed because there is no debug information for compiled native @@ -220,8 +220,10 @@ class nmethod : public CodeBlob { // sharing between platforms. Note that currently biased locking // will never cause Class instances to be biased but this code // handles the static synchronized case as well. - ByteSize _compiled_synchronized_native_basic_lock_owner_sp_offset; - ByteSize _compiled_synchronized_native_basic_lock_sp_offset; + // JVMTI's GetLocalInstance() also uses these offsets to find the receiver + // for non-static native wrapper frames. + ByteSize _native_receiver_sp_offset; + ByteSize _native_basic_lock_sp_offset; friend class nmethodLocker; @@ -676,11 +678,11 @@ public: bool is_patchable_at(address instr_address); // UseBiasedLocking support - ByteSize compiled_synchronized_native_basic_lock_owner_sp_offset() { - return _compiled_synchronized_native_basic_lock_owner_sp_offset; + ByteSize native_receiver_sp_offset() { + return _native_receiver_sp_offset; } - ByteSize compiled_synchronized_native_basic_lock_sp_offset() { - return _compiled_synchronized_native_basic_lock_sp_offset; + ByteSize native_basic_lock_sp_offset() { + return _native_basic_lock_sp_offset; } // support for code generation diff --git a/src/share/vm/prims/jvmti.xml b/src/share/vm/prims/jvmti.xml index 8d580294157976cddb8abaf54d1af139d615e06c..672a59380f6bc8b2727b472e7b6df8c5d78d543f 100644 --- a/src/share/vm/prims/jvmti.xml +++ b/src/share/vm/prims/jvmti.xml @@ -5649,6 +5649,45 @@ class C2 extends C1 implements I2 { + + Get Local Instance + + This function can be used to retrieve the value of the local object + variable at slot 0 (the "this" object) from non-static + frames. This function can retrieve the "this" object from + native method frames, whereas GetLocalObject() would + return JVMTI_ERROR_OPAQUE_FRAME in those cases. + + new + + + + + + + + The thread of the frame containing the variable's value. + + + + + + The depth of the frame containing the variable's value. + + + + + + On return, points to the variable's value. + + + + + + If the specified frame is a static method frame. + + + Get Local Variable - Int diff --git a/src/share/vm/prims/jvmtiEnv.cpp b/src/share/vm/prims/jvmtiEnv.cpp index 8975ce19d9e9ab9e3ee24d004d7fe65e1afa8a25..26f2511f906ff92d3dc80e37b5d714526bd1df8c 100644 --- a/src/share/vm/prims/jvmtiEnv.cpp +++ b/src/share/vm/prims/jvmtiEnv.cpp @@ -1796,6 +1796,29 @@ JvmtiEnv::GetLocalObject(JavaThread* java_thread, jint depth, jint slot, jobject } } /* end GetLocalObject */ +// Threads_lock NOT held, java_thread not protected by lock +// java_thread - pre-checked +// java_thread - unchecked +// depth - pre-checked as non-negative +// value - pre-checked for NULL +jvmtiError +JvmtiEnv::GetLocalInstance(JavaThread* java_thread, jint depth, jobject* value){ + JavaThread* current_thread = JavaThread::current(); + // rm object is created to clean up the javaVFrame created in + // doit_prologue(), but after doit() is finished with it. + ResourceMark rm(current_thread); + + VM_GetReceiver op(java_thread, current_thread, depth); + VMThread::execute(&op); + jvmtiError err = op.result(); + if (err != JVMTI_ERROR_NONE) { + return err; + } else { + *value = op.value().l; + return JVMTI_ERROR_NONE; + } +} /* end GetLocalInstance */ + // Threads_lock NOT held, java_thread not protected by lock // java_thread - pre-checked diff --git a/src/share/vm/prims/jvmtiImpl.cpp b/src/share/vm/prims/jvmtiImpl.cpp index d461d9eee38ecb88735dfd86a6a51c30aa67784b..90864b68abeee2fa2cf6d99e3e495781d9af2f6c 100644 --- a/src/share/vm/prims/jvmtiImpl.cpp +++ b/src/share/vm/prims/jvmtiImpl.cpp @@ -586,7 +586,6 @@ VM_GetOrSetLocal::VM_GetOrSetLocal(JavaThread* thread, JavaThread* calling_threa { } - vframe *VM_GetOrSetLocal::get_vframe() { if (!_thread->has_last_Java_frame()) { return NULL; @@ -609,7 +608,7 @@ javaVFrame *VM_GetOrSetLocal::get_java_vframe() { } javaVFrame *jvf = (javaVFrame*)vf; - if (!vf->is_java_frame() || jvf->method()->is_native()) { + if (!vf->is_java_frame()) { _result = JVMTI_ERROR_OPAQUE_FRAME; return NULL; } @@ -740,6 +739,15 @@ bool VM_GetOrSetLocal::doit_prologue() { _jvf = get_java_vframe(); NULL_CHECK(_jvf, false); + if (_jvf->method()->is_native()) { + if (getting_receiver() && !_jvf->method()->is_static()) { + return true; + } else { + _result = JVMTI_ERROR_OPAQUE_FRAME; + return false; + } + } + if (!check_slot_type(_jvf)) { return false; } @@ -781,40 +789,46 @@ void VM_GetOrSetLocal::doit() { HandleMark hm; switch (_type) { - case T_INT: locals->set_int_at (_index, _value.i); break; - case T_LONG: locals->set_long_at (_index, _value.j); break; - case T_FLOAT: locals->set_float_at (_index, _value.f); break; - case T_DOUBLE: locals->set_double_at(_index, _value.d); break; - case T_OBJECT: { - Handle ob_h(JNIHandles::resolve_external_guard(_value.l)); - locals->set_obj_at (_index, ob_h); - break; - } - default: ShouldNotReachHere(); + case T_INT: locals->set_int_at (_index, _value.i); break; + case T_LONG: locals->set_long_at (_index, _value.j); break; + case T_FLOAT: locals->set_float_at (_index, _value.f); break; + case T_DOUBLE: locals->set_double_at(_index, _value.d); break; + case T_OBJECT: { + Handle ob_h(JNIHandles::resolve_external_guard(_value.l)); + locals->set_obj_at (_index, ob_h); + break; + } + default: ShouldNotReachHere(); } _jvf->set_locals(locals); } else { - StackValueCollection *locals = _jvf->locals(); - - if (locals->at(_index)->type() == T_CONFLICT) { - memset(&_value, 0, sizeof(_value)); - _value.l = NULL; - return; - } + if (_jvf->method()->is_native() && _jvf->is_compiled_frame()) { + assert(getting_receiver(), "Can only get here when getting receiver"); + oop receiver = _jvf->fr().get_native_receiver(); + _value.l = JNIHandles::make_local(_calling_thread, receiver); + } else { + StackValueCollection *locals = _jvf->locals(); + + if (locals->at(_index)->type() == T_CONFLICT) { + memset(&_value, 0, sizeof(_value)); + _value.l = NULL; + return; + } - switch (_type) { - case T_INT: _value.i = locals->int_at (_index); break; - case T_LONG: _value.j = locals->long_at (_index); break; - case T_FLOAT: _value.f = locals->float_at (_index); break; - case T_DOUBLE: _value.d = locals->double_at(_index); break; - case T_OBJECT: { - // Wrap the oop to be returned in a local JNI handle since - // oops_do() no longer applies after doit() is finished. - oop obj = locals->obj_at(_index)(); - _value.l = JNIHandles::make_local(_calling_thread, obj); - break; - } - default: ShouldNotReachHere(); + switch (_type) { + case T_INT: _value.i = locals->int_at (_index); break; + case T_LONG: _value.j = locals->long_at (_index); break; + case T_FLOAT: _value.f = locals->float_at (_index); break; + case T_DOUBLE: _value.d = locals->double_at(_index); break; + case T_OBJECT: { + // Wrap the oop to be returned in a local JNI handle since + // oops_do() no longer applies after doit() is finished. + oop obj = locals->obj_at(_index)(); + _value.l = JNIHandles::make_local(_calling_thread, obj); + break; + } + default: ShouldNotReachHere(); + } } } } @@ -825,6 +839,10 @@ bool VM_GetOrSetLocal::allow_nested_vm_operations() const { } +VM_GetReceiver::VM_GetReceiver( + JavaThread* thread, JavaThread* caller_thread, jint depth) + : VM_GetOrSetLocal(thread, caller_thread, depth, 0) {} + ///////////////////////////////////////////////////////////////////////////////////////// // diff --git a/src/share/vm/prims/jvmtiImpl.hpp b/src/share/vm/prims/jvmtiImpl.hpp index 1c07d756150d721ab589450f534323a838ada38c..df28abf7d721bcd77bc3c8f0acebc3ea806e8aa4 100644 --- a/src/share/vm/prims/jvmtiImpl.hpp +++ b/src/share/vm/prims/jvmtiImpl.hpp @@ -355,7 +355,7 @@ bool JvmtiCurrentBreakpoints::is_breakpoint(address bcp) { // to the thread simultaneously. // class VM_GetOrSetLocal : public VM_Operation { -private: + protected: JavaThread* _thread; JavaThread* _calling_thread; jint _depth; @@ -365,6 +365,10 @@ private: javaVFrame* _jvf; bool _set; + // It is possible to get the receiver out of a non-static native wrapper + // frame. Use VM_GetReceiver to do this. + virtual bool getting_receiver() const { return false; } + jvmtiError _result; vframe* get_vframe(); @@ -395,6 +399,15 @@ public: static bool is_assignable(const char* ty_sign, Klass* klass, Thread* thread); }; +class VM_GetReceiver : public VM_GetOrSetLocal { + protected: + virtual bool getting_receiver() const { return true; } + + public: + VM_GetReceiver(JavaThread* thread, JavaThread* calling_thread, jint depth); + const char* name() const { return "get receiver"; } +}; + /////////////////////////////////////////////////////////////// // diff --git a/src/share/vm/runtime/frame.cpp b/src/share/vm/runtime/frame.cpp index 90167f36bb05aad7c8a2bc1aaa31df5d983cc0dd..ee613e1b9c354d162b6ab375c5b107bfdfd787f9 100644 --- a/src/share/vm/runtime/frame.cpp +++ b/src/share/vm/runtime/frame.cpp @@ -1071,28 +1071,20 @@ oop* frame::oopmapreg_to_location(VMReg reg, const RegisterMap* reg_map) const { } } -BasicLock* frame::compiled_synchronized_native_monitor(nmethod* nm) { - if (nm == NULL) { - assert(_cb != NULL && _cb->is_nmethod() && - nm->method()->is_native() && - nm->method()->is_synchronized(), - "should not call this otherwise"); - nm = (nmethod*) _cb; - } - int byte_offset = in_bytes(nm->compiled_synchronized_native_basic_lock_sp_offset()); +BasicLock* frame::get_native_monitor() { + nmethod* nm = (nmethod*)_cb; + assert(_cb != NULL && _cb->is_nmethod() && nm->method()->is_native(), + "Should not call this unless it's a native nmethod"); + int byte_offset = in_bytes(nm->native_basic_lock_sp_offset()); assert(byte_offset >= 0, "should not see invalid offset"); return (BasicLock*) &sp()[byte_offset / wordSize]; } -oop frame::compiled_synchronized_native_monitor_owner(nmethod* nm) { - if (nm == NULL) { - assert(_cb != NULL && _cb->is_nmethod() && - nm->method()->is_native() && - nm->method()->is_synchronized(), - "should not call this otherwise"); - nm = (nmethod*) _cb; - } - int byte_offset = in_bytes(nm->compiled_synchronized_native_basic_lock_owner_sp_offset()); +oop frame::get_native_receiver() { + nmethod* nm = (nmethod*)_cb; + assert(_cb != NULL && _cb->is_nmethod() && nm->method()->is_native(), + "Should not call this unless it's a native nmethod"); + int byte_offset = in_bytes(nm->native_receiver_sp_offset()); assert(byte_offset >= 0, "should not see invalid offset"); oop owner = ((oop*) sp())[byte_offset / wordSize]; assert( Universe::heap()->is_in(owner), "bad receiver" ); diff --git a/src/share/vm/runtime/frame.hpp b/src/share/vm/runtime/frame.hpp index d253e5b4705c62d5072161d80fb8c457bff6f56d..64055dada61999a799195d66e3e59b0b3e411f86 100644 --- a/src/share/vm/runtime/frame.hpp +++ b/src/share/vm/runtime/frame.hpp @@ -254,10 +254,10 @@ class frame VALUE_OBJ_CLASS_SPEC { // Return the monitor owner and BasicLock for compiled synchronized // native methods so that biased locking can revoke the receiver's - // bias if necessary. Takes optional nmethod for this frame as - // argument to avoid performing repeated lookups in code cache. - BasicLock* compiled_synchronized_native_monitor (nmethod* nm = NULL); - oop compiled_synchronized_native_monitor_owner(nmethod* nm = NULL); + // bias if necessary. This is also used by JVMTI's GetLocalInstance method + // (via VM_GetReceiver) to retrieve the receiver from a native wrapper frame. + BasicLock* get_native_monitor(); + oop get_native_receiver(); // Find receiver for an invoke when arguments are just pushed on stack (i.e., callee stack-frame is // not setup) diff --git a/src/share/vm/runtime/vframe_hp.cpp b/src/share/vm/runtime/vframe_hp.cpp index 4589195b4841c23fdc5015e8406ad318cfbb738b..274bfc604ce8f724dde6bafc6d60fac1053185ea 100644 --- a/src/share/vm/runtime/vframe_hp.cpp +++ b/src/share/vm/runtime/vframe_hp.cpp @@ -207,8 +207,8 @@ GrowableArray* compiledVFrame::monitors() const { GrowableArray *monitors = new GrowableArray(1); // Casting away const frame& fr = (frame&) _fr; - MonitorInfo* info = new MonitorInfo(fr.compiled_synchronized_native_monitor_owner(nm), - fr.compiled_synchronized_native_monitor(nm), false, false); + MonitorInfo* info = new MonitorInfo( + fr.get_native_receiver(), fr.get_native_monitor(), false, false); monitors->push(info); return monitors; }