< prev index next >

src/hotspot/share/runtime/synchronizer.cpp

Print this page
*** 310,10 ***
--- 310,26 ---
  bool volatile ObjectSynchronizer::_is_final_audit = false;
  jlong ObjectSynchronizer::_last_async_deflation_time_ns = 0;
  static uintx _no_progress_cnt = 0;
  static bool _no_progress_skip_increment = false;
  
+ // These checks are required for wait, notify and exit to avoid inflating the monitor to
+ // find out this inline type object cannot be locked.
+ #define CHECK_THROW_NOSYNC_IMSE(obj)  \
+   if (EnableValhalla && (obj)->mark().is_inline_type()) {  \
+     JavaThread* THREAD = current;           \
+     ResourceMark rm(THREAD);                \
+     THROW_MSG(vmSymbols::java_lang_IllegalMonitorStateException(), obj->klass()->external_name()); \
+   }
+ 
+ #define CHECK_THROW_NOSYNC_IMSE_0(obj)  \
+   if (EnableValhalla && (obj)->mark().is_inline_type()) {  \
+     JavaThread* THREAD = current;             \
+     ResourceMark rm(THREAD);                  \
+     THROW_MSG_0(vmSymbols::java_lang_IllegalMonitorStateException(), obj->klass()->external_name()); \
+   }
+ 
  // =====================> Quick functions
  
  // The quick_* forms are special fast-path variants used to improve
  // performance.  In the simplest case, a "quick_*" implementation could
  // simply return false, in which case the caller will perform the necessary

*** 336,10 ***
--- 352,11 ---
  
  bool ObjectSynchronizer::quick_notify(oopDesc* obj, JavaThread* current, bool all) {
    assert(current->thread_state() == _thread_in_Java, "invariant");
    NoSafepointVerifier nsv;
    if (obj == nullptr) return false;  // slow-path for invalid obj
+   assert(!EnableValhalla || !obj->klass()->is_inline_klass(), "monitor op on inline type");
    const markWord mark = obj->mark();
  
    if (LockingMode == LM_LIGHTWEIGHT) {
      if (mark.is_fast_locked() && current->lock_stack().contains(cast_to_oop(obj))) {
        // Degenerate notify

*** 400,10 ***
--- 417,11 ---
  // Note that we can't safely call AsyncPrintJavaStack() from within
  // quick_enter() as our thread state remains _in_Java.
  
  bool ObjectSynchronizer::quick_enter_legacy(oop obj, BasicLock* lock, JavaThread* current) {
    assert(current->thread_state() == _thread_in_Java, "invariant");
+   assert(!EnableValhalla || !obj->klass()->is_inline_klass(), "monitor op on inline type");
  
    if (useHeavyMonitors()) {
      return false;  // Slow path
    }
  

*** 520,10 ***
--- 538,11 ---
  void ObjectSynchronizer::enter_for(Handle obj, BasicLock* lock, JavaThread* locking_thread) {
    // When called with locking_thread != Thread::current() some mechanism must synchronize
    // the locking_thread with respect to the current thread. Currently only used when
    // deoptimizing and re-locking locks. See Deoptimization::relock_objects
    assert(locking_thread == Thread::current() || locking_thread->is_obj_deopt_suspend(), "must be");
+   assert(!EnableValhalla || !obj->klass()->is_inline_klass(), "JITed code should never have locked an instance of a value class");
  
    if (LockingMode == LM_LIGHTWEIGHT) {
      return LightweightSynchronizer::enter_for(obj, lock, locking_thread);
    }
  

*** 542,10 ***
--- 561,11 ---
      }
    }
  }
  
  void ObjectSynchronizer::enter_legacy(Handle obj, BasicLock* lock, JavaThread* current) {
+   assert(!EnableValhalla || !obj->klass()->is_inline_klass(), "This method should never be called on an instance of an inline class");
    if (!enter_fast_impl(obj, lock, current)) {
      // Inflated ObjectMonitor::enter is required
  
      // An async deflation can race after the inflate() call and before
      // enter() can make the ObjectMonitor busy. enter() returns false if

*** 561,10 ***
--- 581,11 ---
  
  // The interpreter and compiler assembly code tries to lock using the fast path
  // of this algorithm. Make sure to update that code if the following function is
  // changed. The implementation is extremely sensitive to race condition. Be careful.
  bool ObjectSynchronizer::enter_fast_impl(Handle obj, BasicLock* lock, JavaThread* locking_thread) {
+   guarantee(!EnableValhalla || !obj->klass()->is_inline_klass(), "Attempt to inflate inline type");
    assert(LockingMode != LM_LIGHTWEIGHT, "Use LightweightSynchronizer");
  
    if (obj->klass()->is_value_based()) {
      handle_sync_on_value_based_class(obj, locking_thread);
    }

*** 608,10 ***
--- 629,13 ---
  void ObjectSynchronizer::exit_legacy(oop object, BasicLock* lock, JavaThread* current) {
    assert(LockingMode != LM_LIGHTWEIGHT, "Use LightweightSynchronizer");
  
    if (!useHeavyMonitors()) {
      markWord mark = object->mark();
+     if (EnableValhalla && mark.is_inline_type()) {
+       return;
+     }
      if (LockingMode == LM_LEGACY) {
        markWord dhw = lock->displaced_header();
        if (dhw.value() == 0) {
          // If the displaced header is null, then this exit matches up with
          // a recursive enter. No real work to do here except for diagnostics.

*** 664,14 ***
--- 688,25 ---
  
  // -----------------------------------------------------------------------------
  // JNI locks on java objects
  // NOTE: must use heavy weight monitor to handle jni monitor enter
  void ObjectSynchronizer::jni_enter(Handle obj, JavaThread* current) {
+   JavaThread* THREAD = current;
    if (obj->klass()->is_value_based()) {
      handle_sync_on_value_based_class(obj, current);
    }
  
+   if (EnableValhalla && obj->klass()->is_inline_klass()) {
+     ResourceMark rm(THREAD);
+     const char* desc = "Cannot synchronize on an instance of value class ";
+     const char* className = obj->klass()->external_name();
+     size_t msglen = strlen(desc) + strlen(className) + 1;
+     char* message = NEW_RESOURCE_ARRAY(char, msglen);
+     assert(message != nullptr, "NEW_RESOURCE_ARRAY should have called vm_exit_out_of_memory and not return nullptr");
+     THROW_MSG(vmSymbols::java_lang_IdentityException(), className);
+   }
+ 
    // the current locking is from JNI instead of Java code
    current->set_current_pending_monitor_is_from_java(false);
    // An async deflation can race after the inflate() call and before
    // enter() can make the ObjectMonitor busy. enter() returns false if
    // we have lost the race to async deflation and we simply try again.

*** 694,10 ***
--- 729,11 ---
  }
  
  // NOTE: must use heavy weight monitor to handle jni monitor exit
  void ObjectSynchronizer::jni_exit(oop obj, TRAPS) {
    JavaThread* current = THREAD;
+   CHECK_THROW_NOSYNC_IMSE(obj);
  
    ObjectMonitor* monitor;
    if (LockingMode == LM_LIGHTWEIGHT) {
      monitor = LightweightSynchronizer::inflate_locked_or_imse(obj, inflate_cause_jni_exit, CHECK);
    } else {

*** 738,10 ***
--- 774,11 ---
  //  Wait/Notify/NotifyAll
  // NOTE: must use heavy weight monitor to handle wait()
  
  int ObjectSynchronizer::wait(Handle obj, jlong millis, TRAPS) {
    JavaThread* current = THREAD;
+   CHECK_THROW_NOSYNC_IMSE_0(obj);
    if (millis < 0) {
      THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(), "timeout value is negative");
    }
  
    ObjectMonitor* monitor;

*** 780,10 ***
--- 817,11 ---
  }
  
  
  void ObjectSynchronizer::notify(Handle obj, TRAPS) {
    JavaThread* current = THREAD;
+   CHECK_THROW_NOSYNC_IMSE(obj);
  
    markWord mark = obj->mark();
    if (LockingMode == LM_LIGHTWEIGHT) {
      if ((mark.is_fast_locked() && current->lock_stack().contains(obj()))) {
        // Not inflated so there can't be any waiters to notify.

*** 808,10 ***
--- 846,11 ---
  }
  
  // NOTE: see comment of notify()
  void ObjectSynchronizer::notifyall(Handle obj, TRAPS) {
    JavaThread* current = THREAD;
+   CHECK_THROW_NOSYNC_IMSE(obj);
  
    markWord mark = obj->mark();
    if (LockingMode == LM_LIGHTWEIGHT) {
      if ((mark.is_fast_locked() && current->lock_stack().contains(obj()))) {
        // Not inflated so there can't be any waiters to notify.

*** 989,10 ***
--- 1028,14 ---
      }
    }
  }
  
  intptr_t ObjectSynchronizer::FastHashCode(Thread* current, oop obj) {
+   if (EnableValhalla && obj->klass()->is_inline_klass()) {
+     // VM should be calling bootstrap method
+     ShouldNotReachHere();
+   }
    if (UseObjectMonitorTable) {
      // Since the monitor isn't in the object header, the hash can simply be
      // installed in the object header.
      return install_hash_code(current, obj);
    }

*** 1115,10 ***
--- 1158,13 ---
    }
  }
  
  bool ObjectSynchronizer::current_thread_holds_lock(JavaThread* current,
                                                     Handle h_obj) {
+   if (EnableValhalla && h_obj->mark().is_inline_type()) {
+     return false;
+   }
    assert(current == JavaThread::current(), "Can only be called on current thread");
    oop obj = h_obj();
  
    markWord mark = read_stable_mark(obj);
  

*** 1426,10 ***
--- 1472,13 ---
    assert(LockingMode != LM_LIGHTWEIGHT, "LM_LIGHTWEIGHT cannot use inflate_for");
    return inflate_impl(obj, cause);
  }
  
  ObjectMonitor* ObjectSynchronizer::inflate_impl(oop object, const InflateCause cause) {
+   if (EnableValhalla) {
+     guarantee(!object->klass()->is_inline_klass(), "Attempt to inflate inline type");
+   }
    assert(LockingMode != LM_LIGHTWEIGHT, "LM_LIGHTWEIGHT cannot use inflate_impl");
    EventJavaMonitorInflate event;
  
    for (;;) {
      const markWord mark = object->mark_acquire();
< prev index next >