diff a/src/hotspot/share/classfile/javaClasses.cpp b/src/hotspot/share/classfile/javaClasses.cpp
--- a/src/hotspot/share/classfile/javaClasses.cpp
+++ b/src/hotspot/share/classfile/javaClasses.cpp
@@ -1620,10 +1620,11 @@
 bool java_lang_Thread::is_in_VTMS_transition(oop java_thread) {
   return java_thread->bool_field_volatile(_jvmti_is_in_VTMS_transition_offset);
 }
 
 void java_lang_Thread::set_is_in_VTMS_transition(oop java_thread, bool val) {
+  assert(is_in_VTMS_transition(java_thread) != val, "already %s transition", val ? "inside" : "outside");
   java_thread->bool_field_put_volatile(_jvmti_is_in_VTMS_transition_offset, val);
 }
 
 int java_lang_Thread::is_in_VTMS_transition_offset() {
   return _jvmti_is_in_VTMS_transition_offset;
@@ -1955,16 +1956,22 @@
 
 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;
+int java_lang_VirtualThread::_next_offset;
+int java_lang_VirtualThread::_onWaitingList_offset;
+int java_lang_VirtualThread::_recheckInterval_offset;
 
 #define VTHREAD_FIELDS_DO(macro) \
   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)
+  macro(_state_offset,                     k, "state",              int_signature,               false); \
+  macro(_next_offset,                      k, "next",               vthread_signature,           false); \
+  macro(_onWaitingList_offset,             k, "onWaitingList",      byte_signature,              false); \
+  macro(_recheckInterval_offset,           k, "recheckInterval",    byte_signature,              false);
 
 
 void java_lang_VirtualThread::compute_offsets() {
   InstanceKlass* k = vmClasses::VirtualThread_klass();
   VTHREAD_FIELDS_DO(FIELD_COMPUTE_OFFSET);
@@ -1986,10 +1993,47 @@
 
 int java_lang_VirtualThread::state(oop vthread) {
   return vthread->int_field_acquire(_state_offset);
 }
 
+void java_lang_VirtualThread::set_state(oop vthread, int state) {
+  vthread->release_int_field_put(_state_offset, state);
+}
+
+oop java_lang_VirtualThread::next(oop vthread) {
+  return vthread->obj_field(_next_offset);
+}
+
+void java_lang_VirtualThread::set_next(oop vthread, oop next_vthread) {
+  vthread->obj_field_put(_next_offset, next_vthread);
+}
+
+bool java_lang_VirtualThread::set_onWaitingList(oop vthread, OopHandle& list_head) {
+  uint8_t* addr = vthread->field_addr<uint8_t>(_onWaitingList_offset);
+  uint8_t value = Atomic::load(addr);
+  assert(value == 0x00 || value == 0x01, "invariant");
+  if (value == 0x00) {
+    value = Atomic::cmpxchg(addr, (uint8_t)0x00, (uint8_t)0x01);
+    if (value == 0x00) {
+      for (;;) {
+        oop head = list_head.resolve();
+        java_lang_VirtualThread::set_next(vthread, head);
+        if (list_head.cmpxchg(head, vthread) == head) return true;
+      }
+    }
+  }
+  return false; // already on waiting list
+}
+
+jbyte java_lang_VirtualThread::recheckInterval(oop vthread) {
+  return vthread->byte_field(_recheckInterval_offset);
+}
+
+void java_lang_VirtualThread::set_recheckInterval(oop vthread, jbyte value) {
+  vthread->release_byte_field_put(_recheckInterval_offset, value);
+}
+
 JavaThreadStatus java_lang_VirtualThread::map_state_to_thread_status(int state) {
   JavaThreadStatus status = JavaThreadStatus::NEW;
   switch (state & ~SUSPENDED) {
     case NEW:
       status = JavaThreadStatus::NEW;
@@ -1999,29 +2043,39 @@
     case PARKING:
     case TIMED_PARKING:
     case UNPARKED:
     case YIELDING:
     case YIELDED:
+    case BLOCKING:
+    case UNBLOCKED:
       status = JavaThreadStatus::RUNNABLE;
       break;
     case PARKED:
     case PINNED:
       status = JavaThreadStatus::PARKED;
       break;
     case TIMED_PARKED:
     case TIMED_PINNED:
       status = JavaThreadStatus::PARKED_TIMED;
       break;
+    case BLOCKED:
+      status = JavaThreadStatus::BLOCKED_ON_MONITOR_ENTER;
+      break;
     case TERMINATED:
       status = JavaThreadStatus::TERMINATED;
       break;
     default:
       ShouldNotReachHere();
   }
   return status;
 }
 
+bool java_lang_VirtualThread::is_preempted(oop vthread) {
+  oop continuation = java_lang_VirtualThread::continuation(vthread);
+  return jdk_internal_vm_Continuation::is_preempted(continuation);
+}
+
 #if INCLUDE_CDS
 void java_lang_VirtualThread::serialize_offsets(SerializeClosure* f) {
    VTHREAD_FIELDS_DO(FIELD_SERIALIZE_OFFSET);
 }
 #endif
