< prev index next >

src/hotspot/share/prims/jvmtiImpl.cpp

Print this page
*** 39,10 ***
--- 39,11 ---
  #include "oops/oopHandle.inline.hpp"
  #include "prims/jvmtiAgentThread.hpp"
  #include "prims/jvmtiEventController.inline.hpp"
  #include "prims/jvmtiImpl.hpp"
  #include "prims/jvmtiRedefineClasses.hpp"
+ #include "runtime/continuation.hpp"
  #include "runtime/deoptimization.hpp"
  #include "runtime/frame.inline.hpp"
  #include "runtime/handles.inline.hpp"
  #include "runtime/interfaceSupport.inline.hpp"
  #include "runtime/javaCalls.hpp"

*** 422,91 ***
    set_breakpoint_list(cache);
  }
  
  ///////////////////////////////////////////////////////////////
  //
! // class VM_GetOrSetLocal
  //
  
  // Constructor for non-object getter
- VM_GetOrSetLocal::VM_GetOrSetLocal(JavaThread* thread, jint depth, jint index, BasicType type)
-   : _thread(thread)
-   , _calling_thread(NULL)
-   , _depth(depth)
-   , _index(index)
-   , _type(type)
-   , _jvf(NULL)
-   , _set(false)
-   , _eb(false, NULL, NULL)
-   , _result(JVMTI_ERROR_NONE)
- {
- }
  
! // Constructor for object or non-object setter
! VM_GetOrSetLocal::VM_GetOrSetLocal(JavaThread* thread, jint depth, jint index, BasicType type, jvalue value)
!   : _thread(thread)
-   , _calling_thread(NULL)
    , _depth(depth)
    , _index(index)
    , _type(type)
    , _value(value)
    , _jvf(NULL)
!   , _set(true)
-   , _eb(type == T_OBJECT, JavaThread::current(), thread)
    , _result(JVMTI_ERROR_NONE)
  {
  }
  
- // Constructor for object getter
- VM_GetOrSetLocal::VM_GetOrSetLocal(JavaThread* thread, JavaThread* calling_thread, jint depth, int index)
-   : _thread(thread)
-   , _calling_thread(calling_thread)
-   , _depth(depth)
-   , _index(index)
-   , _type(T_OBJECT)
-   , _jvf(NULL)
-   , _set(false)
-   , _eb(true, calling_thread, thread)
-   , _result(JVMTI_ERROR_NONE)
- {
- }
- 
- vframe *VM_GetOrSetLocal::get_vframe() {
-   if (!_thread->has_last_Java_frame()) {
-     return NULL;
-   }
-   RegisterMap reg_map(_thread);
-   vframe *vf = _thread->last_java_vframe(&reg_map);
-   int d = 0;
-   while ((vf != NULL) && (d < _depth)) {
-     vf = vf->java_sender();
-     d++;
-   }
-   return vf;
- }
- 
- javaVFrame *VM_GetOrSetLocal::get_java_vframe() {
-   vframe* vf = get_vframe();
-   if (vf == NULL) {
-     _result = JVMTI_ERROR_NO_MORE_FRAMES;
-     return NULL;
-   }
-   javaVFrame *jvf = (javaVFrame*)vf;
- 
-   if (!vf->is_java_frame()) {
-     _result = JVMTI_ERROR_OPAQUE_FRAME;
-     return NULL;
-   }
-   return jvf;
- }
- 
  // Check that the klass is assignable to a type with the given signature.
  // Another solution could be to use the function Klass::is_subtype_of(type).
  // But the type class can be forced to load/initialize eagerly in such a case.
  // This may cause unexpected consequences like CFLH or class-init JVMTI events.
  // It is better to avoid such a behavior.
! bool VM_GetOrSetLocal::is_assignable(const char* ty_sign, Klass* klass, Thread* thread) {
    assert(ty_sign != NULL, "type signature must not be NULL");
    assert(thread != NULL, "thread must not be NULL");
    assert(klass != NULL, "klass must not be NULL");
  
    int len = (int) strlen(ty_sign);
--- 423,35 ---
    set_breakpoint_list(cache);
  }
  
  ///////////////////////////////////////////////////////////////
  //
! // class VM_BaseGetOrSetLocal
  //
  
+ const jvalue VM_BaseGetOrSetLocal::_DEFAULT_VALUE = {0L};
  // Constructor for non-object getter
  
! VM_BaseGetOrSetLocal::VM_BaseGetOrSetLocal(JavaThread* calling_thread, jint depth,
!                                            jint index, BasicType type, jvalue value, bool set)
!   : _calling_thread(calling_thread)
    , _depth(depth)
    , _index(index)
    , _type(type)
    , _value(value)
    , _jvf(NULL)
!   , _set(set)
    , _result(JVMTI_ERROR_NONE)
  {
  }
  
  // Check that the klass is assignable to a type with the given signature.
  // Another solution could be to use the function Klass::is_subtype_of(type).
  // But the type class can be forced to load/initialize eagerly in such a case.
  // This may cause unexpected consequences like CFLH or class-init JVMTI events.
  // It is better to avoid such a behavior.
! bool VM_BaseGetOrSetLocal::is_assignable(const char* ty_sign, Klass* klass, Thread* thread) {
    assert(ty_sign != NULL, "type signature must not be NULL");
    assert(thread != NULL, "thread must not be NULL");
    assert(klass != NULL, "klass must not be NULL");
  
    int len = (int) strlen(ty_sign);

*** 540,12 ***
  // Checks error conditions:
  //   JVMTI_ERROR_INVALID_SLOT
  //   JVMTI_ERROR_TYPE_MISMATCH
  // Returns: 'true' - everything is Ok, 'false' - error code
  
! bool VM_GetOrSetLocal::check_slot_type_lvt(javaVFrame* jvf) {
    Method* method = jvf->method();
    jint num_entries = method->localvariable_table_length();
    if (num_entries == 0) {
      _result = JVMTI_ERROR_INVALID_SLOT;
      return false;       // There are no slots
    }
--- 485,22 ---
  // Checks error conditions:
  //   JVMTI_ERROR_INVALID_SLOT
  //   JVMTI_ERROR_TYPE_MISMATCH
  // Returns: 'true' - everything is Ok, 'false' - error code
  
! bool VM_BaseGetOrSetLocal::check_slot_type_lvt(javaVFrame* jvf) {
    Method* method = jvf->method();
+   if (!method->has_localvariable_table()) {
+     // Just to check index boundaries
+     jint extra_slot = (_type == T_LONG || _type == T_DOUBLE) ? 1 : 0;
+     if (_index < 0 || _index + extra_slot >= method->max_locals()) {
+       _result = JVMTI_ERROR_INVALID_SLOT;
+       return false;
+     }
+     return true;
+   }
+ 
    jint num_entries = method->localvariable_table_length();
    if (num_entries == 0) {
      _result = JVMTI_ERROR_INVALID_SLOT;
      return false;       // There are no slots
    }

*** 603,11 ***
      }
    }
    return true;
  }
  
! bool VM_GetOrSetLocal::check_slot_type_no_lvt(javaVFrame* jvf) {
    Method* method = jvf->method();
    jint extra_slot = (_type == T_LONG || _type == T_DOUBLE) ? 1 : 0;
  
    if (_index < 0 || _index + extra_slot >= method->max_locals()) {
      _result = JVMTI_ERROR_INVALID_SLOT;
--- 558,11 ---
      }
    }
    return true;
  }
  
! bool VM_BaseGetOrSetLocal::check_slot_type_no_lvt(javaVFrame* jvf) {
    Method* method = jvf->method();
    jint extra_slot = (_type == T_LONG || _type == T_DOUBLE) ? 1 : 0;
  
    if (_index < 0 || _index + extra_slot >= method->max_locals()) {
      _result = JVMTI_ERROR_INVALID_SLOT;

*** 646,16 ***
    }
  
    return true;
  }
  
! void VM_GetOrSetLocal::doit() {
!   _jvf = _jvf == NULL ? get_java_vframe() : _jvf;
    if (_jvf == NULL) {
      return;
    };
  
    Method* method = _jvf->method();
    if (getting_receiver()) {
      if (method->is_static()) {
        _result = JVMTI_ERROR_INVALID_SLOT;
        return;
--- 601,21 ---
    }
  
    return true;
  }
  
! void VM_BaseGetOrSetLocal::doit() {
!   _jvf = get_java_vframe();
    if (_jvf == NULL) {
      return;
    };
  
+   if (_set && Continuation::is_frame_in_continuation(_jvf->thread(), _jvf->fr())) {
+     _result = JVMTI_ERROR_OPAQUE_FRAME; // deferred locals currently unsupported in continuations
+     return;
+   }
+ 
    Method* method = _jvf->method();
    if (getting_receiver()) {
      if (method->is_static()) {
        _result = JVMTI_ERROR_INVALID_SLOT;
        return;

*** 753,22 ***
        }
      }
    }
  }
  
! 
- bool VM_GetOrSetLocal::allow_nested_vm_operations() const {
    return true; // May need to deoptimize
  }
  
  
  VM_GetReceiver::VM_GetReceiver(
      JavaThread* thread, JavaThread* caller_thread, jint depth)
      : VM_GetOrSetLocal(thread, caller_thread, depth, 0) {}
  
- /////////////////////////////////////////////////////////////////////////////////////////
  
  //
  // class JvmtiSuspendControl - see comments in jvmtiImpl.hpp
  //
  
  bool JvmtiSuspendControl::suspend(JavaThread *java_thread) {
--- 713,157 ---
        }
      }
    }
  }
  
! bool VM_BaseGetOrSetLocal::allow_nested_vm_operations() const {
    return true; // May need to deoptimize
  }
  
  
+ ///////////////////////////////////////////////////////////////
+ //
+ // class VM_GetOrSetLocal
+ //
+ 
+ // Constructor for non-object getter
+ VM_GetOrSetLocal::VM_GetOrSetLocal(JavaThread* thread, jint depth, jint index, BasicType type)
+   : VM_BaseGetOrSetLocal((JavaThread*)NULL, depth, index, type, _DEFAULT_VALUE, false),
+     _thread(thread),
+     _eb(false, NULL, NULL)
+ {
+ }
+ 
+ // Constructor for object or non-object setter
+ VM_GetOrSetLocal::VM_GetOrSetLocal(JavaThread* thread, jint depth, jint index, BasicType type, jvalue value)
+   : VM_BaseGetOrSetLocal((JavaThread*)NULL, depth, index, type, value, true),
+     _thread(thread),
+     _eb(type == T_OBJECT, JavaThread::current(), thread)
+ {
+ }
+ 
+ // Constructor for object getter
+ VM_GetOrSetLocal::VM_GetOrSetLocal(JavaThread* thread, JavaThread* calling_thread, jint depth, int index)
+   : VM_BaseGetOrSetLocal(calling_thread, depth, index, T_OBJECT, _DEFAULT_VALUE, false),
+     _thread(thread),
+     _eb(true, calling_thread, thread)
+ {
+ }
+ 
+ vframe *VM_GetOrSetLocal::get_vframe() {
+   if (!_thread->has_last_Java_frame()) {
+     return NULL;
+   }
+   RegisterMap reg_map(_thread, true, true, true);
+   vframe *vf = JvmtiEnvBase::get_last_java_vframe(_thread, &reg_map);
+   int d = 0;
+   while ((vf != NULL) && (d < _depth)) {
+     vf = vf->java_sender();
+     d++;
+   }
+   return vf;
+ }
+ 
+ javaVFrame *VM_GetOrSetLocal::get_java_vframe() {
+   vframe* vf = get_vframe();
+   if (vf == NULL) {
+     _result = JVMTI_ERROR_NO_MORE_FRAMES;
+     return NULL;
+   }
+   javaVFrame *jvf = (javaVFrame*)vf;
+ 
+   if (!vf->is_java_frame()) {
+     _result = JVMTI_ERROR_OPAQUE_FRAME;
+     return NULL;
+   }
+   return jvf;
+ }
+ 
  VM_GetReceiver::VM_GetReceiver(
      JavaThread* thread, JavaThread* caller_thread, jint depth)
      : VM_GetOrSetLocal(thread, caller_thread, depth, 0) {}
  
  
+ ///////////////////////////////////////////////////////////////
+ //
+ // class VM_VirtualThreadGetOrSetLocal
+ //
+ 
+ // Constructor for non-object getter
+ VM_VirtualThreadGetOrSetLocal::VM_VirtualThreadGetOrSetLocal(JvmtiEnv* env, Handle vthread_h, jint depth,
+                                                              jint index, BasicType type)
+   : VM_BaseGetOrSetLocal((JavaThread*)NULL, depth, index, type, _DEFAULT_VALUE, false)
+ {
+   _env = env;
+   _vthread_h = vthread_h;
+ }
+ 
+ // Constructor for object or non-object setter
+ VM_VirtualThreadGetOrSetLocal::VM_VirtualThreadGetOrSetLocal(JvmtiEnv* env, Handle vthread_h, jint depth,
+                                                              jint index, BasicType type, jvalue value)
+   : VM_BaseGetOrSetLocal((JavaThread*)NULL, depth, index, type, value, true)
+ {
+   _env = env;
+   _vthread_h = vthread_h;
+ }
+ 
+ // Constructor for object getter
+ VM_VirtualThreadGetOrSetLocal::VM_VirtualThreadGetOrSetLocal(JvmtiEnv* env, Handle vthread_h, JavaThread* calling_thread,
+                                                              jint depth, int index)
+   : VM_BaseGetOrSetLocal(calling_thread, depth, index, T_OBJECT, _DEFAULT_VALUE, false)
+ {
+   _env = env;
+   _vthread_h = vthread_h;
+ }
+ 
+ javaVFrame *VM_VirtualThreadGetOrSetLocal::get_java_vframe() {
+   Thread* cur_thread = Thread::current();
+   oop cont = java_lang_VirtualThread::continuation(_vthread_h());
+   javaVFrame* jvf = NULL;
+ 
+   assert(cont != NULL, "vthread contintuation must not be NULL");
+   if (jdk_internal_vm_Continuation::is_mounted(cont)) {
+     oop carrier_thread = java_lang_VirtualThread::carrier_thread(_vthread_h());
+     JavaThread* java_thread = java_lang_Thread::thread(carrier_thread);
+     vframeStream vfs(java_thread, Handle(cur_thread, Continuation::continuation_scope(cont)));
+ 
+     if (!vfs.at_end()) {
+       jvf = vfs.asJavaVFrame();
+       jvf = JvmtiEnvBase::check_and_skip_hidden_frames(java_thread, jvf);
+     }
+   } else {
+     vframeStream vfs(cont);
+ 
+     if (!vfs.at_end()) {
+       jvf = vfs.asJavaVFrame();
+       jvf = JvmtiEnvBase::check_and_skip_hidden_frames(_vthread_h(), jvf);
+     }
+   }
+   int d = 0;
+   while ((jvf != NULL) && (d < _depth)) {
+     jvf = jvf->java_sender();
+     d++;
+   }
+ 
+   if (d < _depth || jvf == NULL) {
+     _result = JVMTI_ERROR_NO_MORE_FRAMES;
+     return NULL;
+   }
+ 
+   if (!jvf->is_java_frame()) {
+     _result = JVMTI_ERROR_OPAQUE_FRAME;
+     return NULL;
+   }
+   return jvf;
+ }
+ 
+ VM_VirtualThreadGetReceiver::VM_VirtualThreadGetReceiver(
+     JvmtiEnv* env, Handle vthread_h, JavaThread* caller_thread, jint depth)
+     : VM_VirtualThreadGetOrSetLocal(env, vthread_h, caller_thread, depth, 0) {}
+ 
+ 
+ /////////////////////////////////////////////////////////////////////////////////////////
  //
  // class JvmtiSuspendControl - see comments in jvmtiImpl.hpp
  //
  
  bool JvmtiSuspendControl::suspend(JavaThread *java_thread) {
< prev index next >