7004582: Add GetThisObject() function to JVMTI 1.2
authorkamg
Thu, 09 Dec 2010 15:04:26 -0500
changeset 7444 be338e543a57
parent 7443 39c85d63abf2
child 7445 57d387675180
7004582: Add GetThisObject() function to JVMTI 1.2 Summary: Add 'GetThisObject' function Reviewed-by: never, coleenp
hotspot/src/share/vm/code/nmethod.cpp
hotspot/src/share/vm/code/nmethod.hpp
hotspot/src/share/vm/prims/jvmti.xml
hotspot/src/share/vm/prims/jvmtiEnv.cpp
hotspot/src/share/vm/prims/jvmtiImpl.cpp
hotspot/src/share/vm/prims/jvmtiImpl.hpp
hotspot/src/share/vm/runtime/frame.cpp
hotspot/src/share/vm/runtime/frame.hpp
hotspot/src/share/vm/runtime/vframe_hp.cpp
--- a/hotspot/src/share/vm/code/nmethod.cpp	Thu Dec 09 17:53:22 2010 +0300
+++ b/hotspot/src/share/vm/code/nmethod.cpp	Thu Dec 09 15:04:26 2010 -0500
@@ -619,8 +619,8 @@
   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 @@
   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 @@
   )
   : 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");
   {
--- a/hotspot/src/share/vm/code/nmethod.hpp	Thu Dec 09 17:53:22 2010 +0300
+++ b/hotspot/src/share/vm/code/nmethod.hpp	Thu Dec 09 15:04:26 2010 -0500
@@ -210,7 +210,7 @@
   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 @@
   // 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 @@
   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
--- a/hotspot/src/share/vm/prims/jvmti.xml	Thu Dec 09 17:53:22 2010 +0300
+++ b/hotspot/src/share/vm/prims/jvmti.xml	Thu Dec 09 15:04:26 2010 -0500
@@ -5649,6 +5649,45 @@
       </errors>
     </function>
 
+    <function id="GetLocalInstance" num="155" since="1.2">
+      <synopsis>Get Local Instance</synopsis>
+      <description>
+        This function can be used to retrieve the value of the local object
+        variable at slot 0 (the "<code>this</code>" object) from non-static
+        frames.  This function can retrieve the "<code>this</code>" object from
+        native method frames, whereas <code>GetLocalObject()</code> would 
+        return <code>JVMTI_ERROR_OPAQUE_FRAME</code> in those cases.
+      </description>
+      <origin>new</origin>
+      <capabilities>
+	<required id="can_access_local_variables"></required>
+      </capabilities>
+      <parameters>
+ 	<param id="thread">
+	  <jthread null="current" frame="frame"/>
+	  <description>
+	    The thread of the frame containing the variable's value.
+	  </description>
+	</param>
+	<param id="depth">
+	  <jframeID thread="thread"/>
+	  <description>
+	    The depth of the frame containing the variable's value.
+	  </description>
+	</param>
+	<param id="value_ptr">
+	  <outptr><jobject/></outptr>
+	    <description>
+	      On return, points to the variable's value. 
+	    </description>
+	</param>
+      </parameters>
+      <errors>
+	<error id="JVMTI_ERROR_INVALID_SLOT">
+	  If the specified frame is a static method frame.
+	</error>
+      </errors>
+    </function>
     <function id="GetLocalInt" num="22">
       <synopsis>Get Local Variable - Int</synopsis>
       <description>
--- a/hotspot/src/share/vm/prims/jvmtiEnv.cpp	Thu Dec 09 17:53:22 2010 +0300
+++ b/hotspot/src/share/vm/prims/jvmtiEnv.cpp	Thu Dec 09 15:04:26 2010 -0500
@@ -1796,6 +1796,29 @@
   }
 } /* 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
--- a/hotspot/src/share/vm/prims/jvmtiImpl.cpp	Thu Dec 09 17:53:22 2010 +0300
+++ b/hotspot/src/share/vm/prims/jvmtiImpl.cpp	Thu Dec 09 15:04:26 2010 -0500
@@ -586,7 +586,6 @@
 {
 }
 
-
 vframe *VM_GetOrSetLocal::get_vframe() {
   if (!_thread->has_last_Java_frame()) {
     return NULL;
@@ -609,7 +608,7 @@
   }
   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 @@
   _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 @@
     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 (_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;
-    }
+      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 @@
 }
 
 
+VM_GetReceiver::VM_GetReceiver(
+    JavaThread* thread, JavaThread* caller_thread, jint depth)
+    : VM_GetOrSetLocal(thread, caller_thread, depth, 0) {}
+
 /////////////////////////////////////////////////////////////////////////////////////////
 
 //
--- a/hotspot/src/share/vm/prims/jvmtiImpl.hpp	Thu Dec 09 17:53:22 2010 +0300
+++ b/hotspot/src/share/vm/prims/jvmtiImpl.hpp	Thu Dec 09 15:04:26 2010 -0500
@@ -355,7 +355,7 @@
 // to the thread simultaneously.
 //
 class VM_GetOrSetLocal : public VM_Operation {
-private:
+ protected:
   JavaThread* _thread;
   JavaThread* _calling_thread;
   jint        _depth;
@@ -365,6 +365,10 @@
   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 @@
   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"; }
+};
+
 
 ///////////////////////////////////////////////////////////////
 //
--- a/hotspot/src/share/vm/runtime/frame.cpp	Thu Dec 09 17:53:22 2010 +0300
+++ b/hotspot/src/share/vm/runtime/frame.cpp	Thu Dec 09 15:04:26 2010 -0500
@@ -1071,28 +1071,20 @@
   }
 }
 
-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" );
--- a/hotspot/src/share/vm/runtime/frame.hpp	Thu Dec 09 17:53:22 2010 +0300
+++ b/hotspot/src/share/vm/runtime/frame.hpp	Thu Dec 09 15:04:26 2010 -0500
@@ -254,10 +254,10 @@
 
   // 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)
--- a/hotspot/src/share/vm/runtime/vframe_hp.cpp	Thu Dec 09 17:53:22 2010 +0300
+++ b/hotspot/src/share/vm/runtime/vframe_hp.cpp	Thu Dec 09 15:04:26 2010 -0500
@@ -207,8 +207,8 @@
     GrowableArray<MonitorInfo*> *monitors = new GrowableArray<MonitorInfo*>(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;
   }