< prev index next >

src/hotspot/share/runtime/continuation.cpp

Print this page
*** 24,17 ***
--- 24,20 ---
  
  #include "precompiled.hpp"
  #include "classfile/vmSymbols.hpp"
  #include "gc/shared/barrierSetNMethod.hpp"
  #include "oops/method.inline.hpp"
+ #include "oops/oop.inline.hpp"
+ #include "prims/jvmtiThreadState.inline.hpp"
  #include "runtime/continuation.hpp"
  #include "runtime/continuationEntry.inline.hpp"
  #include "runtime/continuationHelper.inline.hpp"
  #include "runtime/continuationJavaClasses.inline.hpp"
  #include "runtime/continuationWrapper.inline.hpp"
  #include "runtime/interfaceSupport.inline.hpp"
  #include "runtime/javaThread.inline.hpp"
+ #include "runtime/jniHandles.inline.hpp"
  #include "runtime/osThread.hpp"
  #include "runtime/vframe.inline.hpp"
  #include "runtime/vframe_hp.hpp"
  
  // defined in continuationFreezeThaw.cpp

*** 52,10 ***
--- 55,131 ---
       THROW_MSG(vmSymbols::java_lang_IllegalStateException(), "pin underflow");
    }
  }
  JVM_END
  
+ #ifdef LOOM_MONITOR_SUPPORT
+ 
+ #if INCLUDE_JVMTI
+ class JvmtiUnmountBeginMark : public StackObj {
+   Handle _vthread;
+   JavaThread* _target;
+   int _preempt_result;
+   bool _failed;
+ 
+  public:
+   JvmtiUnmountBeginMark(JavaThread* t) :
+     _vthread(t, t->vthread()), _target(t), _preempt_result(freeze_pinned_native), _failed(false) {
+     assert(!_target->is_in_any_VTMS_transition(), "must be");
+ 
+     if (JvmtiVTMSTransitionDisabler::VTMS_notify_jvmti_events()) {
+       JvmtiVTMSTransitionDisabler::start_VTMS_transition((jthread)_vthread.raw_value(), /* is_mount */ false);
+ 
+       // Don't preempt if there is a pending popframe or earlyret operation. This can
+       // happen in start_VTMS_transition() so we need to check it here.
+       if (JvmtiExport::can_pop_frame() || JvmtiExport::can_force_early_return()) {
+         JvmtiThreadState* state = _target->jvmti_thread_state();
+         if (_target->has_pending_popframe() || (state != nullptr && state->is_earlyret_pending())) {
+           _failed = true;
+         }
+       }
+     } else {
+       _target->set_is_in_VTMS_transition(true);
+       java_lang_Thread::set_is_in_VTMS_transition(_vthread(), true);
+     }
+   }
+   ~JvmtiUnmountBeginMark() {
+     assert(!_target->is_suspended(), "must be");
+ 
+     assert(_target->is_in_VTMS_transition(), "must be");
+     assert(java_lang_Thread::is_in_VTMS_transition(_vthread()), "must be");
+ 
+     // Read it again since for late binding agents the flag could have
+     // been set while blocked in the allocation path during freeze.
+     bool jvmti_present = JvmtiVTMSTransitionDisabler::VTMS_notify_jvmti_events();
+ 
+     if (_preempt_result != freeze_ok) {
+       // Undo transition
+       if (jvmti_present) {
+         JvmtiVTMSTransitionDisabler::finish_VTMS_transition((jthread)_vthread.raw_value(), false);
+       } else {
+         _target->set_is_in_VTMS_transition(false);
+         java_lang_Thread::set_is_in_VTMS_transition(_vthread(), false);
+       }
+     } else {
+       if (jvmti_present) {
+         _target->rebind_to_jvmti_thread_state_of(_target->threadObj());
+         if (JvmtiExport::should_post_vthread_mount()) {
+           _target->set_pending_jvmti_unmount_event(true);
+         }
+       }
+     }
+   }
+   void set_preempt_result(int res) { _preempt_result = res; }
+   bool failed() { return _failed; }
+ };
+ 
+ static bool is_safe_vthread_to_preempt_for_jvmti(JavaThread* target, oop vthread) {
+   if (target->is_in_any_VTMS_transition()) {
+     // We caught target at the end of a mount transition (is_in_VTMS_transition()) or at the
+     // beginning or end of a temporary switch to carrier thread (is_in_tmp_VTMS_transition()).
+     return false;
+   }
+   return true;
+ }
+ #endif // INCLUDE_JVMTI
+ 
+ static bool is_safe_vthread_to_preempt(JavaThread* target, oop vthread) {
+   if (!java_lang_VirtualThread::is_instance(vthread) ||                               // inside tmp transition
+       java_lang_VirtualThread::state(vthread) != java_lang_VirtualThread::RUNNING) {  // inside transition
+     return false;
+   }
+   return JVMTI_ONLY(is_safe_vthread_to_preempt_for_jvmti(target, vthread)) NOT_JVMTI(true);
+ }
+ 
+ typedef int (*FreezeContFnT)(JavaThread*, intptr_t*);
+ 
+ static void verify_preempt_preconditions(JavaThread* target, oop continuation) {
+   assert(target == JavaThread::current(), "no support for external preemption");
+   assert(target->has_last_Java_frame(), "");
+   assert(!target->preempting(), "");
+   assert(target->last_continuation() != nullptr, "");
+   assert(target->last_continuation()->cont_oop(target) == continuation, "");
+   assert(Continuation::continuation_scope(continuation) == java_lang_VirtualThread::vthread_scope(), "");
+   assert(!target->has_pending_exception(), "");
+   assert(!target->is_suspended() JVMTI_ONLY(|| target->is_disable_suspend()) || target->obj_locker_count() > 0, "");
+ }
+ 
+ int Continuation::try_preempt(JavaThread* target, oop continuation, preempt_kind preempt_kind) {
+   verify_preempt_preconditions(target, continuation);
+ 
+   if (LockingMode == LM_LEGACY) {
+     return freeze_unsupported;
+   }
+ 
+   if (preempt_kind == freeze_on_monitorenter && !target->is_on_monitorenter()) {
+     // ObjectLocker or jni_enter case. We can't preempt in these cases.
+     return freeze_pinned_native;
+   }
+ 
+   if (!is_safe_vthread_to_preempt(target, target->vthread())) {
+     return freeze_pinned_native;
+   }
+ 
+   JVMTI_ONLY(JvmtiUnmountBeginMark jubm(target);)
+   JVMTI_ONLY(if (jubm.failed()) return freeze_pinned_native;)
+   target->set_preempting(true);
+   int res = CAST_TO_FN_PTR(FreezeContFnT, freeze_preempt_entry())(target, target->last_Java_sp());
+   log_trace(continuations, preempt)("try_preempt: %d", res);
+   JVMTI_ONLY(jubm.set_preempt_result(res);)
+   if (res != freeze_ok) {
+     target->set_preempting(false);
+   }
+   return res;
+ }
+ #endif // LOOM_MONITOR_SUPPORT
+ 
  #ifndef PRODUCT
  static jlong java_tid(JavaThread* thread) {
    return java_lang_Thread::thread_id(thread->threadObj());
  }
  #endif
< prev index next >