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;
}