< prev index next >

src/hotspot/share/runtime/objectMonitor.cpp

Print this page
rev 56634 : imported patch 8230876.patch
rev 56635 : v2.00 -> v2.05 (CR5/v2.05/8-for-jdk13) patches combined into one; merge with 8229212.patch; merge with jdk-14+11; merge with 8230184.patch; merge with 8230876.patch; merge with jdk-14+15; merge with jdk-14+18.
rev 56637 : Add OM_CACHE_LINE_SIZE so that ObjectMonitor cache line sizes can be experimented with independently of DEFAULT_CACHE_LINE_SIZE; for SPARC and X64 configs that use 128 for DEFAULT_CACHE_LINE_SIZE, we are experimenting with 64; move _previous_owner_tid and _allocation_state fields to share the cache line with ObjectMonitor::_header; put ObjectMonitor::_ref_count on its own cache line after _owner; add 'int* count_p' parameter to deflate_monitor_list() and deflate_monitor_list_using_JT() and push counter updates down to where the ObjectMonitors are actually removed from the in-use lists; monitors_iterate() async deflation check should use negative ref_count; add 'JavaThread* target' param to deflate_per_thread_idle_monitors_using_JT() add deflate_common_idle_monitors_using_JT() to make it clear which JavaThread* is the target of the work and which is the calling JavaThread* (self); g_free_list, g_om_in_use_list and g_om_in_use_count are now static to synchronizer.cpp (reduce scope); add more diagnostic info to some assert()'s; minor code cleanups and code motion; save_om_ptr() should detect a race with a deflating thread that is bailing out and cause a retry when the ref_count field is not positive; merge with jdk-14+11; add special GC support for TestHumongousClassLoader.java; merge with 8230184.patch; merge with jdk-14+14; merge with jdk-14+18.
rev 56639 : loosen a couple more counter checks due to races observed in testing; simplify om_release() extraction of mid since list head or cur_mid_in_use is marked; simplify deflate_monitor_list() extraction of mid since there are no parallel deleters due to the safepoint; simplify deflate_monitor_list_using_JT() extraction of mid since list head or cur_mid_in_use is marked; prepend_block_to_lists() - simplify based on David H's comments; does not need load_acquire() or release_store() because of the cmpxchg(); prepend_to_common() - simplify to use mark_next_loop() for m and use mark_list_head() and release_store() for the non-empty list case; add more debugging for "Non-balanced monitor enter/exit" failure mode; fix race in inflate() in the "CASE: neutral" code path; install_displaced_markword_in_object() does not need to clear the header field since that is handled when the ObjectMonitor is moved from the global free list; LSuccess should clear boxReg to set ICC.ZF=1 to avoid depending on existing boxReg contents; update fast_unlock() to detect when object no longer refers to the same ObjectMonitor and take fast path exit instead; clarify fast_lock() code where we detect when object no longer refers to the same ObjectMonitor; add/update comments for movptr() calls where we move a literal into an Address; remove set_owner(); refactor setting of owner field into set_owner_from(2 versions), set_owner_from_BasicLock(), and try_set_owner_from(); the new functions include monitorinflation+owner logging; extract debug code from v2.06 and v2.07 and move to v2.07.debug; change 'jccb' -> 'jcc' and 'jmpb' -> 'jmp' as needed; checkpoint initial version of MacroAssembler::inc_om_ref_count(); update LP64 MacroAssembler::fast_lock() and fast_unlock() to use inc_om_ref_count(); fast_lock() return flag setting logic can use 'testptr(tmpReg, tmpReg)' instead of 'cmpptr(tmpReg, 0)' since that's more efficient; fast_unlock() LSuccess return flag setting logic can use 'testl (boxReg, 0)' instead of 'xorptr(boxReg, boxReg)' since that's more efficient; cleanup "fast-path" vs "fast path" and "slow-path" vs "slow path"; update MacroAssembler::rtm_inflated_locking() to use inc_om_ref_count(); update MacroAssembler::fast_lock() to preserve the flags before decrementing ref_count and restore the flags afterwards; this is more clean than depending on the contents of rax/tmpReg; coleenp CR - refactor async monitor deflation work from ServiceThread::service_thread_entry() to ObjectSynchronizer::deflate_idle_monitors_using_JT(); rehn,eosterlund CR - add support for HandshakeAfterDeflateIdleMonitors for platforms that don't have ObjectMonitor ref_count support implemented in C2 fast_lock() and fast_unlock().

@@ -243,11 +243,11 @@
 
   // The following code is ordered to check the most common cases first
   // and to reduce RTS->RTO cache line upgrades on SPARC and IA32 processors.
   Thread * const Self = THREAD;
 
-  void * cur = Atomic::cmpxchg(Self, &_owner, (void*)NULL);
+  void* cur = try_set_owner_from(Self, NULL);
   if (cur == NULL) {
     assert(_recursions == 0, "invariant");
     return;
   }
 

@@ -258,18 +258,16 @@
   }
 
   if (Self->is_lock_owned ((address)cur)) {
     assert(_recursions == 0, "internal state error");
     _recursions = 1;
-    // Commute owner from a thread-specific on-stack BasicLockObject address to
-    // a full-fledged "Thread *".
-    _owner = Self;
+    set_owner_from_BasicLock(Self, cur);  // Convert from BasicLock* to Thread*.
     return;
   }
 
   if (AsyncDeflateIdleMonitors &&
-      Atomic::cmpxchg(Self, &_owner, DEFLATER_MARKER) == DEFLATER_MARKER) {
+      try_set_owner_from(Self, DEFLATER_MARKER) == DEFLATER_MARKER) {
     // The deflation protocol finished the first part (setting owner),
     // but it failed the second part (making ref_count negative) and
     // bailed. Or the ObjectMonitor was async deflated and reused.
     // Acquired the monitor.
     assert(_recursions == 0, "invariant");

@@ -413,11 +411,11 @@
 // Callers must compensate as needed.
 
 int ObjectMonitor::TryLock(Thread * Self) {
   void * own = _owner;
   if (own != NULL) return 0;
-  if (Atomic::replace_if_null(Self, &_owner)) {
+  if (try_set_owner_from(Self, NULL) == NULL) {
     assert(_recursions == 0, "invariant");
     return 1;
   }
   // The lock had been free momentarily, but we lost the race to the lock.
   // Interference -- the CAS failed.

@@ -444,12 +442,12 @@
     return;
   }
 
   markWord dmw = header();
   if (dmw.value() == 0) {
-    // ObjectMonitor's header/dmw has been cleared so the object's
-    // header has already been restored.
+    // ObjectMonitor's header/dmw has been cleared so the ObjectMonitor
+    // has been deflated and taken off the global free list.
     return;
   }
 
   // A non-NULL dmw has to be either neutral (not locked and not marked)
   // or is already participating in this restoration protocol.

@@ -495,16 +493,10 @@
   // into the object's header. The thread deflating the monitor just
   // wanted the object's header restored and it is. The threads that
   // detected a race with the deflation process also wanted the
   // object's header restored before they retry their operation and
   // because it is restored they will only retry once.
-
-  if (marked_dmw.value() != 0) {
-    // Clear _header to NULL if it is still marked_dmw so a racing
-    // install_displaced_markword_in_object() can bail out sooner.
-    Atomic::cmpxchg(markWord::zero(), &_header, marked_dmw);
-  }
 }
 
 // Convert the fields used by is_busy() to a string that can be
 // used for diagnostic output.
 const char* ObjectMonitor::is_busy_to_string(stringStream* ss) {

@@ -537,11 +529,11 @@
     assert(_Responsible != Self, "invariant");
     return;
   }
 
   if (AsyncDeflateIdleMonitors &&
-      Atomic::cmpxchg(Self, &_owner, DEFLATER_MARKER) == DEFLATER_MARKER) {
+      try_set_owner_from(Self, DEFLATER_MARKER) == DEFLATER_MARKER) {
     // The deflation protocol finished the first part (setting owner),
     // but it failed the second part (making ref_count negative) and
     // bailed. Or the ObjectMonitor was async deflated and reused.
     // Acquired the monitor.
     assert(_succ != Self, "invariant");

@@ -664,11 +656,11 @@
     }
 
     if (TryLock(Self) > 0) break;
 
     if (AsyncDeflateIdleMonitors &&
-        Atomic::cmpxchg(Self, &_owner, DEFLATER_MARKER) == DEFLATER_MARKER) {
+        try_set_owner_from(Self, DEFLATER_MARKER) == DEFLATER_MARKER) {
       // The deflation protocol finished the first part (setting owner),
       // but it failed the second part (making ref_count negative) and
       // bailed. Or the ObjectMonitor was async deflated and reused.
       // Acquired the monitor.
       break;

@@ -796,11 +788,11 @@
 
     if (TryLock(Self) > 0) break;
     if (TrySpin(Self) > 0) break;
 
     if (AsyncDeflateIdleMonitors &&
-        Atomic::cmpxchg(Self, &_owner, DEFLATER_MARKER) == DEFLATER_MARKER) {
+        try_set_owner_from(Self, DEFLATER_MARKER) == DEFLATER_MARKER) {
       // The deflation protocol finished the first part (setting owner),
       // but it failed the second part (making ref_count negative) and
       // bailed. Or the ObjectMonitor was async deflated and reused.
       // Acquired the monitor.
       break;

@@ -993,17 +985,14 @@
 // of such futile wakups is low.
 
 void ObjectMonitor::exit(bool not_suspended, TRAPS) {
   Thread * const Self = THREAD;
   if (THREAD != _owner) {
-    if (THREAD->is_lock_owned((address) _owner)) {
-      // Transmute _owner from a BasicLock pointer to a Thread address.
-      // We don't need to hold _mutex for this transition.
-      // Non-null to Non-null is safe as long as all readers can
-      // tolerate either flavor.
+    void* cur = _owner;
+    if (THREAD->is_lock_owned((address)cur)) {
       assert(_recursions == 0, "invariant");
-      _owner = THREAD;
+      set_owner_from_BasicLock(Self, cur);  // Convert from BasicLock* to Thread*.
       _recursions = 0;
     } else {
       // Apparent unbalanced locking ...
       // Naively we'd like to throw IllegalMonitorStateException.
       // As a practical matter we can neither allocate nor throw an

@@ -1011,12 +1000,18 @@
       // see x86_32.ad Fast_Unlock() and the I1 and I2 properties.
       // Upon deeper reflection, however, in a properly run JVM the only
       // way we should encounter this situation is in the presence of
       // unbalanced JNI locking. TODO: CheckJNICalls.
       // See also: CR4414101
-      assert(false, "Non-balanced monitor enter/exit! Likely JNI locking: "
-             "owner=" INTPTR_FORMAT, p2i(_owner));
+      tty->print_cr("ERROR: ObjectMonitor::exit(): thread=" INTPTR_FORMAT
+                    " is exiting an ObjectMonitor it does not own.",
+                    p2i(THREAD));
+      tty->print_cr("The imbalance is possibly caused by JNI locking.");
+      print_debug_style_on(tty);
+      // Changing this from an assert() to ADIM_guarantee() may run
+      // afoul of any test that is inducing non-balanced JNI locking.
+      ADIM_guarantee(false, "Non-balanced monitor enter/exit!");
       return;
     }
   }
 
   if (_recursions != 0) {

@@ -1041,12 +1036,16 @@
 
     // release semantics: prior loads and stores from within the critical section
     // must not float (reorder) past the following store that drops the lock.
     // On SPARC that requires MEMBAR #loadstore|#storestore.
     // But of course in TSO #loadstore|#storestore is not required.
+    if (AsyncDeflateIdleMonitors) {
+      set_owner_from(NULL, Self);
+    } else {
     OrderAccess::release_store(&_owner, (void*)NULL);   // drop the lock
     OrderAccess::storeload();                        // See if we need to wake a successor
+    }
     if ((intptr_t(_EntryList)|intptr_t(_cxq)) == 0 || _succ != NULL) {
       return;
     }
     // Other threads are blocked trying to acquire the lock.
 

@@ -1084,11 +1083,11 @@
     // Only the current lock owner can manipulate the EntryList or
     // drain _cxq, so we need to reacquire the lock.  If we fail
     // to reacquire the lock the responsibility for ensuring succession
     // falls to the new owner.
     //
-    if (!Atomic::replace_if_null(THREAD, &_owner)) {
+    if (try_set_owner_from(Self, NULL) != NULL) {
       return;
     }
 
     guarantee(_owner == THREAD, "invariant");
 

@@ -1217,12 +1216,16 @@
   // The thread associated with Wakee may have grabbed the lock and "Wakee" may be
   // out-of-scope (non-extant).
   Wakee  = NULL;
 
   // Drop the lock
+  if (AsyncDeflateIdleMonitors) {
+    set_owner_from(NULL, Self);
+  } else {
   OrderAccess::release_store(&_owner, (void*)NULL);
   OrderAccess::fence();                               // ST _owner vs LD in unpark()
+  }
 
   DTRACE_MONITOR_PROBE(contended__exit, this, object(), Self);
   Trigger->unpark();
 
   // Maintain stats and report events to JVMTI

@@ -1245,13 +1248,14 @@
   JavaThread *jt = (JavaThread *)THREAD;
 
   assert(InitDone, "Unexpectedly not initialized");
 
   if (THREAD != _owner) {
-    if (THREAD->is_lock_owned ((address)_owner)) {
+    void* cur = _owner;
+    if (THREAD->is_lock_owned((address)cur)) {
       assert(_recursions == 0, "internal state error");
-      _owner = THREAD;   // Convert from basiclock addr to Thread addr
+      set_owner_from_BasicLock(Self, cur);  // Convert from BasicLock* to Thread*.
       _recursions = 0;
     }
   }
 
   guarantee(Self == _owner, "complete_exit not owner");

@@ -1295,12 +1299,13 @@
 // is not the owner, that exception will be replaced by the IMSE.
 bool ObjectMonitor::check_owner(Thread* THREAD) {
   if (_owner == THREAD) {
     return true;
   }
-  if (THREAD->is_lock_owned((address)_owner)) {
-    _owner = THREAD;  // convert from BasicLock addr to Thread addr
+  void* cur = _owner;
+  if (THREAD->is_lock_owned((address)cur)) {
+    set_owner_from_BasicLock(THREAD, cur);  // Convert from BasicLock* to Thread*.
     _recursions = 0;
     return true;
   }
   THROW_MSG_(vmSymbols::java_lang_IllegalMonitorStateException(),
              "current thread is not owner", false);

@@ -1801,11 +1806,11 @@
     // the spin without prejudice or apply a "penalty" to the
     // spin count-down variable "ctr", reducing it by 100, say.
 
     Thread * ox = (Thread *) _owner;
     if (ox == NULL) {
-      ox = (Thread*)Atomic::cmpxchg(Self, &_owner, (void*)NULL);
+      ox = (Thread*)try_set_owner_from(Self, NULL);
       if (ox == NULL) {
         // The CAS succeeded -- this thread acquired ownership
         // Take care of some bookkeeping to exit spin state.
         if (_succ == Self) {
           _succ = NULL;

@@ -2154,5 +2159,91 @@
             ",recursions=" INTX_FORMAT ",owner=" INTPTR_FORMAT "}",
             contentions(), waiters(), recursions(),
             p2i(owner()));
 }
 void ObjectMonitor::print() const { print_on(tty); }
+
+// Print the ObjectMonitor like a debugger would:
+//
+// (ObjectMonitor) 0x00007fdfb6012e40 = {
+//   _header = (_value = 1)
+//   _object = 0x000000070ff45fd0
+//   _allocation_state = Old
+//   _pad_buf0 = {
+//     [0] = '\0'
+//     ...
+//     [43] = '\0'
+//   }
+//   _owner = 0x0000000000000000
+//   _previous_owner_tid = 0
+//   _pad_buf1 = {
+//     [0] = '\0'
+//     ...
+//     [47] = '\0'
+//   }
+//   _ref_count = 1
+//   _pad_buf2 = {
+//     [0] = '\0'
+//     ...
+//     [59] = '\0'
+//   }
+//   _next_om = 0x0000000000000000
+//   _recursions = 0
+//   _EntryList = 0x0000000000000000
+//   _cxq = 0x0000000000000000
+//   _succ = 0x0000000000000000
+//   _Responsible = 0x0000000000000000
+//   _Spinner = 0
+//   _SpinDuration = 5000
+//   _contentions = 0
+//   _WaitSet = 0x0000700009756248
+//   _waiters = 1
+//   _WaitSetLock = 0
+// }
+//
+void ObjectMonitor::print_debug_style_on(outputStream* st) const {
+  st->print_cr("(ObjectMonitor *) " INTPTR_FORMAT " = {", p2i(this));
+  st->print_cr("  _header = " INTPTR_FORMAT, header().value());
+  st->print_cr("  _object = " INTPTR_FORMAT, p2i(_object));
+  st->print("  _allocation_state = ");
+  if (is_free()) {
+    st->print("Free");
+  } else if (is_old()) {
+    st->print("Old");
+  } else if (is_new()) {
+    st->print("New");
+  } else {
+    st->print("unknown=%d", _allocation_state);
+  }
+  st->cr();
+  st->print_cr("  _pad_buf0 = {");
+  st->print_cr("    [0] = '\\0'");
+  st->print_cr("    ...");
+  st->print_cr("    [%d] = '\\0'", (int)sizeof(_pad_buf0) - 1);
+  st->print_cr("  }");
+  st->print_cr("  _owner = " INTPTR_FORMAT, p2i(_owner));
+  st->print_cr("  _previous_owner_tid = " JLONG_FORMAT, _previous_owner_tid);
+  st->print_cr("  _pad_buf1 = {");
+  st->print_cr("    [0] = '\\0'");
+  st->print_cr("    ...");
+  st->print_cr("    [%d] = '\\0'", (int)sizeof(_pad_buf1) - 1);
+  st->print_cr("  }");
+  st->print_cr("  _ref_count = %d", ref_count());
+  st->print_cr("  _pad_buf2 = {");
+  st->print_cr("    [0] = '\\0'");
+  st->print_cr("    ...");
+  st->print_cr("    [%d] = '\\0'", (int)sizeof(_pad_buf1) - 1);
+  st->print_cr("  }");
+  st->print_cr("  _next_om = " INTPTR_FORMAT, p2i(_next_om));
+  st->print_cr("  _recursions = " INTX_FORMAT, _recursions);
+  st->print_cr("  _EntryList = " INTPTR_FORMAT, p2i(_EntryList));
+  st->print_cr("  _cxq = " INTPTR_FORMAT, p2i(_cxq));
+  st->print_cr("  _succ = " INTPTR_FORMAT, p2i(_succ));
+  st->print_cr("  _Responsible = " INTPTR_FORMAT, p2i(_Responsible));
+  st->print_cr("  _Spinner = %d", _Spinner);
+  st->print_cr("  _SpinDuration = %d", _SpinDuration);
+  st->print_cr("  _contentions = %d", _contentions);
+  st->print_cr("  _WaitSet = " INTPTR_FORMAT, p2i(_WaitSet));
+  st->print_cr("  _waiters = %d", _waiters);
+  st->print_cr("  _WaitSetLock = %d", _WaitSetLock);
+  st->print_cr("}");
+}
< prev index next >