< prev index next >

src/hotspot/share/runtime/synchronizer.cpp

Print this page
*** 1,7 ***
  /*
!  * Copyright (c) 1998, 2023, Oracle and/or its affiliates. All rights reserved.
   * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   *
   * This code is free software; you can redistribute it and/or modify it
   * under the terms of the GNU General Public License version 2 only, as
   * published by the Free Software Foundation.
--- 1,7 ---
  /*
!  * Copyright (c) 1998, 2024, Oracle and/or its affiliates. All rights reserved.
   * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   *
   * This code is free software; you can redistribute it and/or modify it
   * under the terms of the GNU General Public License version 2 only, as
   * published by the Free Software Foundation.

*** 34,10 ***
--- 34,11 ---
  #include "memory/universe.hpp"
  #include "oops/markWord.hpp"
  #include "oops/oop.inline.hpp"
  #include "runtime/atomic.hpp"
  #include "runtime/frame.inline.hpp"
+ #include "runtime/globals.hpp"
  #include "runtime/handles.inline.hpp"
  #include "runtime/handshake.hpp"
  #include "runtime/interfaceSupport.inline.hpp"
  #include "runtime/javaThread.hpp"
  #include "runtime/lockStack.inline.hpp"

*** 58,10 ***
--- 59,11 ---
  #include "runtime/vframe.hpp"
  #include "runtime/vmThread.hpp"
  #include "utilities/align.hpp"
  #include "utilities/dtrace.hpp"
  #include "utilities/events.hpp"
+ #include "utilities/globalDefinitions.hpp"
  #include "utilities/linkedlist.hpp"
  #include "utilities/preserveException.hpp"
  
  class ObjectMonitorsHashtable::PtrList :
    public LinkedListImpl<ObjectMonitor*,

*** 383,10 ***
--- 385,23 ---
  
    if (obj->klass()->is_value_based()) {
      return false;
    }
  
+   if (LockingMode == LM_LIGHTWEIGHT) {
+     LockStack& lock_stack = current->lock_stack();
+     if (lock_stack.is_full()) {
+       // Always go into runtime if the lock stack is full.
+       return false;
+     }
+     if (lock_stack.try_recursive_enter(obj)) {
+       // Recursive lock successful.
+       current->inc_held_monitor_count();
+       return true;
+     }
+   }
+ 
    const markWord mark = obj->mark();
  
    if (mark.has_monitor()) {
      ObjectMonitor* const m = mark.monitor();
      // An async deflation or GC can race us before we manage to make

*** 436,12 ***
  
    return false;        // revert to slow-path
  }
  
  // Handle notifications when synchronizing on value based classes
! void ObjectSynchronizer::handle_sync_on_value_based_class(Handle obj, JavaThread* current) {
!   frame last_frame = current->last_frame();
    bool bcp_was_adjusted = false;
    // Don't decrement bcp if it points to the frame's first instruction.  This happens when
    // handle_sync_on_value_based_class() is called because of a synchronized method.  There
    // is no actual monitorenter instruction in the byte code in this case.
    if (last_frame.is_interpreted_frame() &&
--- 451,13 ---
  
    return false;        // revert to slow-path
  }
  
  // Handle notifications when synchronizing on value based classes
! void ObjectSynchronizer::handle_sync_on_value_based_class(Handle obj, JavaThread* locking_thread) {
!   assert(locking_thread == Thread::current() || locking_thread->is_obj_deopt_suspend(), "must be");
+   frame last_frame = locking_thread->last_frame();
    bool bcp_was_adjusted = false;
    // Don't decrement bcp if it points to the frame's first instruction.  This happens when
    // handle_sync_on_value_based_class() is called because of a synchronized method.  There
    // is no actual monitorenter instruction in the byte code in this case.
    if (last_frame.is_interpreted_frame() &&

*** 450,28 ***
      last_frame.interpreter_frame_set_bcp(last_frame.interpreter_frame_bcp() - 1);
      bcp_was_adjusted = true;
    }
  
    if (DiagnoseSyncOnValueBasedClasses == FATAL_EXIT) {
!     ResourceMark rm(current);
      stringStream ss;
!     current->print_active_stack_on(&ss);
      char* base = (char*)strstr(ss.base(), "at");
      char* newline = (char*)strchr(ss.base(), '\n');
      if (newline != nullptr) {
        *newline = '\0';
      }
      fatal("Synchronizing on object " INTPTR_FORMAT " of klass %s %s", p2i(obj()), obj->klass()->external_name(), base);
    } else {
      assert(DiagnoseSyncOnValueBasedClasses == LOG_WARNING, "invalid value for DiagnoseSyncOnValueBasedClasses");
!     ResourceMark rm(current);
      Log(valuebasedclasses) vblog;
  
      vblog.info("Synchronizing on object " INTPTR_FORMAT " of klass %s", p2i(obj()), obj->klass()->external_name());
!     if (current->has_last_Java_frame()) {
        LogStream info_stream(vblog.info());
!       current->print_active_stack_on(&info_stream);
      } else {
        vblog.info("Cannot find the last Java frame");
      }
  
      EventSyncOnValueBasedClass event;
--- 466,28 ---
      last_frame.interpreter_frame_set_bcp(last_frame.interpreter_frame_bcp() - 1);
      bcp_was_adjusted = true;
    }
  
    if (DiagnoseSyncOnValueBasedClasses == FATAL_EXIT) {
!     ResourceMark rm;
      stringStream ss;
!     locking_thread->print_active_stack_on(&ss);
      char* base = (char*)strstr(ss.base(), "at");
      char* newline = (char*)strchr(ss.base(), '\n');
      if (newline != nullptr) {
        *newline = '\0';
      }
      fatal("Synchronizing on object " INTPTR_FORMAT " of klass %s %s", p2i(obj()), obj->klass()->external_name(), base);
    } else {
      assert(DiagnoseSyncOnValueBasedClasses == LOG_WARNING, "invalid value for DiagnoseSyncOnValueBasedClasses");
!     ResourceMark rm;
      Log(valuebasedclasses) vblog;
  
      vblog.info("Synchronizing on object " INTPTR_FORMAT " of klass %s", p2i(obj()), obj->klass()->external_name());
!     if (locking_thread->has_last_Java_frame()) {
        LogStream info_stream(vblog.info());
!       locking_thread->print_active_stack_on(&info_stream);
      } else {
        vblog.info("Cannot find the last Java frame");
      }
  
      EventSyncOnValueBasedClass event;

*** 494,104 ***
  #endif
  }
  
  // -----------------------------------------------------------------------------
  // Monitor Enter/Exit
  // 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.
  
- void ObjectSynchronizer::enter(Handle obj, BasicLock* lock, JavaThread* current) {
    if (obj->klass()->is_value_based()) {
!     handle_sync_on_value_based_class(obj, current);
    }
  
!   current->inc_held_monitor_count();
  
    if (!useHeavyMonitors()) {
      if (LockingMode == LM_LIGHTWEIGHT) {
        // Fast-locking does not use the 'lock' argument.
!       LockStack& lock_stack = current->lock_stack();
!       if (lock_stack.can_push()) {
!         markWord mark = obj()->mark_acquire();
!         if (mark.is_neutral()) {
!           assert(!lock_stack.contains(obj()), "thread must not already hold the lock");
!           // Try to swing into 'fast-locked' state.
!           markWord locked_mark = mark.set_fast_locked();
!           markWord old_mark = obj()->cas_set_mark(locked_mark, mark);
!           if (old_mark == mark) {
!             // Successfully fast-locked, push object to lock-stack and return.
!             lock_stack.push(obj());
!             return;
!           }
          }
        }
!       // All other paths fall-through to inflate-enter.
      } else if (LockingMode == LM_LEGACY) {
        markWord mark = obj->mark();
        if (mark.is_neutral()) {
          // Anticipate successful CAS -- the ST of the displaced mark must
          // be visible <= the ST performed by the CAS.
          lock->set_displaced_header(mark);
          if (mark == obj()->cas_set_mark(markWord::from_pointer(lock), mark)) {
!           return;
          }
-         // Fall through to inflate() ...
        } else if (mark.has_locker() &&
!                  current->is_lock_owned((address) mark.locker())) {
          assert(lock != mark.locker(), "must not re-lock the same lock");
          assert(lock != (BasicLock*) obj->mark().value(), "don't relock with same BasicLock");
          lock->set_displaced_header(markWord::from_pointer(nullptr));
!         return;
        }
  
        // The object header will never be displaced to this lock,
        // so it does not matter what the value is, except that it
        // must be non-zero to avoid looking like a re-entrant lock,
        // and must not look locked either.
        lock->set_displaced_header(markWord::unused_mark());
      }
    } else if (VerifyHeavyMonitors) {
      guarantee((obj->mark().value() & markWord::lock_mask_in_place) != markWord::locked_value, "must not be lightweight/stack-locked");
    }
  
!   // 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.
-   while (true) {
-     ObjectMonitor* monitor = inflate(current, obj(), inflate_cause_monitor_enter);
-     if (monitor->enter(current)) {
-       return;
-     }
-   }
  }
  
  void ObjectSynchronizer::exit(oop object, BasicLock* lock, JavaThread* current) {
    current->dec_held_monitor_count();
  
    if (!useHeavyMonitors()) {
      markWord mark = object->mark();
      if (LockingMode == LM_LIGHTWEIGHT) {
        // Fast-locking does not use the 'lock' argument.
!       if (mark.is_fast_locked()) {
!         markWord unlocked_mark = mark.set_unlocked();
!         markWord old_mark = object->cas_set_mark(unlocked_mark, mark);
-         if (old_mark != mark) {
-           // Another thread won the CAS, it must have inflated the monitor.
-           // It can only have installed an anonymously locked monitor at this point.
-           // Fetch that monitor, set owner correctly to this thread, and
-           // exit it (allowing waiting threads to enter).
-           assert(old_mark.has_monitor(), "must have monitor");
-           ObjectMonitor* monitor = old_mark.monitor();
-           assert(monitor->is_owner_anonymous(), "must be anonymous owner");
-           monitor->set_owner_from_anonymous(current);
-           monitor->exit(current);
-         }
-         LockStack& lock_stack = current->lock_stack();
-         lock_stack.remove(object);
          return;
        }
      } else 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.
--- 510,178 ---
  #endif
  }
  
  // -----------------------------------------------------------------------------
  // Monitor Enter/Exit
+ 
+ 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");
+   if (!enter_fast_impl(obj, lock, locking_thread)) {
+     // Inflated ObjectMonitor::enter_for is required
+ 
+     // An async deflation can race after the inflate_for() call and before
+     // enter_for() can make the ObjectMonitor busy. enter_for() returns false
+     // if we have lost the race to async deflation and we simply try again.
+     while (true) {
+       ObjectMonitor* monitor = inflate_for(locking_thread, obj(), inflate_cause_monitor_enter);
+       if (monitor->enter_for(locking_thread)) {
+         return;
+       }
+       assert(monitor->is_being_async_deflated(), "must be");
+     }
+   }
+ }
+ 
+ void ObjectSynchronizer::enter(Handle obj, BasicLock* lock, JavaThread* current) {
+   assert(current == Thread::current(), "must be");
+   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
+     // we have lost the race to async deflation and we simply try again.
+     while (true) {
+       ObjectMonitor* monitor = inflate(current, obj(), inflate_cause_monitor_enter);
+       if (monitor->enter(current)) {
+         return;
+       }
+     }
+   }
+ }
+ 
  // 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) {
  
    if (obj->klass()->is_value_based()) {
!     handle_sync_on_value_based_class(obj, locking_thread);
    }
  
!   locking_thread->inc_held_monitor_count();
  
    if (!useHeavyMonitors()) {
      if (LockingMode == LM_LIGHTWEIGHT) {
        // Fast-locking does not use the 'lock' argument.
!       LockStack& lock_stack = locking_thread->lock_stack();
!       if (lock_stack.is_full()) {
!         // We unconditionally make room on the lock stack by inflating
!         // the least recently locked object on the lock stack.
! 
!         // About the choice to inflate least recently locked object.
!         // First we must chose to inflate a lock, either some lock on
!         // the lock-stack or the lock that is currently being entered
!         // (which may or may not be on the lock-stack).
!         // Second the best lock to inflate is a lock which is entered
!         // in a control flow where there are only a very few locks being
!         // used, as the costly part of inflated locking is inflation,
!         // not locking. But this property is entirely program dependent.
+         // Third inflating the lock currently being entered on when it
+         // is not present on the lock-stack will result in a still full
+         // lock-stack. This creates a scenario where every deeper nested
+         // monitorenter must call into the runtime.
+         // The rational here is as follows:
+         // Because we cannot (currently) figure out the second, and want
+         // to avoid the third, we inflate a lock on the lock-stack.
+         // The least recently locked lock is chosen as it is the lock
+         // with the longest critical section.
+ 
+         log_info(monitorinflation)("LockStack capacity exceeded, inflating.");
+         ObjectMonitor* monitor = inflate_for(locking_thread, lock_stack.bottom(), inflate_cause_vm_internal);
+         assert(monitor->owner() == Thread::current(), "must be owner=" PTR_FORMAT " current=" PTR_FORMAT " mark=" PTR_FORMAT,
+                p2i(monitor->owner()), p2i(Thread::current()), monitor->object()->mark_acquire().value());
+         assert(!lock_stack.is_full(), "must have made room here");
+       }
+ 
+       markWord mark = obj()->mark_acquire();
+       while (mark.is_neutral()) {
+         // Retry until a lock state change has been observed. cas_set_mark() may collide with non lock bits modifications.
+         // Try to swing into 'fast-locked' state.
+         assert(!lock_stack.contains(obj()), "thread must not already hold the lock");
+         const markWord locked_mark = mark.set_fast_locked();
+         const markWord old_mark = obj()->cas_set_mark(locked_mark, mark);
+         if (old_mark == mark) {
+           // Successfully fast-locked, push object to lock-stack and return.
+           lock_stack.push(obj());
+           return true;
          }
+         mark = old_mark;
        }
! 
+       if (mark.is_fast_locked() && lock_stack.try_recursive_enter(obj())) {
+         // Recursive lock successful.
+         return true;
+       }
+ 
+       // Failed to fast lock.
+       return false;
      } else if (LockingMode == LM_LEGACY) {
        markWord mark = obj->mark();
        if (mark.is_neutral()) {
          // Anticipate successful CAS -- the ST of the displaced mark must
          // be visible <= the ST performed by the CAS.
          lock->set_displaced_header(mark);
          if (mark == obj()->cas_set_mark(markWord::from_pointer(lock), mark)) {
!           return true;
          }
        } else if (mark.has_locker() &&
!                  locking_thread->is_lock_owned((address) mark.locker())) {
          assert(lock != mark.locker(), "must not re-lock the same lock");
          assert(lock != (BasicLock*) obj->mark().value(), "don't relock with same BasicLock");
          lock->set_displaced_header(markWord::from_pointer(nullptr));
!         return true;
        }
  
        // The object header will never be displaced to this lock,
        // so it does not matter what the value is, except that it
        // must be non-zero to avoid looking like a re-entrant lock,
        // and must not look locked either.
        lock->set_displaced_header(markWord::unused_mark());
+ 
+       // Failed to fast lock.
+       return false;
      }
    } else if (VerifyHeavyMonitors) {
      guarantee((obj->mark().value() & markWord::lock_mask_in_place) != markWord::locked_value, "must not be lightweight/stack-locked");
    }
  
!   return false;
  }
  
  void ObjectSynchronizer::exit(oop object, BasicLock* lock, JavaThread* current) {
    current->dec_held_monitor_count();
  
    if (!useHeavyMonitors()) {
      markWord mark = object->mark();
      if (LockingMode == LM_LIGHTWEIGHT) {
        // Fast-locking does not use the 'lock' argument.
!       LockStack& lock_stack = current->lock_stack();
!       if (mark.is_fast_locked() && lock_stack.try_recursive_exit(object)) {
!         // Recursively unlocked.
          return;
        }
+ 
+       if (mark.is_fast_locked() && lock_stack.is_recursive(object)) {
+         // This lock is recursive but is not at the top of the lock stack so we're
+         // doing an unbalanced exit. We have to fall thru to inflation below and
+         // let ObjectMonitor::exit() do the unlock.
+       } else {
+         while (mark.is_fast_locked()) {
+           // Retry until a lock state change has been observed. cas_set_mark() may collide with non lock bits modifications.
+           const markWord unlocked_mark = mark.set_unlocked();
+           const markWord old_mark = object->cas_set_mark(unlocked_mark, mark);
+           if (old_mark == mark) {
+             size_t recursions = lock_stack.remove(object) - 1;
+             assert(recursions == 0, "must not be recursive here");
+             return;
+           }
+           mark = old_mark;
+         }
+       }
      } else 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.

*** 636,17 ***
  
    // We have to take the slow-path of possible inflation and then exit.
    // The ObjectMonitor* can't be async deflated until ownership is
    // dropped inside exit() and the ObjectMonitor* must be !is_busy().
    ObjectMonitor* monitor = inflate(current, object, inflate_cause_vm_internal);
!   if (LockingMode == LM_LIGHTWEIGHT && monitor->is_owner_anonymous()) {
-     // It must be owned by us. Pop lock object from lock stack.
-     LockStack& lock_stack = current->lock_stack();
-     oop popped = lock_stack.pop();
-     assert(popped == object, "must be owned by this thread");
-     monitor->set_owner_from_anonymous(current);
-   }
    monitor->exit(current);
  }
  
  // -----------------------------------------------------------------------------
  // JNI locks on java objects
--- 726,11 ---
  
    // We have to take the slow-path of possible inflation and then exit.
    // The ObjectMonitor* can't be async deflated until ownership is
    // dropped inside exit() and the ObjectMonitor* must be !is_busy().
    ObjectMonitor* monitor = inflate(current, object, inflate_cause_vm_internal);
!   assert(!monitor->is_owner_anonymous(), "must not be");
    monitor->exit(current);
  }
  
  // -----------------------------------------------------------------------------
  // JNI locks on java objects

*** 900,23 ***
      v = (v ^ (v >> 19)) ^ (t ^ (t >> 8));
      current->_hashStateW = v;
      value = v;
    }
  
!   value &= markWord::hash_mask;
    if (value == 0) value = 0xBAD;
    assert(value != markWord::no_hash, "invariant");
    return value;
  }
  
- // Can be called from non JavaThreads (e.g., VMThread) for FastHashCode
- // calculations as part of JVM/TI tagging.
- static bool is_lock_owned(Thread* thread, oop obj) {
-   assert(LockingMode == LM_LIGHTWEIGHT, "only call this with new lightweight locking enabled");
-   return thread->is_Java_thread() ? JavaThread::cast(thread)->lock_stack().contains(obj) : false;
- }
- 
  intptr_t ObjectSynchronizer::FastHashCode(Thread* current, oop obj) {
  
    while (true) {
      ObjectMonitor* monitor = nullptr;
      markWord temp, test;
--- 984,16 ---
      v = (v ^ (v >> 19)) ^ (t ^ (t >> 8));
      current->_hashStateW = v;
      value = v;
    }
  
!   value &= UseCompactObjectHeaders ? markWord::hash_mask_compact : markWord::hash_mask;
    if (value == 0) value = 0xBAD;
    assert(value != markWord::no_hash, "invariant");
    return value;
  }
  
  intptr_t ObjectSynchronizer::FastHashCode(Thread* current, oop obj) {
  
    while (true) {
      ObjectMonitor* monitor = nullptr;
      markWord temp, test;

*** 924,11 ***
      markWord mark = read_stable_mark(obj);
      if (VerifyHeavyMonitors) {
        assert(LockingMode == LM_MONITOR, "+VerifyHeavyMonitors requires LockingMode == 0 (LM_MONITOR)");
        guarantee((obj->mark().value() & markWord::lock_mask_in_place) != markWord::locked_value, "must not be lightweight/stack-locked");
      }
!     if (mark.is_neutral()) {               // if this is a normal header
        hash = mark.hash();
        if (hash != 0) {                     // if it has a hash, just return it
          return hash;
        }
        hash = get_next_hash(current, obj);  // get a new hash
--- 1001,11 ---
      markWord mark = read_stable_mark(obj);
      if (VerifyHeavyMonitors) {
        assert(LockingMode == LM_MONITOR, "+VerifyHeavyMonitors requires LockingMode == 0 (LM_MONITOR)");
        guarantee((obj->mark().value() & markWord::lock_mask_in_place) != markWord::locked_value, "must not be lightweight/stack-locked");
      }
!     if (mark.is_neutral() || (LockingMode == LM_LIGHTWEIGHT && mark.is_fast_locked())) {
        hash = mark.hash();
        if (hash != 0) {                     // if it has a hash, just return it
          return hash;
        }
        hash = get_next_hash(current, obj);  // get a new hash

*** 936,10 ***
--- 1013,14 ---
                                             // try to install the hash
        test = obj->cas_set_mark(temp, mark);
        if (test == mark) {                  // if the hash was installed, return it
          return hash;
        }
+       if (LockingMode == LM_LIGHTWEIGHT) {
+         // CAS failed, retry
+         continue;
+       }
        // Failed to install the hash. It could be that another thread
        // installed the hash just before our attempt or inflation has
        // occurred or... so we fall thru to inflate the monitor for
        // stability and then install the hash.
      } else if (mark.has_monitor()) {

*** 967,17 ***
          }
          return hash;
        }
        // Fall thru so we only have one place that installs the hash in
        // the ObjectMonitor.
-     } else if (LockingMode == LM_LIGHTWEIGHT && mark.is_fast_locked() && is_lock_owned(current, obj)) {
-       // This is a fast-lock owned by the calling thread so use the
-       // markWord from the object.
-       hash = mark.hash();
-       if (hash != 0) {                  // if it has a hash, just return it
-         return hash;
-       }
      } else if (LockingMode == LM_LEGACY && mark.has_locker() && current->is_lock_owned((address)mark.locker())) {
        // This is a stack-lock owned by the calling thread so fetch the
        // displaced markWord from the BasicLock on the stack.
        temp = mark.displaced_mark_helper();
        assert(temp.is_neutral(), "invariant: header=" INTPTR_FORMAT, temp.value());
--- 1048,10 ---

*** 1310,24 ***
      return;
    }
    (void)inflate(Thread::current(), obj, inflate_cause_vm_internal);
  }
  
! ObjectMonitor* ObjectSynchronizer::inflate(Thread* current, oop object,
!                                            const InflateCause cause) {
    EventJavaMonitorInflate event;
  
    for (;;) {
      const markWord mark = object->mark_acquire();
  
      // The mark can be in one of the following states:
      // *  inflated     - Just return if using stack-locking.
      //                   If using fast-locking and the ObjectMonitor owner
!     //                   is anonymous and the current thread owns the
!     //                   object lock, then we make the current thread the
!     //                   ObjectMonitor owner and remove the lock from the
!     //                   current thread's lock stack.
      // *  fast-locked  - Coerce it to inflated from fast-locked.
      // *  stack-locked - Coerce it to inflated from stack-locked.
      // *  INFLATING    - Busy wait for conversion from stack-locked to
      //                   inflated.
      // *  neutral      - Aggressively inflate the object.
--- 1384,44 ---
      return;
    }
    (void)inflate(Thread::current(), obj, inflate_cause_vm_internal);
  }
  
! ObjectMonitor* ObjectSynchronizer::inflate(Thread* current, oop obj, const InflateCause cause) {
!   assert(current == Thread::current(), "must be");
+   if (LockingMode == LM_LIGHTWEIGHT && current->is_Java_thread()) {
+     return inflate_impl(JavaThread::cast(current), obj, cause);
+   }
+   return inflate_impl(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");
+   return inflate_impl(thread, obj, cause);
+ }
+ 
+ ObjectMonitor* ObjectSynchronizer::inflate_impl(JavaThread* inflating_thread, oop object, const InflateCause cause) {
+   // The JavaThread* inflating_thread parameter is only used by LM_LIGHTWEIGHT and requires
+   // that the inflating_thread == Thread::current() or is suspended throughout the call by
+   // some other mechanism.
+   // Even with LM_LIGHTWEIGHT 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 the correctness of the LM_LIGHTWEIGHT algorithm that the thread
+   // is set when called from ObjectSynchronizer::enter from the owning thread,
+   // ObjectSynchronizer::enter_for from any thread, or ObjectSynchronizer::exit.
    EventJavaMonitorInflate event;
  
    for (;;) {
      const markWord mark = object->mark_acquire();
  
      // The mark can be in one of the following states:
      // *  inflated     - Just return if using stack-locking.
      //                   If using fast-locking and the ObjectMonitor owner
!     //                   is anonymous and the inflating_thread owns the
!     //                   object lock, then we make the inflating_thread
!     //                   the ObjectMonitor owner and remove the lock from
!     //                   the inflating_thread's lock stack.
      // *  fast-locked  - Coerce it to inflated from fast-locked.
      // *  stack-locked - Coerce it to inflated from stack-locked.
      // *  INFLATING    - Busy wait for conversion from stack-locked to
      //                   inflated.
      // *  neutral      - Aggressively inflate the object.

*** 1335,13 ***
      // 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 (LockingMode == LM_LIGHTWEIGHT && inf->is_owner_anonymous() && is_lock_owned(current, object)) {
!         inf->set_owner_from_anonymous(current);
!         JavaThread::cast(current)->lock_stack().remove(object);
        }
        return inf;
      }
  
      if (LockingMode != LM_LIGHTWEIGHT) {
--- 1429,15 ---
      // 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 (LockingMode == LM_LIGHTWEIGHT && inf->is_owner_anonymous() &&
!           inflating_thread != nullptr && inflating_thread->lock_stack().contains(object)) {
!         inf->set_owner_from_anonymous(inflating_thread);
+         size_t removed = inflating_thread->lock_stack().remove(object);
+         inf->set_recursions(removed - 1);
        }
        return inf;
      }
  
      if (LockingMode != LM_LIGHTWEIGHT) {

*** 1357,47 ***
          continue;
        }
      }
  
      // CASE: fast-locked
!     // Could be fast-locked either by current or by some other thread.
      //
      // Note that we allocate the ObjectMonitor speculatively, _before_
      // attempting to set the object's mark to the new ObjectMonitor. If
!     // this thread owns the monitor, then we set the ObjectMonitor's
!     // owner to this thread. Otherwise, we set the ObjectMonitor's owner
      // to anonymous. If we lose the race to set the object's mark to the
      // new ObjectMonitor, then we just delete it and loop around again.
      //
      LogStreamHandle(Trace, monitorinflation) lsh;
      if (LockingMode == LM_LIGHTWEIGHT && mark.is_fast_locked()) {
        ObjectMonitor* monitor = new ObjectMonitor(object);
        monitor->set_header(mark.set_unlocked());
!       bool own = is_lock_owned(current, object);
        if (own) {
!         // Owned by us.
!         monitor->set_owner_from(nullptr, current);
        } else {
          // Owned by somebody else.
          monitor->set_owner_anonymous();
        }
        markWord monitor_mark = markWord::encode(monitor);
        markWord old_mark = object->cas_set_mark(monitor_mark, mark);
        if (old_mark == mark) {
          // Success! Return inflated monitor.
          if (own) {
!           JavaThread::cast(current)->lock_stack().remove(object);
          }
          // Once the ObjectMonitor is configured and object is associated
          // with the ObjectMonitor, it is safe to allow async deflation:
          _in_use_list.add(monitor);
  
          // Hopefully the performance counters are allocated on distinct
          // cache lines to avoid false sharing on MP systems ...
          OM_PERFDATA_OP(Inflations, inc());
          if (log_is_enabled(Trace, monitorinflation)) {
!           ResourceMark rm(current);
            lsh.print_cr("inflate(has_locker): object=" INTPTR_FORMAT ", mark="
                         INTPTR_FORMAT ", type='%s'", p2i(object),
                         object->mark().value(), object->klass()->external_name());
          }
          if (event.should_commit()) {
--- 1453,48 ---
          continue;
        }
      }
  
      // CASE: fast-locked
!     // Could be fast-locked either by the inflating_thread or by some other thread.
      //
      // Note that we allocate the ObjectMonitor speculatively, _before_
      // attempting to set the object's mark to the new ObjectMonitor. If
!     // the inflating_thread owns the monitor, then we set the ObjectMonitor's
!     // owner to the inflating_thread. Otherwise, we set the ObjectMonitor's owner
      // to anonymous. If we lose the race to set the object's mark to the
      // new ObjectMonitor, then we just delete it and loop around again.
      //
      LogStreamHandle(Trace, monitorinflation) lsh;
      if (LockingMode == LM_LIGHTWEIGHT && mark.is_fast_locked()) {
        ObjectMonitor* monitor = new ObjectMonitor(object);
        monitor->set_header(mark.set_unlocked());
!       bool own = inflating_thread != nullptr && inflating_thread->lock_stack().contains(object);
        if (own) {
!         // Owned by inflating_thread.
!         monitor->set_owner_from(nullptr, inflating_thread);
        } else {
          // Owned by somebody else.
          monitor->set_owner_anonymous();
        }
        markWord monitor_mark = markWord::encode(monitor);
        markWord old_mark = object->cas_set_mark(monitor_mark, mark);
        if (old_mark == mark) {
          // Success! Return inflated monitor.
          if (own) {
!           size_t removed = inflating_thread->lock_stack().remove(object);
+           monitor->set_recursions(removed - 1);
          }
          // Once the ObjectMonitor is configured and object is associated
          // with the ObjectMonitor, it is safe to allow async deflation:
          _in_use_list.add(monitor);
  
          // Hopefully the performance counters are allocated on distinct
          // cache lines to avoid false sharing on MP systems ...
          OM_PERFDATA_OP(Inflations, inc());
          if (log_is_enabled(Trace, monitorinflation)) {
!           ResourceMark rm;
            lsh.print_cr("inflate(has_locker): object=" INTPTR_FORMAT ", mark="
                         INTPTR_FORMAT ", type='%s'", p2i(object),
                         object->mark().value(), object->klass()->external_name());
          }
          if (event.should_commit()) {

*** 1492,11 ***
  
        // Hopefully the performance counters are allocated on distinct cache lines
        // to avoid false sharing on MP systems ...
        OM_PERFDATA_OP(Inflations, inc());
        if (log_is_enabled(Trace, monitorinflation)) {
!         ResourceMark rm(current);
          lsh.print_cr("inflate(has_locker): object=" INTPTR_FORMAT ", mark="
                       INTPTR_FORMAT ", type='%s'", p2i(object),
                       object->mark().value(), object->klass()->external_name());
        }
        if (event.should_commit()) {
--- 1589,11 ---
  
        // Hopefully the performance counters are allocated on distinct cache lines
        // to avoid false sharing on MP systems ...
        OM_PERFDATA_OP(Inflations, inc());
        if (log_is_enabled(Trace, monitorinflation)) {
!         ResourceMark rm;
          lsh.print_cr("inflate(has_locker): object=" INTPTR_FORMAT ", mark="
                       INTPTR_FORMAT ", type='%s'", p2i(object),
                       object->mark().value(), object->klass()->external_name());
        }
        if (event.should_commit()) {

*** 1536,11 ***
  
      // Hopefully the performance counters are allocated on distinct
      // cache lines to avoid false sharing on MP systems ...
      OM_PERFDATA_OP(Inflations, inc());
      if (log_is_enabled(Trace, monitorinflation)) {
!       ResourceMark rm(current);
        lsh.print_cr("inflate(neutral): object=" INTPTR_FORMAT ", mark="
                     INTPTR_FORMAT ", type='%s'", p2i(object),
                     object->mark().value(), object->klass()->external_name());
      }
      if (event.should_commit()) {
--- 1633,11 ---
  
      // Hopefully the performance counters are allocated on distinct
      // cache lines to avoid false sharing on MP systems ...
      OM_PERFDATA_OP(Inflations, inc());
      if (log_is_enabled(Trace, monitorinflation)) {
!       ResourceMark rm;
        lsh.print_cr("inflate(neutral): object=" INTPTR_FORMAT ", mark="
                     INTPTR_FORMAT ", type='%s'", p2i(object),
                     object->mark().value(), object->klass()->external_name());
      }
      if (event.should_commit()) {
< prev index next >