< prev index next >

src/hotspot/share/runtime/synchronizer.cpp

Print this page
@@ -359,11 +359,11 @@
      if (LockingMode == LM_LIGHTWEIGHT && mon == nullptr) {
        // Racing with inflation/deflation go slow path
        return false;
      }
      assert(mon->object() == oop(obj), "invariant");
-     if (mon->owner() != current) return false;  // slow-path for IMS exception
+     if (!mon->is_owner(current)) return false;  // slow-path for IMS exception
  
      if (mon->first_waiter() != nullptr) {
        // We have one or more waiters. Since this is an inflated monitor
        // that we own, we can transfer one or more threads from the waitset
        // to the entrylist here and now, avoiding the slow-path.

@@ -422,18 +422,17 @@
      // the ObjectMonitor busy by setting the owner below. If we detect
      // that race we just bail out to the slow-path here.
      if (m->object_peek() == nullptr) {
        return false;
      }
-     JavaThread* const owner = static_cast<JavaThread*>(m->owner_raw());
  
      // Lock contention and Transactional Lock Elision (TLE) diagnostics
      // and observability
      // Case: light contention possibly amenable to TLE
      // Case: TLE inimical operations such as nested/recursive synchronization
  
-     if (owner == current) {
+     if (m->is_owner(current)) {
        m->_recursions++;
        current->inc_held_monitor_count();
        return true;
      }
  

@@ -446,11 +445,11 @@
      // stack-locking in the object's header, the second check is for
      // recursive stack-locking in the displaced header in the BasicLock,
      // and last are the inflated Java Monitor (ObjectMonitor) checks.
      lock->set_displaced_header(markWord::unused_mark());
  
-     if (owner == nullptr && m->try_set_owner_from(nullptr, current) == nullptr) {
+     if (!m->has_owner() && m->try_set_owner(current)) {
        assert(m->_recursions == 0, "invariant");
        current->inc_held_monitor_count();
        return true;
      }
    }

@@ -664,10 +663,14 @@
  
  // -----------------------------------------------------------------------------
  // JNI locks on java objects
  // NOTE: must use heavy weight monitor to handle jni monitor enter
  void ObjectSynchronizer::jni_enter(Handle obj, JavaThread* current) {
+   // Top native frames in the stack will not be seen if we attempt
+   // preemption, since we start walking from the last Java anchor.
+   NoPreemptMark npm(current);
+ 
    if (obj->klass()->is_value_based()) {
      handle_sync_on_value_based_class(obj, current);
    }
  
    // the current locking is from JNI instead of Java code

@@ -715,11 +718,11 @@
  }
  
  // -----------------------------------------------------------------------------
  // Internal VM locks on java objects
  // standard constructor, allows locking failures
- ObjectLocker::ObjectLocker(Handle obj, JavaThread* thread) {
+ ObjectLocker::ObjectLocker(Handle obj, JavaThread* thread) : _npm(thread) {
    _thread = thread;
    _thread->check_for_valid_safepoint_state();
    _obj = obj;
  
    if (_obj() != nullptr) {

@@ -1163,11 +1166,11 @@
    markWord mark = read_stable_mark(obj);
  
    if (LockingMode == LM_LEGACY && mark.has_locker()) {
      // stack-locked so header points into owner's stack.
      // owning_thread_from_monitor_owner() may also return null here:
-     return Threads::owning_thread_from_monitor_owner(t_list, (address) mark.locker());
+     return Threads::owning_thread_from_stacklock(t_list, (address) mark.locker());
    }
  
    if (LockingMode == LM_LIGHTWEIGHT && mark.is_fast_locked()) {
      // fast-locked so get owner from the object.
      // owning_thread_from_object() may also return null here:

@@ -1227,28 +1230,28 @@
      // target thread is suspended or when the target thread is
      // operating on itself. The current closures in use today are
      // only interested in an owned ObjectMonitor and ownership
      // cannot be dropped under the calling contexts so the
      // ObjectMonitor cannot be async deflated.
-     if (monitor->has_owner() && filter(monitor->owner_raw())) {
+     if (monitor->has_owner() && filter(monitor)) {
        assert(!monitor->is_being_async_deflated(), "Owned monitors should not be deflating");
  
        closure->do_monitor(monitor);
      }
    });
  }
  
  // Iterate ObjectMonitors where the owner == thread; this does NOT include
  // ObjectMonitors where owner is set to a stack-lock address in thread.
  void ObjectSynchronizer::owned_monitors_iterate(MonitorClosure* closure, JavaThread* thread) {
-   auto thread_filter = [&](void* owner) { return owner == thread; };
+   auto thread_filter = [&](ObjectMonitor* monitor) { return monitor->is_owner(thread); };
    return owned_monitors_iterate_filtered(closure, thread_filter);
  }
  
  // Iterate ObjectMonitors owned by any thread.
  void ObjectSynchronizer::owned_monitors_iterate(MonitorClosure* closure) {
-   auto all_filter = [&](void* owner) { return true; };
+   auto all_filter = [&](ObjectMonitor* monitor) { return true; };
    return owned_monitors_iterate_filtered(closure, all_filter);
  }
  
  static bool monitors_used_above_threshold(MonitorList* list) {
    if (MonitorUsedDeflationThreshold == 0) {  // disabled case is easy

@@ -1416,38 +1419,52 @@
  }
  
  ObjectMonitor* ObjectSynchronizer::inflate(Thread* current, oop obj, const InflateCause cause) {
    assert(current == Thread::current(), "must be");
    assert(LockingMode != LM_LIGHTWEIGHT, "only inflate through enter");
-   return inflate_impl(obj, cause);
+   return inflate_impl(current->is_Java_thread() ? JavaThread::cast(current) : nullptr, obj, cause);
  }
  
  ObjectMonitor* ObjectSynchronizer::inflate_for(JavaThread* thread, oop obj, const InflateCause cause) {
    assert(thread == Thread::current() || thread->is_obj_deopt_suspend(), "must be");
    assert(LockingMode != LM_LIGHTWEIGHT, "LM_LIGHTWEIGHT cannot use inflate_for");
-   return inflate_impl(obj, cause);
+   return inflate_impl(thread, obj, cause);
  }
  
- ObjectMonitor* ObjectSynchronizer::inflate_impl(oop object, const InflateCause cause) {
+ ObjectMonitor* ObjectSynchronizer::inflate_impl(JavaThread* inflating_thread, oop object, const InflateCause cause) {
+   // The JavaThread* inflating_thread requires that the inflating_thread == Thread::current() or
+   // is suspended throughout the call by some other mechanism.
+   // The thread might be nullptr when called from a non JavaThread. (As may still be
+   // the case from FastHashCode). However it is only important for correctness that the
+   // thread is set when called from ObjectSynchronizer::enter from the owning thread,
+   // ObjectSynchronizer::enter_for from any thread, or ObjectSynchronizer::exit.
    assert(LockingMode != LM_LIGHTWEIGHT, "LM_LIGHTWEIGHT cannot use inflate_impl");
    EventJavaMonitorInflate event;
  
    for (;;) {
      const markWord mark = object->mark_acquire();
  
      // The mark can be in one of the following states:
-     // *  inflated     - Just return it.
+     // *  inflated     - If the ObjectMonitor owner is anonymous and the
+     //                   inflating_thread owns the object lock, then we
+     //                   make the inflating_thread the ObjectMonitor owner.
      // *  stack-locked - Coerce it to inflated from stack-locked.
      // *  INFLATING    - Busy wait for conversion from stack-locked to
      //                   inflated.
      // *  unlocked     - Aggressively inflate the object.
  
      // CASE: inflated
      if (mark.has_monitor()) {
        ObjectMonitor* inf = mark.monitor();
        markWord dmw = inf->header();
        assert(dmw.is_neutral(), "invariant: header=" INTPTR_FORMAT, dmw.value());
+       if (inf->is_owner_anonymous() && inflating_thread != nullptr) {
+         assert(LockingMode == LM_LEGACY, "invariant");
+         if (inflating_thread->is_lock_owned((address)inf->stack_locker())) {
+           inf->set_owner_from_BasicLock(inflating_thread);
+         }
+       }
        return inf;
      }
  
      // CASE: inflation in progress - inflating over a stack-lock.
      // Some other thread is converting from stack-locked to inflated.

@@ -1520,16 +1537,21 @@
        assert(dmw.is_neutral(), "invariant: header=" INTPTR_FORMAT, dmw.value());
  
        // Setup monitor fields to proper values -- prepare the monitor
        m->set_header(dmw);
  
-       // Optimization: if the mark.locker stack address is associated
-       // with this thread we could simply set m->_owner = current.
        // Note that a thread can inflate an object
        // that it has stack-locked -- as might happen in wait() -- directly
        // with CAS.  That is, we can avoid the xchg-nullptr .... ST idiom.
-       m->set_owner_from(nullptr, mark.locker());
+       if (inflating_thread != nullptr && inflating_thread->is_lock_owned((address)mark.locker())) {
+         m->set_owner(inflating_thread);
+       } else {
+         // Use ANONYMOUS_OWNER to indicate that the owner is the BasicLock on the stack,
+         // and set the stack locker field in the monitor.
+         m->set_stack_locker(mark.locker());
+         m->set_owner_anonymous();  // second
+       }
        // TODO-FIXME: assert BasicLock->dhw != 0.
  
        // Must preserve store ordering. The monitor state must
        // be stable at the time of publishing the monitor address.
        guarantee(object->mark() == markWord::INFLATING(), "invariant");

@@ -2048,11 +2070,11 @@
        if (is_interesting(monitor)) {
          const oop obj = monitor->object_peek();
          const intptr_t hash = UseObjectMonitorTable ? monitor->hash() : monitor->header().hash();
          ResourceMark rm;
          out->print(INTPTR_FORMAT "  %d%d%d  " INTPTR_FORMAT "  %s", p2i(monitor),
-                    monitor->is_busy(), hash != 0, monitor->owner() != nullptr,
+                    monitor->is_busy(), hash != 0, monitor->has_owner(),
                     p2i(obj), obj == nullptr ? "" : obj->klass()->external_name());
          if (monitor->is_busy()) {
            out->print(" (%s)", monitor->is_busy_to_string(&ss));
            ss.reset();
          }
< prev index next >