--- old/src/hotspot/share/runtime/objectMonitor.cpp 2020-05-14 16:16:59.000000000 -0400 +++ new/src/hotspot/share/runtime/objectMonitor.cpp 2020-05-14 16:16:58.000000000 -0400 @@ -294,8 +294,8 @@ assert(AsyncDeflateIdleMonitors || contentions() >= 0, "must not be negative: contentions=%d", contentions()); // Keep track of contention for JVM/TI and M&M queries. - Atomic::inc(&_contentions); - if (AsyncDeflateIdleMonitors && is_being_async_deflated()) { + add_to_contentions((jint)1); + if (is_being_async_deflated()) { // Async deflation is in progress and our contentions increment // above lost the race to async deflation. Undo the work and // force the caller to retry. @@ -306,7 +306,7 @@ install_displaced_markword_in_object(l_object); } Self->_Stalled = 0; - Atomic::dec(&_contentions); + add_to_contentions((jint)-1); return false; } @@ -369,7 +369,7 @@ // acquire it. } - Atomic::dec(&_contentions); + add_to_contentions((jint)-1); assert(contentions() >= 0, "must not be negative: contentions=%d", contentions()); Self->_Stalled = 0; @@ -453,8 +453,8 @@ ADIM_guarantee(dmw.is_neutral(), "must be neutral: dmw=" INTPTR_FORMAT, dmw.value()); // Install displaced mark word if the object's header still points - // to this ObjectMonitor. All racing callers to this function will - // reach this point, but only one can win. + // to this ObjectMonitor. More than one racing caller to this function + // can rarely reach this point, but only one can win. markWord res = obj->cas_set_mark(dmw, markWord::encode(this)); if (res != markWord::encode(this)) { // This should be rare so log at the Info level when it happens. --- old/src/hotspot/share/runtime/objectMonitor.hpp 2020-05-14 16:17:04.000000000 -0400 +++ new/src/hotspot/share/runtime/objectMonitor.hpp 2020-05-14 16:17:03.000000000 -0400 @@ -288,6 +288,7 @@ jint waiters() const; jint contentions() const; + void add_to_contentions(jint value); intx recursions() const { return _recursions; } // JVM/TI GetObjectMonitorUsage() needs this: @@ -339,7 +340,7 @@ // returns false and throws IllegalMonitorStateException (IMSE). bool check_owner(Thread* THREAD); void clear(); - void clear_using_JT(); + void clear_common(); bool enter(TRAPS); void exit(bool not_suspended, TRAPS); --- old/src/hotspot/share/runtime/objectMonitor.inline.hpp 2020-05-14 16:17:08.000000000 -0400 +++ new/src/hotspot/share/runtime/objectMonitor.inline.hpp 2020-05-14 16:17:07.000000000 -0400 @@ -62,12 +62,12 @@ // This accessor is called when we really need to know if the owner // field == DEFLATER_MARKER and any non-NULL value won't do the trick. inline bool ObjectMonitor::owner_is_DEFLATER_MARKER() { - return _owner == DEFLATER_MARKER; + return Atomic::load(&_owner) == DEFLATER_MARKER; } // Returns true if 'this' is being async deflated and false otherwise. inline bool ObjectMonitor::is_being_async_deflated() { - return owner_is_DEFLATER_MARKER() && contentions() < 0; + return AsyncDeflateIdleMonitors && owner_is_DEFLATER_MARKER() && contentions() < 0; } inline void ObjectMonitor::clear() { @@ -76,14 +76,10 @@ Atomic::store(&_header, markWord::zero()); - clear_using_JT(); + clear_common(); } -inline void ObjectMonitor::clear_using_JT() { - // Unlike other *_using_JT() functions, we cannot assert - // AsyncDeflateIdleMonitors or Thread::current()->is_Java_thread() - // because clear() calls this function for the rest of its checks. - +inline void ObjectMonitor::clear_common() { if (AsyncDeflateIdleMonitors) { // Async deflation protocol uses the header, owner and contentions // fields. While the ObjectMonitor being deflated is on the global free @@ -121,6 +117,11 @@ return Atomic::load(&_contentions); } +// Add value to the contentions field. +inline void ObjectMonitor::add_to_contentions(jint value) { + Atomic::add(&_contentions, value); +} + // Clear _owner field; current value must match old_value. inline void ObjectMonitor::release_clear_owner(void* old_value) { void* prev = Atomic::load(&_owner); --- old/src/hotspot/share/runtime/synchronizer.cpp 2020-05-14 16:17:13.000000000 -0400 +++ new/src/hotspot/share/runtime/synchronizer.cpp 2020-05-14 16:17:12.000000000 -0400 @@ -1041,13 +1041,31 @@ // occurred or... so we fall thru to inflate the monitor for // stability and then install the hash. } else if (mark.has_monitor()) { - // The first stage of a racing async deflation won't affect the - // hash value if this ObjectMonitor happens to already have one. monitor = mark.monitor(); temp = monitor->header(); assert(temp.is_neutral(), "invariant: header=" INTPTR_FORMAT, temp.value()); hash = temp.hash(); - if (hash != 0) { // if it has a hash, just return it + if (hash != 0) { + // It has a hash. + + // Separate load of dmw/header above from the loads in + // is_being_async_deflated(). + if (support_IRIW_for_not_multiple_copy_atomic_cpu) { + // A non-multiple copy atomic (nMCA) machine needs a bigger + // hammer to make sure that the load above and the loads + // below all see non-stale memory values. + OrderAccess::fence(); + } else { + OrderAccess::loadload(); + } + if (monitor->is_being_async_deflated()) { + // But we can't safely use the hash if we detect that async + // deflation has occurred. So we attempt to restore the + // header/dmw to the object's header so that we only retry + // once if the deflater thread happens to be slow. + monitor->install_displaced_markword_in_object(obj); + continue; + } return hash; } // Fall thru so we only have one place that installs the hash in @@ -1098,9 +1116,10 @@ } if (monitor->is_being_async_deflated()) { // If we detect that async deflation has occurred, then we - // simply retry so that the hash value can be stored in either - // the object's header or in the re-inflated ObjectMonitor's - // header as appropriate. + // attempt to restore the header/dmw to the object's header + // so that we only retry once if the deflater thread happens + // to be slow. + monitor->install_displaced_markword_in_object(obj); continue; } } @@ -1244,14 +1263,15 @@ assert(block->object() == CHAINMARKER, "must be a block header"); for (int i = _BLOCKSIZE - 1; i > 0; i--) { ObjectMonitor* mid = (ObjectMonitor *)(block + i); - if (!mid->is_free() && mid->object() != NULL) { + if (mid->object() != NULL) { // Only process with closure if the object is set. // monitors_iterate() is only called at a safepoint or when the // target thread is suspended or when the target thread is - // operating on itself. The closures are only interested in an - // owned ObjectMonitor and ownership cannot be dropped under the - // calling contexts so the ObjectMonitor cannot be async deflated. + // 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. closure->do_monitor(mid); } } @@ -1408,7 +1428,7 @@ if (take->contentions() < 0) { // Add back max_jint to restore the contentions field to its // proper value. - Atomic::add(&take->_contentions, max_jint); + take->add_to_contentions(max_jint); #ifdef ASSERT jint l_contentions = take->contentions(); @@ -1640,11 +1660,11 @@ cur_om = unmarked_next(in_use_tail); continue; } - if (cur_om->is_free()) { - // cur_om was deflated and the allocation state was changed - // to Free while it was locked. We happened to see it just - // after it was unlocked (and added to the free list). - // Refetch the possibly changed next field and try again. + if (cur_om->object() == NULL) { + // cur_om was deflated and the object ref was cleared while it + // was locked. We happened to see it just after it was unlocked + // (and added to the free list). Refetch the possibly changed + // next field and try again. cur_om = unmarked_next(in_use_tail); continue; } @@ -2139,10 +2159,10 @@ return false; } - // Make contentions negative to force any contending threads to - // retry. This is the second part of the async deflation dance. + // Make a zero contentions field negative to force any contending threads + // to retry. This is the second part of the async deflation dance. if (Atomic::cmpxchg(&mid->_contentions, (jint)0, -max_jint) != 0) { - // The contentions was no longer 0 so we lost the race since the + // Contentions was no longer 0 so we lost the race since the // ObjectMonitor is now busy. Restore owner to NULL if it is // still DEFLATER_MARKER: mid->try_set_owner_from(DEFLATER_MARKER, NULL); @@ -2161,7 +2181,7 @@ // Add back max_jint to restore the contentions field to its // proper value (which may not be what we saw above): - Atomic::add(&mid->_contentions, max_jint); + mid->add_to_contentions(max_jint); #ifdef ASSERT jint l_contentions = mid->contentions(); @@ -2193,7 +2213,7 @@ // Install the old mark word if nobody else has already done it. mid->install_displaced_markword_in_object(obj); - mid->clear_using_JT(); + mid->clear_common(); assert(mid->object() == NULL, "must be NULL: object=" INTPTR_FORMAT, p2i(mid->object())); @@ -2605,6 +2625,16 @@ } do { + if (saved_mid_in_use_p != NULL) { + // We looped around because deflate_monitor_list_using_JT() + // detected a pending safepoint. Honoring the safepoint is good, + // but as long as is_special_deflation_requested() is supported, + // we can't safely restart using saved_mid_in_use_p. That saved + // ObjectMonitor could have been deflated by safepoint based + // deflation and would no longer be on the in-use list where we + // originally found it. + saved_mid_in_use_p = NULL; + } int local_deflated_count; if (is_global) { local_deflated_count = --- old/src/hotspot/share/runtime/vframe.cpp 2020-05-14 16:17:18.000000000 -0400 +++ new/src/hotspot/share/runtime/vframe.cpp 2020-05-14 16:17:16.000000000 -0400 @@ -124,7 +124,7 @@ bool found_first_monitor = false; // The ObjectMonitor* can't be async deflated since we are either // at a safepoint or the calling thread is operating on itself so - // it cannot leave the underlying wait()/enter() call. + // it cannot exit the ObjectMonitor so it remains busy. ObjectMonitor *waiting_monitor = thread()->current_waiting_monitor(); ObjectMonitor *pending_monitor = NULL; if (waiting_monitor == NULL) { --- old/src/hotspot/share/services/threadService.cpp 2020-05-14 16:17:23.000000000 -0400 +++ new/src/hotspot/share/services/threadService.cpp 2020-05-14 16:17:21.000000000 -0400 @@ -37,7 +37,6 @@ #include "runtime/handles.inline.hpp" #include "runtime/init.hpp" #include "runtime/objectMonitor.inline.hpp" -#include "runtime/safepointVerifiers.hpp" #include "runtime/thread.inline.hpp" #include "runtime/threadSMR.inline.hpp" #include "runtime/vframe.hpp"