< prev index next >

src/hotspot/share/classfile/javaClasses.cpp

Print this page
*** 193,10 ***
--- 193,252 ---
  #endif
  
  #define FIELD_COMPUTE_OFFSET(offset, klass, name, signature, is_static) \
    compute_offset(offset, klass, name, vmSymbols::signature(), is_static)
  
+ // This class provides a simple wrapper over the internal structure of
+ // exception backtrace to insulate users of the backtrace from needing
+ // to know what it looks like.
+ // The code of this class is not GC safe. Allocations can only happen
+ // in expand().
+ class BacktraceBuilder: public StackObj {
+  friend class BacktraceIterator;
+  private:
+   Handle          _backtrace;
+   objArrayOop     _head;
+   typeArrayOop    _methods;
+   typeArrayOop    _bcis;
+   objArrayOop     _mirrors;
+   typeArrayOop    _names; // Needed to insulate method name against redefinition.
+   objArrayOop     _conts;
+   // True if the top frame of the backtrace is omitted because it shall be hidden.
+   bool            _has_hidden_top_frame;
+   int             _index;
+   NoSafepointVerifier _nsv;
+ 
+   enum {
+     trace_methods_offset = java_lang_Throwable::trace_methods_offset,
+     trace_bcis_offset    = java_lang_Throwable::trace_bcis_offset,
+     trace_mirrors_offset = java_lang_Throwable::trace_mirrors_offset,
+     trace_names_offset   = java_lang_Throwable::trace_names_offset,
+     trace_conts_offset   = java_lang_Throwable::trace_conts_offset,
+     trace_next_offset    = java_lang_Throwable::trace_next_offset,
+     trace_hidden_offset  = java_lang_Throwable::trace_hidden_offset,
+     trace_size           = java_lang_Throwable::trace_size,
+     trace_chunk_size     = java_lang_Throwable::trace_chunk_size
+   };
+ 
+   // get info out of chunks
+   static typeArrayOop get_methods(objArrayHandle chunk) {
+     typeArrayOop methods = typeArrayOop(chunk->obj_at(trace_methods_offset));
+     assert(methods != NULL, "method array should be initialized in backtrace");
+     return methods;
+   }
+   static typeArrayOop get_bcis(objArrayHandle chunk) {
+     typeArrayOop bcis = typeArrayOop(chunk->obj_at(trace_bcis_offset));
+     assert(bcis != NULL, "bci array should be initialized in backtrace");
+     return bcis;
+   }
+   static objArrayOop get_mirrors(objArrayHandle chunk) {
+     objArrayOop mirrors = objArrayOop(chunk->obj_at(trace_mirrors_offset));
+     assert(mirrors != NULL, "mirror array should be initialized in backtrace");
+     return mirrors;
+   }
+   static typeArrayOop get_names(objArrayHandle chunk) {
+     typeArrayOop names = typeArrayOop(chunk->obj_at(trace_names_offset));
+     assert(names != NULL, "names array should be initialized in backtrace");
+     return names;
+   }
+   static objArrayOop get_conts(objArrayHandle chunk) {
+     objArrayOop conts = objArrayOop(chunk->obj_at(trace_conts_offset));
+     assert(conts != NULL, "conts array should be initialized in backtrace");
+     return conts;
+   }
+   static bool has_hidden_top_frame(objArrayHandle chunk) {
+     oop hidden = chunk->obj_at(trace_hidden_offset);
+     return hidden != NULL;
+   }
+ 
+  public:
+ 
+   // constructor for new backtrace
+   BacktraceBuilder(TRAPS): _head(NULL), _methods(NULL), _bcis(NULL), _mirrors(NULL), _names(NULL), _conts(NULL), _has_hidden_top_frame(false) {
+     expand(CHECK);
+     _backtrace = Handle(THREAD, _head);
+     _index = 0;
+   }
+ 
+   BacktraceBuilder(Thread* thread, objArrayHandle backtrace) {
+     _methods = get_methods(backtrace);
+     _bcis = get_bcis(backtrace);
+     _mirrors = get_mirrors(backtrace);
+     _names = get_names(backtrace);
+     _conts = get_conts(backtrace);
+     _has_hidden_top_frame = has_hidden_top_frame(backtrace);
+     assert(_methods->length() == _bcis->length() &&
+            _methods->length() == _mirrors->length() &&
+            _mirrors->length() == _names->length() &&
+            _names->length() == _conts->length(),
+            "method and source information arrays should match");
+ 
+     // head is the preallocated backtrace
+     _head = backtrace();
+     _backtrace = Handle(thread, _head);
+     _index = 0;
+   }
+ 
+   void expand(TRAPS) {
+     objArrayHandle old_head(THREAD, _head);
+     PauseNoSafepointVerifier pnsv(&_nsv);
+ 
+     objArrayOop head = oopFactory::new_objectArray(trace_size, CHECK);
+     objArrayHandle new_head(THREAD, head);
+ 
+     typeArrayOop methods = oopFactory::new_shortArray(trace_chunk_size, CHECK);
+     typeArrayHandle new_methods(THREAD, methods);
+ 
+     typeArrayOop bcis = oopFactory::new_intArray(trace_chunk_size, CHECK);
+     typeArrayHandle new_bcis(THREAD, bcis);
+ 
+     objArrayOop mirrors = oopFactory::new_objectArray(trace_chunk_size, CHECK);
+     objArrayHandle new_mirrors(THREAD, mirrors);
+ 
+     typeArrayOop names = oopFactory::new_symbolArray(trace_chunk_size, CHECK);
+     typeArrayHandle new_names(THREAD, names);
+ 
+     objArrayOop conts = oopFactory::new_objectArray(trace_chunk_size, CHECK);
+     objArrayHandle new_conts(THREAD, conts);
+ 
+     if (!old_head.is_null()) {
+       old_head->obj_at_put(trace_next_offset, new_head());
+     }
+     new_head->obj_at_put(trace_methods_offset, new_methods());
+     new_head->obj_at_put(trace_bcis_offset, new_bcis());
+     new_head->obj_at_put(trace_mirrors_offset, new_mirrors());
+     new_head->obj_at_put(trace_names_offset, new_names());
+     new_head->obj_at_put(trace_conts_offset, new_conts());
+     new_head->obj_at_put(trace_hidden_offset, NULL);
+ 
+     _head    = new_head();
+     _methods = new_methods();
+     _bcis = new_bcis();
+     _mirrors = new_mirrors();
+     _names  = new_names();
+     _conts  = new_conts();
+     _index = 0;
+   }
+ 
+   oop backtrace() {
+     return _backtrace();
+   }
+ 
+   inline void push(Method* method, int bci, oop contScopeName, TRAPS) {
+     // Smear the -1 bci to 0 since the array only holds unsigned
+     // shorts.  The later line number lookup would just smear the -1
+     // to a 0 even if it could be recorded.
+     if (bci == SynchronizationEntryBCI) bci = 0;
+ 
+     if (_index >= trace_chunk_size) {
+       methodHandle mhandle(THREAD, method);
+       Handle chandle(THREAD, contScopeName);
+       expand(CHECK);
+       method = mhandle();
+       contScopeName = chandle();
+     }
+ 
+     _methods->ushort_at_put(_index, method->orig_method_idnum());
+     _bcis->int_at_put(_index, Backtrace::merge_bci_and_version(bci, method->constants()->version()));
+ 
+     // Note:this doesn't leak symbols because the mirror in the backtrace keeps the
+     // klass owning the symbols alive so their refcounts aren't decremented.
+     Symbol* name = method->name();
+     _names->symbol_at_put(_index, name);
+ 
+     // We need to save the mirrors in the backtrace to keep the class
+     // from being unloaded while we still have this stack trace.
+     assert(method->method_holder()->java_mirror() != NULL, "never push null for mirror");
+     _mirrors->obj_at_put(_index, method->method_holder()->java_mirror());
+ 
+     _conts->obj_at_put(_index, contScopeName);
+ 
+     _index++;
+   }
+ 
+   void set_has_hidden_top_frame(TRAPS) {
+     if (!_has_hidden_top_frame) {
+       // It would be nice to add java/lang/Boolean::TRUE here
+       // to indicate that this backtrace has a hidden top frame.
+       // But this code is used before TRUE is allocated.
+       // Therefore let's just use an arbitrary legal oop
+       // available right here. _methods is a short[].
+       assert(_methods != NULL, "we need a legal oop");
+       _has_hidden_top_frame = true;
+       _head->obj_at_put(trace_hidden_offset, _methods);
+     }
+   }
+ };
+ 
+ struct BacktraceElement : public StackObj {
+   int _method_id;
+   int _bci;
+   int _version;
+   Symbol* _name;
+   Handle _mirror;
+   Handle _cont; // the continuation scope name (String)
+   BacktraceElement(Handle mirror, int mid, int version, int bci, Symbol* name, Handle cont) :
+                    _method_id(mid), _bci(bci), _version(version), _name(name), _mirror(mirror), _cont(cont) {}
+ };
+ 
+ class BacktraceIterator : public StackObj {
+   int _index;
+   objArrayHandle  _result;
+   objArrayHandle  _mirrors;
+   typeArrayHandle _methods;
+   typeArrayHandle _bcis;
+   typeArrayHandle _names;
+   objArrayHandle  _conts;
+ 
+   void init(objArrayHandle result, Thread* thread) {
+     // Get method id, bci, version and mirror from chunk
+     _result = result;
+     if (_result.not_null()) {
+       _methods = typeArrayHandle(thread, BacktraceBuilder::get_methods(_result));
+       _bcis = typeArrayHandle(thread, BacktraceBuilder::get_bcis(_result));
+       _mirrors = objArrayHandle(thread, BacktraceBuilder::get_mirrors(_result));
+       _names = typeArrayHandle(thread, BacktraceBuilder::get_names(_result));
+       _conts = objArrayHandle(thread, BacktraceBuilder::get_conts(_result));
+       _index = 0;
+     }
+   }
+  public:
+   BacktraceIterator(objArrayHandle result, Thread* thread) {
+     init(result, thread);
+     assert(_methods.is_null() || _methods->length() == java_lang_Throwable::trace_chunk_size, "lengths don't match");
+   }
+ 
+   BacktraceElement next(Thread* thread) {
+     BacktraceElement e (Handle(thread, _mirrors->obj_at(_index)),
+                         _methods->ushort_at(_index),
+                         Backtrace::version_at(_bcis->int_at(_index)),
+                         Backtrace::bci_at(_bcis->int_at(_index)),
+                         _names->symbol_at(_index),
+                         Handle(thread, _conts->obj_at(_index)));
+     _index++;
+ 
+     if (_index >= java_lang_Throwable::trace_chunk_size) {
+       int next_offset = java_lang_Throwable::trace_next_offset;
+       // Get next chunk
+       objArrayHandle result (thread, objArrayOop(_result->obj_at(next_offset)));
+       init(result, thread);
+     }
+     return e;
+   }
+ 
+   bool repeat() {
+     return _result.not_null() && _mirrors->obj_at(_index) != NULL;
+   }
+ };
  
  // java_lang_String
  
  int java_lang_String::_value_offset;
  int java_lang_String::_hash_offset;

*** 1667,61 ***
  //       merged, so in the HotSpot VM we just use the eetop field for the thread
  //       instead of the privateInfo_offset.
  //
  // Note: The stackSize field is only present starting in 1.4.
  
  int java_lang_Thread::_name_offset;
- int java_lang_Thread::_group_offset;
  int java_lang_Thread::_contextClassLoader_offset;
  int java_lang_Thread::_inheritedAccessControlContext_offset;
- int java_lang_Thread::_priority_offset;
  int java_lang_Thread::_eetop_offset;
  int java_lang_Thread::_interrupted_offset;
- int java_lang_Thread::_daemon_offset;
- int java_lang_Thread::_stillborn_offset;
- int java_lang_Thread::_stackSize_offset;
  int java_lang_Thread::_tid_offset;
! int java_lang_Thread::_thread_status_offset;
  int java_lang_Thread::_park_blocker_offset;
  
  #define THREAD_FIELDS_DO(macro) \
    macro(_name_offset,          k, vmSymbols::name_name(), string_signature, false); \
-   macro(_group_offset,         k, vmSymbols::group_name(), threadgroup_signature, false); \
    macro(_contextClassLoader_offset, k, vmSymbols::contextClassLoader_name(), classloader_signature, false); \
    macro(_inheritedAccessControlContext_offset, k, vmSymbols::inheritedAccessControlContext_name(), accesscontrolcontext_signature, false); \
-   macro(_priority_offset,      k, vmSymbols::priority_name(), int_signature, false); \
-   macro(_daemon_offset,        k, vmSymbols::daemon_name(), bool_signature, false); \
    macro(_eetop_offset,         k, "eetop", long_signature, false); \
    macro(_interrupted_offset,   k, "interrupted", bool_signature, false); \
-   macro(_stillborn_offset,     k, "stillborn", bool_signature, false); \
-   macro(_stackSize_offset,     k, "stackSize", long_signature, false); \
    macro(_tid_offset,           k, "tid", long_signature, false); \
!   macro(_thread_status_offset, k, "threadStatus", int_signature, false); \
!   macro(_park_blocker_offset,  k, "parkBlocker", object_signature, false)
  
  void java_lang_Thread::compute_offsets() {
!   assert(_group_offset == 0, "offsets should be initialized only once");
  
    InstanceKlass* k = vmClasses::Thread_klass();
    THREAD_FIELDS_DO(FIELD_COMPUTE_OFFSET);
  }
  
  #if INCLUDE_CDS
  void java_lang_Thread::serialize_offsets(SerializeClosure* f) {
    THREAD_FIELDS_DO(FIELD_SERIALIZE_OFFSET);
  }
  #endif
  
  JavaThread* java_lang_Thread::thread(oop java_thread) {
    return (JavaThread*)java_thread->address_field(_eetop_offset);
  }
  
- 
  void java_lang_Thread::set_thread(oop java_thread, JavaThread* thread) {
    java_thread->address_field_put(_eetop_offset, (address)thread);
  }
  
  bool java_lang_Thread::interrupted(oop java_thread) {
    // Make sure the caller can safely access oops.
    assert(Thread::current()->is_VM_thread() ||
           (JavaThread::current()->thread_state() != _thread_blocked &&
            JavaThread::current()->thread_state() != _thread_in_native),
--- 1909,191 ---
  //       merged, so in the HotSpot VM we just use the eetop field for the thread
  //       instead of the privateInfo_offset.
  //
  // Note: The stackSize field is only present starting in 1.4.
  
+ int java_lang_Thread_FieldHolder::_group_offset;
+ int java_lang_Thread_FieldHolder::_priority_offset;
+ int java_lang_Thread_FieldHolder::_stackSize_offset;
+ int java_lang_Thread_FieldHolder::_stillborn_offset;
+ int java_lang_Thread_FieldHolder::_daemon_offset;
+ int java_lang_Thread_FieldHolder::_thread_status_offset;
+ 
+ #define THREAD_FIELD_HOLDER_FIELDS_DO(macro) \
+   macro(_group_offset,         k, vmSymbols::group_name(), threadgroup_signature, false); \
+   macro(_priority_offset,      k, vmSymbols::priority_name(), int_signature, false); \
+   macro(_stackSize_offset,     k, "stackSize", long_signature, false); \
+   macro(_stillborn_offset,     k, "stillborn", bool_signature, false); \
+   macro(_daemon_offset,        k, vmSymbols::daemon_name(), bool_signature, false); \
+   macro(_thread_status_offset, k, "threadStatus", int_signature, false)
+ 
+ void java_lang_Thread_FieldHolder::compute_offsets() {
+   assert(_group_offset == 0, "offsets should be initialized only once");
+ 
+   InstanceKlass* k = vmClasses::Thread_FieldHolder_klass();
+   THREAD_FIELD_HOLDER_FIELDS_DO(FIELD_COMPUTE_OFFSET);
+ }
+ 
+ #if INCLUDE_CDS
+ void java_lang_Thread_FieldHolder::serialize_offsets(SerializeClosure* f) {
+   THREAD_FIELD_HOLDER_FIELDS_DO(FIELD_SERIALIZE_OFFSET);
+ }
+ #endif
+ 
+ oop java_lang_Thread_FieldHolder::threadGroup(oop holder) {
+   return holder->obj_field(_group_offset);
+ }
+ 
+ ThreadPriority java_lang_Thread_FieldHolder::priority(oop holder) {
+   return (ThreadPriority)holder->int_field(_priority_offset);
+ }
+ 
+ void java_lang_Thread_FieldHolder::set_priority(oop holder, ThreadPriority priority) {
+   holder->int_field_put(_priority_offset, priority);
+ }
+ 
+ jlong java_lang_Thread_FieldHolder::stackSize(oop holder) {
+   return holder->long_field(_stackSize_offset);
+ }
+ 
+ bool java_lang_Thread_FieldHolder::is_stillborn(oop holder) {
+   return holder->bool_field(_stillborn_offset) != 0;
+ }
+ 
+ void java_lang_Thread_FieldHolder::set_stillborn(oop holder) {
+   holder->bool_field_put(_stillborn_offset, true);
+ }
+ 
+ bool java_lang_Thread_FieldHolder::is_daemon(oop holder) {
+   return holder->bool_field(_daemon_offset) != 0;
+ }
+ 
+ void java_lang_Thread_FieldHolder::set_daemon(oop holder) {
+   holder->bool_field_put(_daemon_offset, true);
+ }
+ 
+ void java_lang_Thread_FieldHolder::set_thread_status(oop holder, JavaThreadStatus status) {
+   holder->int_field_put(_thread_status_offset, static_cast<int>(status));
+ }
+ 
+ JavaThreadStatus java_lang_Thread_FieldHolder::get_thread_status(oop holder) {
+   return static_cast<JavaThreadStatus>(holder->int_field(_thread_status_offset));
+ }
+ 
+ 
+ int java_lang_Thread_VirtualThreads::_static_THREAD_GROUP_offset = 0;
+ 
+ #define THREAD_VIRTUAL_THREADS_STATIC_FIELDS_DO(macro) \
+   macro(_static_THREAD_GROUP_offset, k, "THREAD_GROUP", threadgroup_signature, true);
+ 
+ void java_lang_Thread_VirtualThreads::compute_offsets() {
+   assert(_static_THREAD_GROUP_offset == 0, "offsets should be initialized only once");
+ 
+   InstanceKlass* k = vmClasses::Thread_VirtualThreads_klass();
+   THREAD_VIRTUAL_THREADS_STATIC_FIELDS_DO(FIELD_COMPUTE_OFFSET);
+ }
+ 
+ #if INCLUDE_CDS
+ void java_lang_Thread_VirtualThreads::serialize_offsets(SerializeClosure* f) {
+   THREAD_VIRTUAL_THREADS_STATIC_FIELDS_DO(FIELD_SERIALIZE_OFFSET);
+ }
+ #endif
+ 
+ oop java_lang_Thread_VirtualThreads::get_THREAD_GROUP() {
+   InstanceKlass* k = vmClasses::Thread_VirtualThreads_klass();
+   oop base = k->static_field_base_raw();
+   return base->obj_field(_static_THREAD_GROUP_offset);
+ }
+ 
+ 
+ int java_lang_Thread_ClassLoaders::_static_NOT_SUPPORTED_offset = 0;
+ 
+ #define THREAD_CLASS_LOADERS_STATIC_FIELDS_DO(macro) \
+   macro(_static_NOT_SUPPORTED_offset, k, "NOT_SUPPORTED", classloader_signature, true);
+ 
+ void java_lang_Thread_ClassLoaders::compute_offsets() {
+   assert(_static_NOT_SUPPORTED_offset == 0, "offsets should be initialized only once");
+ 
+   InstanceKlass* k = vmClasses::Thread_ClassLoaders_klass();
+   THREAD_CLASS_LOADERS_STATIC_FIELDS_DO(FIELD_COMPUTE_OFFSET);
+ }
+ 
+ #if INCLUDE_CDS
+ void java_lang_Thread_ClassLoaders::serialize_offsets(SerializeClosure* f) {
+   THREAD_CLASS_LOADERS_STATIC_FIELDS_DO(FIELD_SERIALIZE_OFFSET);
+ }
+ #endif
+ 
+ oop java_lang_Thread_ClassLoaders::get_NOT_SUPPORTED() {
+   InstanceKlass* k = vmClasses::Thread_ClassLoaders_klass();
+   oop base = k->static_field_base_raw();
+   return base->obj_field(_static_NOT_SUPPORTED_offset);
+ }
+ 
+ int java_lang_Thread::_holder_offset;
  int java_lang_Thread::_name_offset;
  int java_lang_Thread::_contextClassLoader_offset;
  int java_lang_Thread::_inheritedAccessControlContext_offset;
  int java_lang_Thread::_eetop_offset;
+ int java_lang_Thread::_jvmti_thread_state_offset;
  int java_lang_Thread::_interrupted_offset;
  int java_lang_Thread::_tid_offset;
! int java_lang_Thread::_continuation_offset;
  int java_lang_Thread::_park_blocker_offset;
+ int java_lang_Thread::_scopeLocalBindings_offset;
  
  #define THREAD_FIELDS_DO(macro) \
+   macro(_holder_offset,        k, "holder", thread_fieldholder_signature, false); \
    macro(_name_offset,          k, vmSymbols::name_name(), string_signature, false); \
    macro(_contextClassLoader_offset, k, vmSymbols::contextClassLoader_name(), classloader_signature, false); \
    macro(_inheritedAccessControlContext_offset, k, vmSymbols::inheritedAccessControlContext_name(), accesscontrolcontext_signature, false); \
    macro(_eetop_offset,         k, "eetop", long_signature, false); \
    macro(_interrupted_offset,   k, "interrupted", bool_signature, false); \
    macro(_tid_offset,           k, "tid", long_signature, false); \
!   macro(_park_blocker_offset,  k, "parkBlocker", object_signature, false); \
!   macro(_continuation_offset,  k, "cont", continuation_signature, false); \
+   macro(_scopeLocalBindings_offset, k, "scopeLocalBindings", scopeLocalSnapshot_name, false);
  
  void java_lang_Thread::compute_offsets() {
!   assert(_holder_offset == 0, "offsets should be initialized only once");
  
    InstanceKlass* k = vmClasses::Thread_klass();
    THREAD_FIELDS_DO(FIELD_COMPUTE_OFFSET);
+   THREAD_INJECTED_FIELDS(INJECTED_FIELD_COMPUTE_OFFSET);
  }
  
  #if INCLUDE_CDS
  void java_lang_Thread::serialize_offsets(SerializeClosure* f) {
    THREAD_FIELDS_DO(FIELD_SERIALIZE_OFFSET);
+   THREAD_INJECTED_FIELDS(INJECTED_FIELD_SERIALIZE_OFFSET);
  }
  #endif
  
  JavaThread* java_lang_Thread::thread(oop java_thread) {
    return (JavaThread*)java_thread->address_field(_eetop_offset);
  }
  
  void java_lang_Thread::set_thread(oop java_thread, JavaThread* thread) {
    java_thread->address_field_put(_eetop_offset, (address)thread);
  }
  
+ JvmtiThreadState* java_lang_Thread::jvmti_thread_state(oop java_thread) {
+   return (JvmtiThreadState*)java_thread->address_field(_jvmti_thread_state_offset);
+ }
+ 
+ void java_lang_Thread::set_jvmti_thread_state(oop java_thread, JvmtiThreadState* state) {
+   java_thread->address_field_put(_jvmti_thread_state_offset, (address)state);
+ }
+ 
+ void java_lang_Thread::clear_scopeLocalBindings(oop java_thread) {
+   java_thread->obj_field_put(_scopeLocalBindings_offset, NULL);
+ }
+ 
+ oop java_lang_Thread::holder(oop java_thread) {
+     return java_thread->obj_field(_holder_offset);
+ }
+ 
  bool java_lang_Thread::interrupted(oop java_thread) {
    // Make sure the caller can safely access oops.
    assert(Thread::current()->is_VM_thread() ||
           (JavaThread::current()->thread_state() != _thread_blocked &&
            JavaThread::current()->thread_state() != _thread_in_native),

*** 1748,48 ***
    java_thread->obj_field_put(_name_offset, name);
  }
  
  
  ThreadPriority java_lang_Thread::priority(oop java_thread) {
!   return (ThreadPriority)java_thread->int_field(_priority_offset);
  }
  
  
  void java_lang_Thread::set_priority(oop java_thread, ThreadPriority priority) {
!   java_thread->int_field_put(_priority_offset, priority);
  }
  
  
  oop java_lang_Thread::threadGroup(oop java_thread) {
!   return java_thread->obj_field(_group_offset);
  }
  
  
  bool java_lang_Thread::is_stillborn(oop java_thread) {
!   return java_thread->bool_field(_stillborn_offset) != 0;
  }
  
  
  // We never have reason to turn the stillborn bit off
  void java_lang_Thread::set_stillborn(oop java_thread) {
!   java_thread->bool_field_put(_stillborn_offset, true);
  }
  
  
  bool java_lang_Thread::is_alive(oop java_thread) {
    JavaThread* thr = java_lang_Thread::thread(java_thread);
    return (thr != NULL);
  }
  
  
  bool java_lang_Thread::is_daemon(oop java_thread) {
!   return java_thread->bool_field(_daemon_offset) != 0;
  }
  
- 
  void java_lang_Thread::set_daemon(oop java_thread) {
!   java_thread->bool_field_put(_daemon_offset, true);
  }
  
  oop java_lang_Thread::context_class_loader(oop java_thread) {
    return java_thread->obj_field(_contextClassLoader_offset);
  }
--- 2120,61 ---
    java_thread->obj_field_put(_name_offset, name);
  }
  
  
  ThreadPriority java_lang_Thread::priority(oop java_thread) {
!   oop holder = java_lang_Thread::holder(java_thread);
+   assert(holder != NULL, "Java Thread not initialized");
+   return java_lang_Thread_FieldHolder::priority(holder);
  }
  
  
  void java_lang_Thread::set_priority(oop java_thread, ThreadPriority priority) {
!   oop holder = java_lang_Thread::holder(java_thread);
+   assert(holder != NULL, "Java Thread not initialized");
+   java_lang_Thread_FieldHolder::set_priority(holder, priority);
  }
  
  
  oop java_lang_Thread::threadGroup(oop java_thread) {
!   oop holder = java_lang_Thread::holder(java_thread);
+   assert(holder != NULL, "Java Thread not initialized");
+   return java_lang_Thread_FieldHolder::threadGroup(holder);
  }
  
  
  bool java_lang_Thread::is_stillborn(oop java_thread) {
!   oop holder = java_lang_Thread::holder(java_thread);
+   assert(holder != NULL, "Java Thread not initialized");
+   return java_lang_Thread_FieldHolder::is_stillborn(holder);
  }
  
  
  // We never have reason to turn the stillborn bit off
  void java_lang_Thread::set_stillborn(oop java_thread) {
!   oop holder = java_lang_Thread::holder(java_thread);
+   assert(holder != NULL, "Java Thread not initialized");
+   java_lang_Thread_FieldHolder::set_stillborn(holder);
  }
  
  
  bool java_lang_Thread::is_alive(oop java_thread) {
    JavaThread* thr = java_lang_Thread::thread(java_thread);
    return (thr != NULL);
  }
  
  
  bool java_lang_Thread::is_daemon(oop java_thread) {
!   oop holder = java_lang_Thread::holder(java_thread);
+   assert(holder != NULL, "Java Thread not initialized");
+   return java_lang_Thread_FieldHolder::is_daemon(holder);
  }
  
  void java_lang_Thread::set_daemon(oop java_thread) {
!   oop holder = java_lang_Thread::holder(java_thread);
+   assert(holder != NULL, "Java Thread not initialized");
+   java_lang_Thread_FieldHolder::set_daemon(holder);
  }
  
  oop java_lang_Thread::context_class_loader(oop java_thread) {
    return java_thread->obj_field(_contextClassLoader_offset);
  }

*** 1798,40 ***
    return java_thread->obj_field(_inheritedAccessControlContext_offset);
  }
  
  
  jlong java_lang_Thread::stackSize(oop java_thread) {
!   return java_thread->long_field(_stackSize_offset);
  }
  
  // Write the thread status value to threadStatus field in java.lang.Thread java class.
! void java_lang_Thread::set_thread_status(oop java_thread,
!                                          JavaThreadStatus status) {
!   java_thread->int_field_put(_thread_status_offset, static_cast<int>(status));
  }
  
  // Read thread status value from threadStatus field in java.lang.Thread java class.
  JavaThreadStatus java_lang_Thread::get_thread_status(oop java_thread) {
    // Make sure the caller is operating on behalf of the VM or is
    // running VM code (state == _thread_in_vm).
    assert(Threads_lock->owned_by_self() || Thread::current()->is_VM_thread() ||
           JavaThread::current()->thread_state() == _thread_in_vm,
           "Java Thread is not running in vm");
!   return static_cast<JavaThreadStatus>(java_thread->int_field(_thread_status_offset));
  }
  
- 
  jlong java_lang_Thread::thread_id(oop java_thread) {
!   return java_thread->long_field(_tid_offset);
  }
  
  oop java_lang_Thread::park_blocker(oop java_thread) {
    return java_thread->obj_field(_park_blocker_offset);
  }
  
  const char* java_lang_Thread::thread_status_name(oop java_thread) {
!   JavaThreadStatus status = static_cast<JavaThreadStatus>(java_thread->int_field(_thread_status_offset));
    switch (status) {
      case JavaThreadStatus::NEW                      : return "NEW";
      case JavaThreadStatus::RUNNABLE                 : return "RUNNABLE";
      case JavaThreadStatus::SLEEPING                 : return "TIMED_WAITING (sleeping)";
      case JavaThreadStatus::IN_OBJECT_WAIT           : return "WAITING (on object monitor)";
--- 2183,169 ---
    return java_thread->obj_field(_inheritedAccessControlContext_offset);
  }
  
  
  jlong java_lang_Thread::stackSize(oop java_thread) {
!   oop holder = java_lang_Thread::holder(java_thread);
+   assert(holder != NULL, "Java Thread not initialized");
+   return java_lang_Thread_FieldHolder::stackSize(holder);
  }
  
  // Write the thread status value to threadStatus field in java.lang.Thread java class.
! void java_lang_Thread::set_thread_status(oop java_thread, JavaThreadStatus status) {
!   oop holder = java_lang_Thread::holder(java_thread);
!   assert(holder != NULL, "Java Thread not initialized");
+   java_lang_Thread_FieldHolder::set_thread_status(holder, status);
  }
  
  // Read thread status value from threadStatus field in java.lang.Thread java class.
  JavaThreadStatus java_lang_Thread::get_thread_status(oop java_thread) {
    // Make sure the caller is operating on behalf of the VM or is
    // running VM code (state == _thread_in_vm).
    assert(Threads_lock->owned_by_self() || Thread::current()->is_VM_thread() ||
           JavaThread::current()->thread_state() == _thread_in_vm,
           "Java Thread is not running in vm");
!   oop holder = java_lang_Thread::holder(java_thread);
+   if (holder == NULL) {
+     return JavaThreadStatus::NEW;  // Java Thread not initialized
+   } else {
+     return java_lang_Thread_FieldHolder::get_thread_status(holder);
+   }
  }
  
  jlong java_lang_Thread::thread_id(oop java_thread) {
!   // The 16 most significant bits can be used for tracing
+   // so these bits are excluded using a mask.
+   static const jlong tid_mask = (((jlong)1) << 48) - 1;
+   return java_thread->long_field(_tid_offset) & tid_mask;
+ }
+ 
+ ByteSize java_lang_Thread::thread_id_offset() {
+   return in_ByteSize(_tid_offset);
  }
  
  oop java_lang_Thread::park_blocker(oop java_thread) {
    return java_thread->obj_field(_park_blocker_offset);
  }
  
+ oop java_lang_Thread::async_get_stack_trace(oop java_thread, TRAPS) {
+   JavaThread* thread;
+   bool is_virtual = java_lang_VirtualThread::is_instance(java_thread);
+   if (is_virtual) {
+     oop carrier_thread = java_lang_VirtualThread::carrier_thread(java_thread);
+     if (carrier_thread == NULL) {
+       return NULL;
+     }
+     thread = java_lang_Thread::thread(carrier_thread);
+   } else {
+     thread = java_lang_Thread::thread(java_thread);
+   }
+ 
+   class GetStackTraceClosure : public HandshakeClosure {
+   public:
+     const Handle _java_thread;
+     int _depth;
+     GrowableArray<Method*>* _methods;
+     GrowableArray<int>*     _bcis;
+     GrowableArray<oop>*     _continuations;
+ 
+     GetStackTraceClosure(Handle java_thread) :
+       HandshakeClosure("GetStackTraceClosure"), _java_thread(java_thread), _depth(0) {
+       // Pick some initial length
+       int init_length = MaxJavaStackTraceDepth/2;
+       _methods = new GrowableArray<Method*>(init_length);
+       _bcis = new GrowableArray<int>(init_length);
+       _continuations = new GrowableArray<oop>(init_length);
+     }
+ 
+     bool can_be_processed_by(Thread* thread) {
+       return thread->is_Java_thread();
+     }
+ 
+     void do_thread(Thread* th) {
+       JavaThread* thread = JavaThread::cast(th);
+ 
+       if (!thread->has_last_Java_frame()) {
+         return;
+       }
+ 
+       bool carrier = false;
+       oop vthread_scope = java_lang_VirtualThread::vthread_scope();
+       if (java_lang_VirtualThread::is_instance(_java_thread())) {
+         // if (thread->vthread() != _java_thread()) // We might be inside a System.executeOnCarrierThread
+         if (thread->last_continuation(vthread_scope)->cont_oop() !=
+               java_lang_VirtualThread::continuation(_java_thread())) {
+           return; // not mounted
+         }
+       } else {
+         carrier = (thread->last_continuation(vthread_scope) != NULL);
+       }
+ 
+       const int max_depth = MaxJavaStackTraceDepth;
+       const bool skip_hidden = !ShowHiddenFrames;
+ 
+       int total_count = 0;
+       for (vframeStream vfst(thread, false, false, carrier);
+            !vfst.at_end() && (max_depth == 0 || max_depth != total_count);
+            vfst.next()) {
+ 
+         if (skip_hidden && (vfst.method()->is_hidden() ||
+                             vfst.method()->is_continuation_enter_intrinsic())) continue;
+         _methods->push(vfst.method());
+         _bcis->push(vfst.bci());
+         _continuations->push(contScopeName(vfst.continuation()));
+         total_count++;
+       }
+ 
+       _depth = total_count;
+     }
+ 
+     oop contScopeName(oop cont) {
+       return cont == NULL ? NULL : jdk_internal_vm_ContinuationScope::name(Continuation::continuation_scope(cont));
+     }
+   };
+ 
+   // Handshake with target
+   ResourceMark rm(THREAD);
+   HandleMark   hm(THREAD);
+   GetStackTraceClosure gstc(Handle(THREAD, java_thread));
+   Handshake::execute(&gstc, thread);
+ 
+   // Stop if no stack trace is found.
+   if (gstc._depth == 0) {
+     return NULL;
+   }
+ 
+   // Convert the continuations into handles before allocation.
+   assert(gstc._depth == gstc._continuations->length(), "should be the same");
+   GrowableArray<Handle>* cont_handles = new GrowableArray<Handle>(gstc._depth);
+   for (int i = 0; i < gstc._depth; i++) {
+     cont_handles->push(Handle(THREAD, gstc._continuations->at(i)));
+   }
+ 
+   // Convert to StackTraceElement array
+   InstanceKlass* k = vmClasses::StackTraceElement_klass();
+   assert(k != NULL, "must be loaded in 1.4+");
+   if (k->should_be_initialized()) k->initialize(CHECK_NULL);
+   objArrayHandle trace = oopFactory::new_objArray_handle(k, gstc._depth, CHECK_NULL);
+ 
+   for (int i = 0; i < gstc._depth; i++) {
+     methodHandle method(THREAD, gstc._methods->at(i));
+     oop element = java_lang_StackTraceElement::create(method,
+                                                       gstc._bcis->at(i),
+                                                       cont_handles->at(i),
+                                                       CHECK_NULL);
+     trace->obj_at_put(i, element);
+   }
+ 
+   return trace();
+ }
+ 
  const char* java_lang_Thread::thread_status_name(oop java_thread) {
!   oop holder = java_lang_Thread::holder(java_thread);
+   assert(holder != NULL, "Java Thread not initialized");
+   JavaThreadStatus status = java_lang_Thread_FieldHolder::get_thread_status(holder);
    switch (status) {
      case JavaThreadStatus::NEW                      : return "NEW";
      case JavaThreadStatus::RUNNABLE                 : return "RUNNABLE";
      case JavaThreadStatus::SLEEPING                 : return "TIMED_WAITING (sleeping)";
      case JavaThreadStatus::IN_OBJECT_WAIT           : return "WAITING (on object monitor)";

*** 1843,17 ***
      default                       : return "UNKNOWN";
    };
  }
  int java_lang_ThreadGroup::_parent_offset;
  int java_lang_ThreadGroup::_name_offset;
- int java_lang_ThreadGroup::_threads_offset;
- int java_lang_ThreadGroup::_groups_offset;
  int java_lang_ThreadGroup::_maxPriority_offset;
- int java_lang_ThreadGroup::_destroyed_offset;
- int java_lang_ThreadGroup::_daemon_offset;
- int java_lang_ThreadGroup::_nthreads_offset;
  int java_lang_ThreadGroup::_ngroups_offset;
  
  oop  java_lang_ThreadGroup::parent(oop java_thread_group) {
    assert(oopDesc::is_oop(java_thread_group), "thread group must be oop");
    return java_thread_group->obj_field(_parent_offset);
  }
--- 2357,15 ---
      default                       : return "UNKNOWN";
    };
  }
  int java_lang_ThreadGroup::_parent_offset;
  int java_lang_ThreadGroup::_name_offset;
  int java_lang_ThreadGroup::_maxPriority_offset;
  int java_lang_ThreadGroup::_ngroups_offset;
+ int java_lang_ThreadGroup::_groups_offset;
+ int java_lang_ThreadGroup::_nweaks_offset;
+ int java_lang_ThreadGroup::_weaks_offset;
  
  oop  java_lang_ThreadGroup::parent(oop java_thread_group) {
    assert(oopDesc::is_oop(java_thread_group), "thread group must be oop");
    return java_thread_group->obj_field(_parent_offset);
  }

*** 1867,20 ***
      return java_lang_String::as_utf8_string(name);
    }
    return NULL;
  }
  
! int java_lang_ThreadGroup::nthreads(oop java_thread_group) {
    assert(oopDesc::is_oop(java_thread_group), "thread group must be oop");
!   return java_thread_group->int_field(_nthreads_offset);
- }
- 
- objArrayOop java_lang_ThreadGroup::threads(oop java_thread_group) {
-   oop threads = java_thread_group->obj_field(_threads_offset);
-   assert(threads != NULL, "threadgroups should have threads");
-   assert(threads->is_objArray(), "just checking"); // Todo: Add better type checking code
-   return objArrayOop(threads);
  }
  
  int java_lang_ThreadGroup::ngroups(oop java_thread_group) {
    assert(oopDesc::is_oop(java_thread_group), "thread group must be oop");
    return java_thread_group->int_field(_ngroups_offset);
--- 2379,13 ---
      return java_lang_String::as_utf8_string(name);
    }
    return NULL;
  }
  
! ThreadPriority java_lang_ThreadGroup::maxPriority(oop java_thread_group) {
    assert(oopDesc::is_oop(java_thread_group), "thread group must be oop");
!   return (ThreadPriority) java_thread_group->int_field(_maxPriority_offset);
  }
  
  int java_lang_ThreadGroup::ngroups(oop java_thread_group) {
    assert(oopDesc::is_oop(java_thread_group), "thread group must be oop");
    return java_thread_group->int_field(_ngroups_offset);

*** 1890,35 ***
    oop groups = java_thread_group->obj_field(_groups_offset);
    assert(groups == NULL || groups->is_objArray(), "just checking"); // Todo: Add better type checking code
    return objArrayOop(groups);
  }
  
! ThreadPriority java_lang_ThreadGroup::maxPriority(oop java_thread_group) {
-   assert(oopDesc::is_oop(java_thread_group), "thread group must be oop");
-   return (ThreadPriority) java_thread_group->int_field(_maxPriority_offset);
- }
- 
- bool java_lang_ThreadGroup::is_destroyed(oop java_thread_group) {
    assert(oopDesc::is_oop(java_thread_group), "thread group must be oop");
!   return java_thread_group->bool_field(_destroyed_offset) != 0;
  }
  
! bool java_lang_ThreadGroup::is_daemon(oop java_thread_group) {
!   assert(oopDesc::is_oop(java_thread_group), "thread group must be oop");
!   return java_thread_group->bool_field(_daemon_offset) != 0;
  }
  
  #define THREADGROUP_FIELDS_DO(macro) \
    macro(_parent_offset,      k, vmSymbols::parent_name(),      threadgroup_signature,       false); \
    macro(_name_offset,        k, vmSymbols::name_name(),        string_signature,            false); \
-   macro(_threads_offset,     k, vmSymbols::threads_name(),     thread_array_signature,      false); \
-   macro(_groups_offset,      k, vmSymbols::groups_name(),      threadgroup_array_signature, false); \
    macro(_maxPriority_offset, k, vmSymbols::maxPriority_name(), int_signature,               false); \
!   macro(_destroyed_offset,   k, vmSymbols::destroyed_name(),   bool_signature,              false); \
!   macro(_daemon_offset,      k, vmSymbols::daemon_name(),      bool_signature,              false); \
!   macro(_nthreads_offset,    k, vmSymbols::nthreads_name(),    int_signature,               false); \
!   macro(_ngroups_offset,     k, vmSymbols::ngroups_name(),     int_signature,               false)
  
  void java_lang_ThreadGroup::compute_offsets() {
    assert(_parent_offset == 0, "offsets should be initialized only once");
  
    InstanceKlass* k = vmClasses::ThreadGroup_klass();
--- 2395,29 ---
    oop groups = java_thread_group->obj_field(_groups_offset);
    assert(groups == NULL || groups->is_objArray(), "just checking"); // Todo: Add better type checking code
    return objArrayOop(groups);
  }
  
! int java_lang_ThreadGroup::nweaks(oop java_thread_group) {
    assert(oopDesc::is_oop(java_thread_group), "thread group must be oop");
!   return java_thread_group->int_field(_nweaks_offset);
  }
  
! objArrayOop java_lang_ThreadGroup::weaks(oop java_thread_group) {
!   oop weaks = java_thread_group->obj_field(_weaks_offset);
!   assert(weaks == NULL || weaks->is_objArray(), "just checking");
+   return objArrayOop(weaks);
  }
  
  #define THREADGROUP_FIELDS_DO(macro) \
    macro(_parent_offset,      k, vmSymbols::parent_name(),      threadgroup_signature,       false); \
    macro(_name_offset,        k, vmSymbols::name_name(),        string_signature,            false); \
    macro(_maxPriority_offset, k, vmSymbols::maxPriority_name(), int_signature,               false); \
!   macro(_ngroups_offset,     k, vmSymbols::ngroups_name(),     int_signature,               false); \
!   macro(_groups_offset,      k, vmSymbols::groups_name(),      threadgroup_array_signature, false); \
!   macro(_nweaks_offset,      k, vmSymbols::nweaks_name(),      int_signature,               false); \
!   macro(_weaks_offset,       k, vmSymbols::weaks_name(),       weakreference_array_signature, false);
  
  void java_lang_ThreadGroup::compute_offsets() {
    assert(_parent_offset == 0, "offsets should be initialized only once");
  
    InstanceKlass* k = vmClasses::ThreadGroup_klass();

*** 1929,10 ***
--- 2428,101 ---
  void java_lang_ThreadGroup::serialize_offsets(SerializeClosure* f) {
    THREADGROUP_FIELDS_DO(FIELD_SERIALIZE_OFFSET);
  }
  #endif
  
+ 
+ // java_lang_VirtualThread
+ 
+ int java_lang_VirtualThread::static_notify_jvmti_events_offset;
+ int java_lang_VirtualThread::static_vthread_scope_offset;
+ int java_lang_VirtualThread::_carrierThread_offset;
+ int java_lang_VirtualThread::_continuation_offset;
+ int java_lang_VirtualThread::_state_offset;
+ 
+ #define VTHREAD_FIELDS_DO(macro) \
+   macro(static_notify_jvmti_events_offset,  k, "notifyJvmtiEvents",  bool_signature, true); \
+   macro(static_vthread_scope_offset,  k, "VTHREAD_SCOPE",  continuationscope_signature, true); \
+   macro(_carrierThread_offset,  k, "carrierThread",  thread_signature, false); \
+   macro(_continuation_offset,  k, "cont",  continuation_signature, false); \
+   macro(_state_offset,  k, "state",  int_signature, false)
+ 
+ static jboolean vthread_notify_jvmti_events = JNI_FALSE;
+ 
+ void java_lang_VirtualThread::compute_offsets() {
+   InstanceKlass* k = vmClasses::VirtualThread_klass();
+   VTHREAD_FIELDS_DO(FIELD_COMPUTE_OFFSET);
+ }
+ 
+ void java_lang_VirtualThread::init_static_notify_jvmti_events() {
+   if (vthread_notify_jvmti_events) {
+     InstanceKlass* ik = vmClasses::VirtualThread_klass();
+     oop base = ik->static_field_base_raw();
+     base->release_bool_field_put(static_notify_jvmti_events_offset, vthread_notify_jvmti_events);
+   }
+ }
+ 
+ bool java_lang_VirtualThread::is_instance(oop obj) {
+   return obj != NULL && is_subclass(obj->klass());
+ }
+ 
+ oop java_lang_VirtualThread::carrier_thread(oop vthread) {
+   oop thread = vthread->obj_field(_carrierThread_offset);
+   return thread;
+ }
+ 
+ oop java_lang_VirtualThread::continuation(oop vthread) {
+   oop cont = vthread->obj_field(_continuation_offset);
+   return cont;
+ }
+ 
+ jshort java_lang_VirtualThread::state(oop vthread) {
+   return vthread->short_field_acquire(_state_offset);
+ }
+ 
+ JavaThreadStatus java_lang_VirtualThread::map_state_to_thread_status(jint state) {
+   JavaThreadStatus status = JavaThreadStatus::NEW;
+   switch (state) {
+     case NEW :
+       status = JavaThreadStatus::NEW;
+       break;
+     case STARTED :
+     case RUNNABLE :
+     case RUNNING :
+     case PARKING :
+     case YIELDING :
+       status = JavaThreadStatus::RUNNABLE;
+       break;
+     case PARKED :
+     case PARKED_SUSPENDED :
+     case PINNED :
+       status = JavaThreadStatus::PARKED;
+       break;
+     case TERMINATED :
+       status = JavaThreadStatus::TERMINATED;
+       break;
+     default:
+       ShouldNotReachHere();
+   }
+   return status;
+ }
+ 
+ #if INCLUDE_CDS
+ void java_lang_VirtualThread::serialize_offsets(SerializeClosure* f) {
+    VTHREAD_FIELDS_DO(FIELD_SERIALIZE_OFFSET);
+ }
+ #endif
+ 
+ bool java_lang_VirtualThread::notify_jvmti_events() {
+   return vthread_notify_jvmti_events == JNI_TRUE;
+ }
+ 
+ void java_lang_VirtualThread::set_notify_jvmti_events(jboolean enable) {
+   vthread_notify_jvmti_events = enable;
+ }
+ 
+ 
  // java_lang_Throwable
  
  int java_lang_Throwable::_backtrace_offset;
  int java_lang_Throwable::_detailMessage_offset;
  int java_lang_Throwable::_stackTrace_offset;

*** 2031,231 ***
  static inline bool version_matches(Method* method, int version) {
    assert(version < MAX_VERSION, "version is too big");
    return method != NULL && (method->constants()->version() == version);
  }
  
- // This class provides a simple wrapper over the internal structure of
- // exception backtrace to insulate users of the backtrace from needing
- // to know what it looks like.
- // The code of this class is not GC safe. Allocations can only happen
- // in expand().
- class BacktraceBuilder: public StackObj {
-  friend class BacktraceIterator;
-  private:
-   Handle          _backtrace;
-   objArrayOop     _head;
-   typeArrayOop    _methods;
-   typeArrayOop    _bcis;
-   objArrayOop     _mirrors;
-   typeArrayOop    _names; // Needed to insulate method name against redefinition.
-   // True if the top frame of the backtrace is omitted because it shall be hidden.
-   bool            _has_hidden_top_frame;
-   int             _index;
-   NoSafepointVerifier _nsv;
- 
-   enum {
-     trace_methods_offset = java_lang_Throwable::trace_methods_offset,
-     trace_bcis_offset    = java_lang_Throwable::trace_bcis_offset,
-     trace_mirrors_offset = java_lang_Throwable::trace_mirrors_offset,
-     trace_names_offset   = java_lang_Throwable::trace_names_offset,
-     trace_next_offset    = java_lang_Throwable::trace_next_offset,
-     trace_hidden_offset  = java_lang_Throwable::trace_hidden_offset,
-     trace_size           = java_lang_Throwable::trace_size,
-     trace_chunk_size     = java_lang_Throwable::trace_chunk_size
-   };
- 
-   // get info out of chunks
-   static typeArrayOop get_methods(objArrayHandle chunk) {
-     typeArrayOop methods = typeArrayOop(chunk->obj_at(trace_methods_offset));
-     assert(methods != NULL, "method array should be initialized in backtrace");
-     return methods;
-   }
-   static typeArrayOop get_bcis(objArrayHandle chunk) {
-     typeArrayOop bcis = typeArrayOop(chunk->obj_at(trace_bcis_offset));
-     assert(bcis != NULL, "bci array should be initialized in backtrace");
-     return bcis;
-   }
-   static objArrayOop get_mirrors(objArrayHandle chunk) {
-     objArrayOop mirrors = objArrayOop(chunk->obj_at(trace_mirrors_offset));
-     assert(mirrors != NULL, "mirror array should be initialized in backtrace");
-     return mirrors;
-   }
-   static typeArrayOop get_names(objArrayHandle chunk) {
-     typeArrayOop names = typeArrayOop(chunk->obj_at(trace_names_offset));
-     assert(names != NULL, "names array should be initialized in backtrace");
-     return names;
-   }
-   static bool has_hidden_top_frame(objArrayHandle chunk) {
-     oop hidden = chunk->obj_at(trace_hidden_offset);
-     return hidden != NULL;
-   }
- 
-  public:
- 
-   // constructor for new backtrace
-   BacktraceBuilder(TRAPS): _head(NULL), _methods(NULL), _bcis(NULL), _mirrors(NULL), _names(NULL), _has_hidden_top_frame(false) {
-     expand(CHECK);
-     _backtrace = Handle(THREAD, _head);
-     _index = 0;
-   }
- 
-   BacktraceBuilder(Thread* thread, objArrayHandle backtrace) {
-     _methods = get_methods(backtrace);
-     _bcis = get_bcis(backtrace);
-     _mirrors = get_mirrors(backtrace);
-     _names = get_names(backtrace);
-     _has_hidden_top_frame = has_hidden_top_frame(backtrace);
-     assert(_methods->length() == _bcis->length() &&
-            _methods->length() == _mirrors->length() &&
-            _mirrors->length() == _names->length(),
-            "method and source information arrays should match");
- 
-     // head is the preallocated backtrace
-     _head = backtrace();
-     _backtrace = Handle(thread, _head);
-     _index = 0;
-   }
- 
-   void expand(TRAPS) {
-     objArrayHandle old_head(THREAD, _head);
-     PauseNoSafepointVerifier pnsv(&_nsv);
- 
-     objArrayOop head = oopFactory::new_objectArray(trace_size, CHECK);
-     objArrayHandle new_head(THREAD, head);
- 
-     typeArrayOop methods = oopFactory::new_shortArray(trace_chunk_size, CHECK);
-     typeArrayHandle new_methods(THREAD, methods);
- 
-     typeArrayOop bcis = oopFactory::new_intArray(trace_chunk_size, CHECK);
-     typeArrayHandle new_bcis(THREAD, bcis);
- 
-     objArrayOop mirrors = oopFactory::new_objectArray(trace_chunk_size, CHECK);
-     objArrayHandle new_mirrors(THREAD, mirrors);
- 
-     typeArrayOop names = oopFactory::new_symbolArray(trace_chunk_size, CHECK);
-     typeArrayHandle new_names(THREAD, names);
- 
-     if (!old_head.is_null()) {
-       old_head->obj_at_put(trace_next_offset, new_head());
-     }
-     new_head->obj_at_put(trace_methods_offset, new_methods());
-     new_head->obj_at_put(trace_bcis_offset, new_bcis());
-     new_head->obj_at_put(trace_mirrors_offset, new_mirrors());
-     new_head->obj_at_put(trace_names_offset, new_names());
-     new_head->obj_at_put(trace_hidden_offset, NULL);
- 
-     _head    = new_head();
-     _methods = new_methods();
-     _bcis = new_bcis();
-     _mirrors = new_mirrors();
-     _names  = new_names();
-     _index = 0;
-   }
- 
-   oop backtrace() {
-     return _backtrace();
-   }
- 
-   inline void push(Method* method, int bci, TRAPS) {
-     // Smear the -1 bci to 0 since the array only holds unsigned
-     // shorts.  The later line number lookup would just smear the -1
-     // to a 0 even if it could be recorded.
-     if (bci == SynchronizationEntryBCI) bci = 0;
- 
-     if (_index >= trace_chunk_size) {
-       methodHandle mhandle(THREAD, method);
-       expand(CHECK);
-       method = mhandle();
-     }
- 
-     _methods->ushort_at_put(_index, method->orig_method_idnum());
-     _bcis->int_at_put(_index, Backtrace::merge_bci_and_version(bci, method->constants()->version()));
- 
-     // Note:this doesn't leak symbols because the mirror in the backtrace keeps the
-     // klass owning the symbols alive so their refcounts aren't decremented.
-     Symbol* name = method->name();
-     _names->symbol_at_put(_index, name);
- 
-     // We need to save the mirrors in the backtrace to keep the class
-     // from being unloaded while we still have this stack trace.
-     assert(method->method_holder()->java_mirror() != NULL, "never push null for mirror");
-     _mirrors->obj_at_put(_index, method->method_holder()->java_mirror());
-     _index++;
-   }
- 
-   void set_has_hidden_top_frame() {
-     if (!_has_hidden_top_frame) {
-       // It would be nice to add java/lang/Boolean::TRUE here
-       // to indicate that this backtrace has a hidden top frame.
-       // But this code is used before TRUE is allocated.
-       // Therefore let's just use an arbitrary legal oop
-       // available right here. _methods is a short[].
-       assert(_methods != NULL, "we need a legal oop");
-       _has_hidden_top_frame = true;
-       _head->obj_at_put(trace_hidden_offset, _methods);
-     }
-   }
- };
- 
- struct BacktraceElement : public StackObj {
-   int _method_id;
-   int _bci;
-   int _version;
-   Symbol* _name;
-   Handle _mirror;
-   BacktraceElement(Handle mirror, int mid, int version, int bci, Symbol* name) :
-                    _method_id(mid), _bci(bci), _version(version), _name(name), _mirror(mirror) {}
- };
- 
- class BacktraceIterator : public StackObj {
-   int _index;
-   objArrayHandle  _result;
-   objArrayHandle  _mirrors;
-   typeArrayHandle _methods;
-   typeArrayHandle _bcis;
-   typeArrayHandle _names;
- 
-   void init(objArrayHandle result, Thread* thread) {
-     // Get method id, bci, version and mirror from chunk
-     _result = result;
-     if (_result.not_null()) {
-       _methods = typeArrayHandle(thread, BacktraceBuilder::get_methods(_result));
-       _bcis = typeArrayHandle(thread, BacktraceBuilder::get_bcis(_result));
-       _mirrors = objArrayHandle(thread, BacktraceBuilder::get_mirrors(_result));
-       _names = typeArrayHandle(thread, BacktraceBuilder::get_names(_result));
-       _index = 0;
-     }
-   }
-  public:
-   BacktraceIterator(objArrayHandle result, Thread* thread) {
-     init(result, thread);
-     assert(_methods.is_null() || _methods->length() == java_lang_Throwable::trace_chunk_size, "lengths don't match");
-   }
- 
-   BacktraceElement next(Thread* thread) {
-     BacktraceElement e (Handle(thread, _mirrors->obj_at(_index)),
-                         _methods->ushort_at(_index),
-                         Backtrace::version_at(_bcis->int_at(_index)),
-                         Backtrace::bci_at(_bcis->int_at(_index)),
-                         _names->symbol_at(_index));
-     _index++;
- 
-     if (_index >= java_lang_Throwable::trace_chunk_size) {
-       int next_offset = java_lang_Throwable::trace_next_offset;
-       // Get next chunk
-       objArrayHandle result (thread, objArrayOop(_result->obj_at(next_offset)));
-       init(result, thread);
-     }
-     return e;
-   }
- 
-   bool repeat() {
-     return _result.not_null() && _mirrors->obj_at(_index) != NULL;
-   }
- };
- 
- 
  // Print stack trace element to resource allocated buffer
  static void print_stack_element_to_stream(outputStream* st, Handle mirror, int method_id,
                                            int version, int bci, Symbol* name) {
    ResourceMark rm;
  
--- 2621,10 ---

*** 2400,10 ***
--- 2769,11 ---
  }
  
  void java_lang_Throwable::fill_in_stack_trace(Handle throwable, const methodHandle& method, TRAPS) {
    if (!StackTraceInThrowable) return;
    ResourceMark rm(THREAD);
+   HandleMark hm(THREAD);
  
    // Start out by clearing the backtrace for this object, in case the VM
    // runs out of memory while allocating the stack trace
    set_backtrace(throwable(), NULL);
    // Clear lazily constructed Java level stacktrace if refilling occurs

*** 2417,11 ***
  
    // If there is no Java frame just return the method that was being called
    // with bci 0
    if (!thread->has_last_Java_frame()) {
      if (max_depth >= 1 && method() != NULL) {
!       bt.push(method(), 0, CHECK);
        log_info(stacktrace)("%s, %d", throwable->klass()->external_name(), 1);
        set_depth(throwable(), 1);
        set_backtrace(throwable(), bt.backtrace());
      }
      return;
--- 2787,11 ---
  
    // If there is no Java frame just return the method that was being called
    // with bci 0
    if (!thread->has_last_Java_frame()) {
      if (max_depth >= 1 && method() != NULL) {
!       bt.push(method(), 0, NULL, CHECK);
        log_info(stacktrace)("%s, %d", throwable->klass()->external_name(), 1);
        set_depth(throwable(), 1);
        set_backtrace(throwable(), bt.backtrace());
      }
      return;

*** 2435,33 ***
    // trace as utilizing vframe.
  #ifdef ASSERT
    vframeStream st(thread, false /* stop_at_java_call_stub */, false /* process_frames */);
  #endif
    int total_count = 0;
!   RegisterMap map(thread, false /* update */, false /* process_frames */);
    int decode_offset = 0;
    CompiledMethod* nm = NULL;
    bool skip_fillInStackTrace_check = false;
    bool skip_throwableInit_check = false;
    bool skip_hidden = !ShowHiddenFrames;
! 
    for (frame fr = thread->last_frame(); max_depth == 0 || max_depth != total_count;) {
      Method* method = NULL;
      int bci = 0;
  
      // Compiled java method case.
      if (decode_offset != 0) {
        DebugInfoReadStream stream(nm, decode_offset);
        decode_offset = stream.read_int();
        method = (Method*)nm->metadata_at(stream.read_int());
        bci = stream.read_bci();
      } else {
        if (fr.is_first_frame()) break;
        address pc = fr.pc();
        if (fr.is_interpreted_frame()) {
!         address bcp = fr.interpreter_frame_bcp();
!         method = fr.interpreter_frame_method();
          bci =  method->bci_from(bcp);
          fr = fr.sender(&map);
        } else {
          CodeBlob* cb = fr.cb();
          // HMMM QQQ might be nice to have frame return nm as NULL if cb is non-NULL
--- 2805,50 ---
    // trace as utilizing vframe.
  #ifdef ASSERT
    vframeStream st(thread, false /* stop_at_java_call_stub */, false /* process_frames */);
  #endif
    int total_count = 0;
!   RegisterMap map(thread, false /* update */, false /* process_frames */, true /* walk_cont */);
    int decode_offset = 0;
    CompiledMethod* nm = NULL;
    bool skip_fillInStackTrace_check = false;
    bool skip_throwableInit_check = false;
    bool skip_hidden = !ShowHiddenFrames;
!   bool show_carrier = ShowCarrierFrames;
+   Handle cont_h(THREAD, thread->last_continuation()->cont_oop());
    for (frame fr = thread->last_frame(); max_depth == 0 || max_depth != total_count;) {
      Method* method = NULL;
      int bci = 0;
+     oop contScopeName = (cont_h() != NULL) ? jdk_internal_vm_ContinuationScope::name(jdk_internal_vm_Continuation::scope(cont_h())) : (oop)NULL;
  
      // Compiled java method case.
      if (decode_offset != 0) {
        DebugInfoReadStream stream(nm, decode_offset);
        decode_offset = stream.read_int();
        method = (Method*)nm->metadata_at(stream.read_int());
        bci = stream.read_bci();
      } else {
        if (fr.is_first_frame()) break;
+ 
+       if (cont_h() != NULL && Continuation::is_continuation_enterSpecial(fr)) {
+         oop scope = jdk_internal_vm_Continuation::scope(cont_h());
+         if (!show_carrier && scope == java_lang_VirtualThread::vthread_scope()) break;
+ 
+         Handle parent_h(THREAD, jdk_internal_vm_Continuation::parent(cont_h()));
+         cont_h =  parent_h;
+       }
+ 
        address pc = fr.pc();
        if (fr.is_interpreted_frame()) {
!         address bcp;
!         if (!map.in_cont()) {
+           bcp = fr.interpreter_frame_bcp();
+           method = fr.interpreter_frame_method();
+         } else {
+           bcp = map.stack_chunk()->interpreter_frame_bcp(fr);
+           method = map.stack_chunk()->interpreter_frame_method(fr);
+         }
          bci =  method->bci_from(bcp);
          fr = fr.sender(&map);
        } else {
          CodeBlob* cb = fr.cb();
          // HMMM QQQ might be nice to have frame return nm as NULL if cb is non-NULL

*** 2469,10 ***
--- 2856,11 ---
          fr = fr.sender(&map);
          if (cb == NULL || !cb->is_compiled()) {
            continue;
          }
          nm = cb->as_compiled_method();
+         assert (nm->method() != NULL, "must be");
          if (nm->method()->is_native()) {
            method = nm->method();
            bci = 0;
          } else {
            PcDesc* pd = nm->pc_desc_at(pc);

*** 2482,13 ***
            continue;
          }
        }
      }
  #ifdef ASSERT
!     assert(st.method() == method && st.bci() == bci,
!            "Wrong stack trace");
!     st.next();
  #endif
  
      // the format of the stacktrace will be:
      // - 1 or more fillInStackTrace frames for the exception class (skipped)
      // - 0 or more <init> methods for the exception class (skipped)
--- 2870,14 ---
            continue;
          }
        }
      }
  #ifdef ASSERT
!     if (!st.at_end()) { // TODO LOOM remove once we show only vthread trace
!       assert(st.method() == method && st.bci() == bci, "Wrong stack trace");
!       st.next();
+     }
  #endif
  
      // the format of the stacktrace will be:
      // - 1 or more fillInStackTrace frames for the exception class (skipped)
      // - 0 or more <init> methods for the exception class (skipped)

*** 2514,20 ***
        } else {
          // there are none or we've seen them all - either way stop checking
          skip_throwableInit_check = true;
        }
      }
!     if (method->is_hidden()) {
        if (skip_hidden) {
          if (total_count == 0) {
            // The top frame will be hidden from the stack trace.
!           bt.set_has_hidden_top_frame();
          }
          continue;
        }
      }
!     bt.push(method, bci, CHECK);
      total_count++;
    }
  
    log_info(stacktrace)("%s, %d", throwable->klass()->external_name(), total_count);
  
--- 2903,21 ---
        } else {
          // there are none or we've seen them all - either way stop checking
          skip_throwableInit_check = true;
        }
      }
!     if (method->is_hidden() || method->is_continuation_enter_intrinsic()) {
        if (skip_hidden) {
          if (total_count == 0) {
            // The top frame will be hidden from the stack trace.
!           bt.set_has_hidden_top_frame(CHECK);
          }
          continue;
        }
      }
! 
+     bt.push(method, bci, contScopeName, CHECK);
      total_count++;
    }
  
    log_info(stacktrace)("%s, %d", throwable->klass()->external_name(), total_count);
  

*** 2588,11 ***
    // methods as preallocated errors aren't created by "java" code.
  
    // fill in as much stack trace as possible
    int chunk_count = 0;
    for (;!st.at_end(); st.next()) {
!     bt.push(st.method(), st.bci(), CHECK);
      chunk_count++;
  
      // Bail-out for deep stacks
      if (chunk_count >= trace_chunk_size) break;
    }
--- 2978,11 ---
    // methods as preallocated errors aren't created by "java" code.
  
    // fill in as much stack trace as possible
    int chunk_count = 0;
    for (;!st.at_end(); st.next()) {
!     bt.push(st.method(), st.bci(), NULL, CHECK);
      chunk_count++;
  
      // Bail-out for deep stacks
      if (chunk_count >= trace_chunk_size) break;
    }

*** 2602,24 ***
    // We support the Throwable immutability protocol defined for Java 7.
    java_lang_Throwable::set_stacktrace(throwable(), java_lang_Throwable::unassigned_stacktrace());
    assert(java_lang_Throwable::unassigned_stacktrace() != NULL, "not initialized");
  }
  
! void java_lang_Throwable::get_stack_trace_elements(Handle throwable,
                                                     objArrayHandle stack_trace_array_h, TRAPS) {
  
!   if (throwable.is_null() || stack_trace_array_h.is_null()) {
      THROW(vmSymbols::java_lang_NullPointerException());
    }
  
    assert(stack_trace_array_h->is_objArray(), "Stack trace array should be an array of StackTraceElenent");
  
!   if (stack_trace_array_h->length() != depth(throwable())) {
      THROW(vmSymbols::java_lang_IndexOutOfBoundsException());
    }
  
!   objArrayHandle result(THREAD, objArrayOop(backtrace(throwable())));
    BacktraceIterator iter(result, THREAD);
  
    int index = 0;
    while (iter.repeat()) {
      BacktraceElement bte = iter.next(THREAD);
--- 2992,24 ---
    // We support the Throwable immutability protocol defined for Java 7.
    java_lang_Throwable::set_stacktrace(throwable(), java_lang_Throwable::unassigned_stacktrace());
    assert(java_lang_Throwable::unassigned_stacktrace() != NULL, "not initialized");
  }
  
! void java_lang_Throwable::get_stack_trace_elements(int depth, Handle backtrace,
                                                     objArrayHandle stack_trace_array_h, TRAPS) {
  
!   if (backtrace.is_null() || stack_trace_array_h.is_null()) {
      THROW(vmSymbols::java_lang_NullPointerException());
    }
  
    assert(stack_trace_array_h->is_objArray(), "Stack trace array should be an array of StackTraceElenent");
  
!   if (stack_trace_array_h->length() != depth) {
      THROW(vmSymbols::java_lang_IndexOutOfBoundsException());
    }
  
!   objArrayHandle result(THREAD, objArrayOop(backtrace()));
    BacktraceIterator iter(result, THREAD);
  
    int index = 0;
    while (iter.repeat()) {
      BacktraceElement bte = iter.next(THREAD);

*** 2635,11 ***
  
      java_lang_StackTraceElement::fill_in(stack_trace_element, holder,
                                           method,
                                           bte._version,
                                           bte._bci,
!                                          bte._name, CHECK);
    }
  }
  
  Handle java_lang_Throwable::get_cause_with_stack_trace(Handle throwable, TRAPS) {
    // Call to JVM to fill in the stack trace and clear declaringClassObject to
--- 3025,13 ---
  
      java_lang_StackTraceElement::fill_in(stack_trace_element, holder,
                                           method,
                                           bte._version,
                                           bte._bci,
!                                          bte._name,
+                                          bte._cont,
+                                          CHECK);
    }
  }
  
  Handle java_lang_Throwable::get_cause_with_stack_trace(Handle throwable, TRAPS) {
    // Call to JVM to fill in the stack trace and clear declaringClassObject to

*** 2715,28 ***
    *method = m;
    *bci = bte._bci;
    return true;
  }
  
! oop java_lang_StackTraceElement::create(const methodHandle& method, int bci, TRAPS) {
    // Allocate java.lang.StackTraceElement instance
    InstanceKlass* k = vmClasses::StackTraceElement_klass();
    assert(k != NULL, "must be loaded in 1.4+");
    if (k->should_be_initialized()) {
      k->initialize(CHECK_NULL);
    }
  
    Handle element = k->allocate_instance_handle(CHECK_NULL);
  
    int version = method->constants()->version();
!   fill_in(element, method->method_holder(), method, version, bci, method->name(), CHECK_NULL);
    return element();
  }
  
  void java_lang_StackTraceElement::fill_in(Handle element,
                                            InstanceKlass* holder, const methodHandle& method,
!                                           int version, int bci, Symbol* name, TRAPS) {
    assert(element->is_a(vmClasses::StackTraceElement_klass()), "sanity check");
  
    ResourceMark rm(THREAD);
    HandleMark hm(THREAD);
  
--- 3107,28 ---
    *method = m;
    *bci = bte._bci;
    return true;
  }
  
! oop java_lang_StackTraceElement::create(const methodHandle& method, int bci, Handle contScope, TRAPS) {
    // Allocate java.lang.StackTraceElement instance
    InstanceKlass* k = vmClasses::StackTraceElement_klass();
    assert(k != NULL, "must be loaded in 1.4+");
    if (k->should_be_initialized()) {
      k->initialize(CHECK_NULL);
    }
  
    Handle element = k->allocate_instance_handle(CHECK_NULL);
  
    int version = method->constants()->version();
!   fill_in(element, method->method_holder(), method, version, bci, method->name(), contScope, CHECK_NULL);
    return element();
  }
  
  void java_lang_StackTraceElement::fill_in(Handle element,
                                            InstanceKlass* holder, const methodHandle& method,
!                                           int version, int bci, Symbol* name, Handle contScopeName, TRAPS) {
    assert(element->is_a(vmClasses::StackTraceElement_klass()), "sanity check");
  
    ResourceMark rm(THREAD);
    HandleMark hm(THREAD);
  

*** 2782,10 ***
--- 3174,13 ---
      decode_file_and_line(java_class, holder, version, method, bci, source, source_file, line_number, CHECK);
  
      java_lang_StackTraceElement::set_fileName(element(), source_file);
      java_lang_StackTraceElement::set_lineNumber(element(), line_number);
    }
+ 
+   // Fill in continuation scope
+   java_lang_StackTraceElement::set_contScopeName(element(), contScopeName());
  }
  
  void java_lang_StackTraceElement::decode_file_and_line(Handle java_class,
                                                         InstanceKlass* holder,
                                                         int version,

*** 2834,14 ***
  // java_lang_StackFrameInfo
  
  int java_lang_StackFrameInfo::_memberName_offset;
  int java_lang_StackFrameInfo::_bci_offset;
  int java_lang_StackFrameInfo::_version_offset;
  
  #define STACKFRAMEINFO_FIELDS_DO(macro) \
    macro(_memberName_offset,     k, "memberName",  object_signature, false); \
!   macro(_bci_offset,            k, "bci",         int_signature,    false)
  
  void java_lang_StackFrameInfo::compute_offsets() {
    InstanceKlass* k = vmClasses::StackFrameInfo_klass();
    STACKFRAMEINFO_FIELDS_DO(FIELD_COMPUTE_OFFSET);
    STACKFRAMEINFO_INJECTED_FIELDS(INJECTED_FIELD_COMPUTE_OFFSET);
--- 3229,16 ---
  // java_lang_StackFrameInfo
  
  int java_lang_StackFrameInfo::_memberName_offset;
  int java_lang_StackFrameInfo::_bci_offset;
  int java_lang_StackFrameInfo::_version_offset;
+ int java_lang_StackFrameInfo::_contScope_offset;
  
  #define STACKFRAMEINFO_FIELDS_DO(macro) \
    macro(_memberName_offset,     k, "memberName",  object_signature, false); \
!   macro(_bci_offset,            k, "bci",         int_signature,    false); \
+   macro(_contScope_offset,      k, "contScope",   continuationscope_signature, false)
  
  void java_lang_StackFrameInfo::compute_offsets() {
    InstanceKlass* k = vmClasses::StackFrameInfo_klass();
    STACKFRAMEINFO_FIELDS_DO(FIELD_COMPUTE_OFFSET);
    STACKFRAMEINFO_INJECTED_FIELDS(INJECTED_FIELD_COMPUTE_OFFSET);

*** 2861,38 ***
    // we should expand MemberName::name when Throwable uses StackTrace
    // MethodHandles::expand_MemberName(mname, MethodHandles::_suppress_defc|MethodHandles::_suppress_type, CHECK_NULL);
    return method;
  }
  
! void java_lang_StackFrameInfo::set_method_and_bci(Handle stackFrame, const methodHandle& method, int bci, TRAPS) {
    // set Method* or mid/cpref
    HandleMark hm(THREAD);
    Handle mname(THREAD, stackFrame->obj_field(_memberName_offset));
    InstanceKlass* ik = method->method_holder();
    CallInfo info(method(), ik, CHECK);
    MethodHandles::init_method_MemberName(mname, info);
    // set bci
    java_lang_StackFrameInfo::set_bci(stackFrame(), bci);
    // method may be redefined; store the version
    int version = method->constants()->version();
    assert((jushort)version == version, "version should be short");
    java_lang_StackFrameInfo::set_version(stackFrame(), (short)version);
  }
  
  void java_lang_StackFrameInfo::to_stack_trace_element(Handle stackFrame, Handle stack_trace_element, TRAPS) {
    ResourceMark rm(THREAD);
    HandleMark hm(THREAD);
    Handle mname(THREAD, stackFrame->obj_field(java_lang_StackFrameInfo::_memberName_offset));
    Klass* clazz = java_lang_Class::as_Klass(java_lang_invoke_MemberName::clazz(mname()));
    InstanceKlass* holder = InstanceKlass::cast(clazz);
    Method* method = java_lang_StackFrameInfo::get_method(stackFrame, holder, CHECK);
  
    short version = stackFrame->short_field(_version_offset);
    int bci = stackFrame->int_field(_bci_offset);
    Symbol* name = method->name();
!   java_lang_StackTraceElement::fill_in(stack_trace_element, holder, methodHandle(THREAD, method),
!                                        version, bci, name, CHECK);
  }
  
  void java_lang_StackFrameInfo::set_version(oop element, short value) {
    element->short_field_put(_version_offset, value);
  }
--- 3258,47 ---
    // we should expand MemberName::name when Throwable uses StackTrace
    // MethodHandles::expand_MemberName(mname, MethodHandles::_suppress_defc|MethodHandles::_suppress_type, CHECK_NULL);
    return method;
  }
  
! void java_lang_StackFrameInfo::set_method_and_bci(Handle stackFrame, const methodHandle& method, int bci, oop cont, TRAPS) {
    // set Method* or mid/cpref
    HandleMark hm(THREAD);
    Handle mname(THREAD, stackFrame->obj_field(_memberName_offset));
+   Handle cont_h (THREAD, cont);
    InstanceKlass* ik = method->method_holder();
    CallInfo info(method(), ik, CHECK);
    MethodHandles::init_method_MemberName(mname, info);
    // set bci
    java_lang_StackFrameInfo::set_bci(stackFrame(), bci);
    // method may be redefined; store the version
    int version = method->constants()->version();
    assert((jushort)version == version, "version should be short");
    java_lang_StackFrameInfo::set_version(stackFrame(), (short)version);
+ 
+   oop contScope = cont_h() != NULL ? jdk_internal_vm_Continuation::scope(cont_h()) : (oop)NULL;
+   java_lang_StackFrameInfo::set_contScope(stackFrame(), contScope);
  }
  
  void java_lang_StackFrameInfo::to_stack_trace_element(Handle stackFrame, Handle stack_trace_element, TRAPS) {
    ResourceMark rm(THREAD);
    HandleMark hm(THREAD);
    Handle mname(THREAD, stackFrame->obj_field(java_lang_StackFrameInfo::_memberName_offset));
    Klass* clazz = java_lang_Class::as_Klass(java_lang_invoke_MemberName::clazz(mname()));
    InstanceKlass* holder = InstanceKlass::cast(clazz);
    Method* method = java_lang_StackFrameInfo::get_method(stackFrame, holder, CHECK);
+   oop contScope = stackFrame->obj_field(java_lang_StackFrameInfo::_contScope_offset);
+   Handle contScopeName(THREAD, contScope != (oop)NULL ? jdk_internal_vm_ContinuationScope::name(contScope) : (oop)NULL);
  
    short version = stackFrame->short_field(_version_offset);
    int bci = stackFrame->int_field(_bci_offset);
    Symbol* name = method->name();
!   java_lang_StackTraceElement::fill_in(stack_trace_element, holder, methodHandle(THREAD, method), version, bci, name, contScopeName, CHECK);
! }
+ 
+ void java_lang_StackTraceElement::set_contScopeName(oop element, oop value) {
+   element->obj_field_put(_contScopeName_offset, value);
  }
  
  void java_lang_StackFrameInfo::set_version(oop element, short value) {
    element->short_field_put(_version_offset, value);
  }

*** 2900,10 ***
--- 3306,14 ---
  void java_lang_StackFrameInfo::set_bci(oop element, int value) {
    assert(value >= 0 && value < max_jushort, "must be a valid bci value");
    element->int_field_put(_bci_offset, value);
  }
  
+ void java_lang_StackFrameInfo::set_contScope(oop element, oop value) {
+   element->obj_field_put(_contScope_offset, value);
+ }
+ 
  int java_lang_LiveStackFrameInfo::_monitors_offset;
  int java_lang_LiveStackFrameInfo::_locals_offset;
  int java_lang_LiveStackFrameInfo::_operands_offset;
  int java_lang_LiveStackFrameInfo::_mode_offset;
  

*** 4488,10 ***
--- 4898,12 ---
        mirror->bool_field_put(fd->offset(), _big_endian);
      } else if (fd->name() == vmSymbols::use_unaligned_access_name()) {
        mirror->bool_field_put(fd->offset(), _use_unaligned_access);
      } else if (fd->name() == vmSymbols::data_cache_line_flush_size_name()) {
        mirror->int_field_put(fd->offset(), _data_cache_line_flush_size);
+     } else if (fd->name() == vmSymbols::scoped_cache_shift_name()) {
+       mirror->int_field_put(fd->offset(), ScopeLocalCacheSize ? exact_log2(ScopeLocalCacheSize) : -1);
      } else {
        assert(false, "unexpected UnsafeConstants field");
      }
    }
  };

*** 4510,20 ***
  int java_lang_StackTraceElement::_moduleName_offset;
  int java_lang_StackTraceElement::_moduleVersion_offset;
  int java_lang_StackTraceElement::_classLoaderName_offset;
  int java_lang_StackTraceElement::_declaringClass_offset;
  int java_lang_StackTraceElement::_declaringClassObject_offset;
  
  #define STACKTRACEELEMENT_FIELDS_DO(macro) \
    macro(_declaringClassObject_offset,  k, "declaringClassObject", class_signature, false); \
    macro(_classLoaderName_offset, k, "classLoaderName", string_signature, false); \
    macro(_moduleName_offset,      k, "moduleName",      string_signature, false); \
    macro(_moduleVersion_offset,   k, "moduleVersion",   string_signature, false); \
    macro(_declaringClass_offset,  k, "declaringClass",  string_signature, false); \
    macro(_methodName_offset,      k, "methodName",      string_signature, false); \
    macro(_fileName_offset,        k, "fileName",        string_signature, false); \
!   macro(_lineNumber_offset,      k, "lineNumber",      int_signature,    false)
  
  // Support for java_lang_StackTraceElement
  void java_lang_StackTraceElement::compute_offsets() {
    InstanceKlass* k = vmClasses::StackTraceElement_klass();
    STACKTRACEELEMENT_FIELDS_DO(FIELD_COMPUTE_OFFSET);
--- 4922,22 ---
  int java_lang_StackTraceElement::_moduleName_offset;
  int java_lang_StackTraceElement::_moduleVersion_offset;
  int java_lang_StackTraceElement::_classLoaderName_offset;
  int java_lang_StackTraceElement::_declaringClass_offset;
  int java_lang_StackTraceElement::_declaringClassObject_offset;
+ int java_lang_StackTraceElement::_contScopeName_offset;
  
  #define STACKTRACEELEMENT_FIELDS_DO(macro) \
    macro(_declaringClassObject_offset,  k, "declaringClassObject", class_signature, false); \
    macro(_classLoaderName_offset, k, "classLoaderName", string_signature, false); \
    macro(_moduleName_offset,      k, "moduleName",      string_signature, false); \
    macro(_moduleVersion_offset,   k, "moduleVersion",   string_signature, false); \
    macro(_declaringClass_offset,  k, "declaringClass",  string_signature, false); \
    macro(_methodName_offset,      k, "methodName",      string_signature, false); \
    macro(_fileName_offset,        k, "fileName",        string_signature, false); \
!   macro(_lineNumber_offset,      k, "lineNumber",      int_signature,    false); \
+   macro(_contScopeName_offset,   k, "contScopeName",   string_signature, false)
  
  // Support for java_lang_StackTraceElement
  void java_lang_StackTraceElement::compute_offsets() {
    InstanceKlass* k = vmClasses::StackTraceElement_klass();
    STACKTRACEELEMENT_FIELDS_DO(FIELD_COMPUTE_OFFSET);

*** 4613,10 ***
--- 5027,104 ---
  
  void java_lang_AssertionStatusDirectives::set_deflt(oop o, bool val) {
    o->bool_field_put(_deflt_offset, val);
  }
  
+ // Support for jdk.internal.vm.Continuation
+ 
+ int jdk_internal_vm_ContinuationScope::_name_offset;
+ int jdk_internal_vm_Continuation::_scope_offset;
+ int jdk_internal_vm_Continuation::_target_offset;
+ int jdk_internal_vm_Continuation::_tail_offset;
+ int jdk_internal_vm_Continuation::_parent_offset;
+ int jdk_internal_vm_Continuation::_yieldInfo_offset;
+ int jdk_internal_vm_Continuation::_cs_offset;
+ int jdk_internal_vm_Continuation::_reset_offset;
+ int jdk_internal_vm_Continuation::_mounted_offset;
+ int jdk_internal_vm_Continuation::_done_offset;
+ int jdk_internal_vm_Continuation::_preempted_offset;
+ 
+ #define CONTINUATIONSCOPE_FIELDS_DO(macro) \
+   macro(_name_offset, k, vmSymbols::name_name(), string_signature, false);
+ 
+ void jdk_internal_vm_ContinuationScope::compute_offsets() {
+   InstanceKlass* k = vmClasses::ContinuationScope_klass();
+   CONTINUATIONSCOPE_FIELDS_DO(FIELD_COMPUTE_OFFSET);
+ }
+ 
+ #if INCLUDE_CDS
+ void jdk_internal_vm_ContinuationScope::serialize_offsets(SerializeClosure* f) {
+   CONTINUATIONSCOPE_FIELDS_DO(FIELD_SERIALIZE_OFFSET);
+ }
+ #endif
+ 
+ // Support for jdk.internal.vm.Continuation
+ 
+ #define CONTINUATION_FIELDS_DO(macro) \
+   macro(_scope_offset,     k, vmSymbols::scope_name(),     continuationscope_signature, false); \
+   macro(_target_offset,    k, vmSymbols::target_name(),    runnable_signature,          false); \
+   macro(_parent_offset,    k, vmSymbols::parent_name(),    continuation_signature,      false); \
+   macro(_yieldInfo_offset, k, vmSymbols::yieldInfo_name(), object_signature,            false); \
+   macro(_tail_offset,      k, vmSymbols::tail_name(),      stackchunk_signature,        false); \
+   macro(_cs_offset,        k, vmSymbols::cs_name(),        short_signature,             false); \
+   macro(_reset_offset,     k, vmSymbols::reset_name(),     bool_signature,              false); \
+   macro(_mounted_offset,   k, vmSymbols::mounted_name(),   bool_signature,              false); \
+   macro(_done_offset,      k, vmSymbols::done_name(),      bool_signature,              false); \
+   macro(_preempted_offset, k, "preempted",                 bool_signature,              false);
+ 
+ void jdk_internal_vm_Continuation::compute_offsets() {
+   InstanceKlass* k = vmClasses::Continuation_klass();
+   CONTINUATION_FIELDS_DO(FIELD_COMPUTE_OFFSET);
+ }
+ 
+ #if INCLUDE_CDS
+ void jdk_internal_vm_Continuation::serialize_offsets(SerializeClosure* f) {
+   CONTINUATION_FIELDS_DO(FIELD_SERIALIZE_OFFSET);
+ }
+ #endif
+ 
+ // Support for jdk.internal.vm.StackChunk
+ 
+ int jdk_internal_vm_StackChunk::_parent_offset;
+ int jdk_internal_vm_StackChunk::_size_offset;
+ int jdk_internal_vm_StackChunk::_sp_offset;
+ int jdk_internal_vm_StackChunk::_pc_offset;
+ int jdk_internal_vm_StackChunk::_argsize_offset;
+ int jdk_internal_vm_StackChunk::_flags_offset;
+ int jdk_internal_vm_StackChunk::_gcSP_offset;
+ int jdk_internal_vm_StackChunk::_markCycle_offset;
+ int jdk_internal_vm_StackChunk::_maxSize_offset;
+ int jdk_internal_vm_StackChunk::_numFrames_offset;
+ int jdk_internal_vm_StackChunk::_numOops_offset;
+ int jdk_internal_vm_StackChunk::_cont_offset;
+ 
+ #define STACKCHUNK_FIELDS_DO(macro) \
+   macro(_parent_offset,    k, vmSymbols::parent_name(),    stackchunk_signature, false); \
+   macro(_size_offset,      k, vmSymbols::size_name(),      int_signature,        false); \
+   macro(_sp_offset,        k, vmSymbols::sp_name(),        int_signature,        false); \
+   macro(_pc_offset,        k, vmSymbols::pc_name(),        long_signature,       false); \
+   macro(_argsize_offset,   k, vmSymbols::argsize_name(),   int_signature,        false); \
+   macro(_flags_offset,     k, "flags",                     byte_signature,       false); \
+   macro(_gcSP_offset,      k, "gcSP",                      int_signature,        false); \
+   macro(_markCycle_offset, k, "markCycle",                 long_signature,       false); \
+   macro(_maxSize_offset,   k, vmSymbols::maxSize_name(),   int_signature,        false); \
+   macro(_numFrames_offset, k, vmSymbols::numFrames_name(), int_signature,        false); \
+   macro(_numOops_offset,   k, vmSymbols::numOops_name(),   int_signature,        false); \
+   macro(_cont_offset,      k, "cont",                      continuation_signature, false);
+ 
+ void jdk_internal_vm_StackChunk::compute_offsets() {
+   InstanceKlass* k = vmClasses::StackChunk_klass();
+   STACKCHUNK_FIELDS_DO(FIELD_COMPUTE_OFFSET);
+ }
+ 
+ #if INCLUDE_CDS
+ void jdk_internal_vm_StackChunk::serialize_offsets(SerializeClosure* f) {
+   STACKCHUNK_FIELDS_DO(FIELD_SERIALIZE_OFFSET);
+ }
+ #endif
+ 
+ 
  int java_util_concurrent_locks_AbstractOwnableSynchronizer::_owner_offset;
  
  #define AOS_FIELDS_DO(macro) \
    macro(_owner_offset, k, "exclusiveOwnerThread", thread_signature, false)
  

*** 5035,10 ***
--- 5543,18 ---
    CHECK_OFFSET("java/lang/Byte",      java_lang_boxing_object, value, "B");
    CHECK_OFFSET("java/lang/Short",     java_lang_boxing_object, value, "S");
    CHECK_OFFSET("java/lang/Integer",   java_lang_boxing_object, value, "I");
    CHECK_LONG_OFFSET("java/lang/Long", java_lang_boxing_object, value, "J");
  
+   // jdk.internal.vm.Continuation
+ 
+   // CHECK_OFFSET("jdk/internal/vm/Continuation", jdk_internal_vm_Continuation, target,   "Ljava/lang/Runnable;");
+   // CHECK_OFFSET("jdk/internal/vm/Continuation", jdk_internal_vm_Continuation, stack,    "[I");
+   // CHECK_OFFSET("jdk/internal/vm/Continuation", jdk_internal_vm_Continuation, parent,   "Ljdk/internal/vm/Continuation;");
+   // CHECK_OFFSET("jdk/internal/vm/Continuation", jdk_internal_vm_Continuation, lastFP,   "I");
+   // CHECK_OFFSET("jdk/internal/vm/Continuation", jdk_internal_vm_Continuation, lastSP,   "I");
+ 
    if (!valid) vm_exit_during_initialization("Field offset verification failed");
  }
  
  #endif // PRODUCT
  

*** 5067,7 ***
--- 5583,8 ---
  }
  
  void javaClasses_init() {
    JavaClasses::compute_offsets();
    JavaClasses::check_offsets();
+   java_lang_VirtualThread::init_static_notify_jvmti_events();
    FilteredFieldsMap::initialize();  // must be done after computing offsets.
  }
< prev index next >