8153224: Monitor deflation prolong safepoints

Add support for AsyncDeflateIdleMonitors (default true); the async deflation work is performed by the ServiceThread.

Co-authored-by: Carsten Varming <varming@gmail.com>
Reviewed-by: dcubed, rehn, rkennke, cvarming, coleenp, acorn, dholmes, eosterlund
This commit is contained in:
Daniel D. Daugherty 2020-06-01 23:37:14 -04:00
parent 30aa1b0689
commit 00f223e22f
23 changed files with 1496 additions and 250 deletions

View File

@ -74,6 +74,7 @@
#include "runtime/os.inline.hpp"
#include "runtime/perfData.hpp"
#include "runtime/reflection.hpp"
#include "runtime/synchronizer.hpp"
#include "runtime/thread.inline.hpp"
#include "runtime/threadSMR.hpp"
#include "runtime/vframe.inline.hpp"
@ -490,6 +491,11 @@ JVM_END
JVM_ENTRY_NO_ENV(void, JVM_GC(void))
JVMWrapper("JVM_GC");
if (!DisableExplicitGC) {
if (AsyncDeflateIdleMonitors) {
// AsyncDeflateIdleMonitors needs to know when System.gc() is
// called so any special deflation can be done at a safepoint.
ObjectSynchronizer::set_is_special_deflation_requested(true);
}
Universe::heap()->collect(GCCause::_java_lang_system_gc);
}
JVM_END

View File

@ -653,6 +653,9 @@ JvmtiEnvBase::get_current_contended_monitor(JavaThread *java_thread, jobject *mo
current_jt == java_thread->active_handshaker(),
"call by myself or at direct handshake");
oop obj = NULL;
// 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.
ObjectMonitor *mon = java_thread->current_waiting_monitor();
if (mon == NULL) {
// thread is not doing an Object.wait() call
@ -730,7 +733,10 @@ JvmtiEnvBase::get_locked_objects_in_frame(JavaThread* calling_thread, JavaThread
HandleMark hm;
oop wait_obj = NULL;
{
// save object of current wait() call (if any) for later comparison
// 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() call.
// Save object of current wait() call (if any) for later comparison.
ObjectMonitor *mon = java_thread->current_waiting_monitor();
if (mon != NULL) {
wait_obj = (oop)mon->object();
@ -738,7 +744,10 @@ JvmtiEnvBase::get_locked_objects_in_frame(JavaThread* calling_thread, JavaThread
}
oop pending_obj = NULL;
{
// save object of current enter() call (if any) for later comparison
// 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 enter() call.
// Save object of current enter() call (if any) for later comparison.
ObjectMonitor *mon = java_thread->current_pending_monitor();
if (mon != NULL) {
pending_obj = (oop)mon->object();

View File

@ -73,6 +73,7 @@
#include "runtime/jniHandles.inline.hpp"
#include "runtime/os.hpp"
#include "runtime/sweeper.hpp"
#include "runtime/synchronizer.hpp"
#include "runtime/thread.hpp"
#include "runtime/threadSMR.hpp"
#include "runtime/vm_version.hpp"
@ -477,6 +478,12 @@ WB_END
WB_ENTRY(jboolean, WB_G1StartMarkCycle(JNIEnv* env, jobject o))
if (UseG1GC) {
if (AsyncDeflateIdleMonitors) {
// AsyncDeflateIdleMonitors needs to know when System.gc() or
// the equivalent is called so any special clean up can be done
// at a safepoint, e.g., TestHumongousClassLoader.java.
ObjectSynchronizer::set_is_special_deflation_requested(true);
}
G1CollectedHeap* g1h = G1CollectedHeap::heap();
if (!g1h->concurrent_mark()->cm_thread()->during_cycle()) {
g1h->collect(GCCause::_wb_conc_mark);
@ -1448,6 +1455,12 @@ WB_ENTRY(jboolean, WB_IsInStringTable(JNIEnv* env, jobject o, jstring javaString
WB_END
WB_ENTRY(void, WB_FullGC(JNIEnv* env, jobject o))
if (AsyncDeflateIdleMonitors) {
// AsyncDeflateIdleMonitors needs to know when System.gc() or
// the equivalent is called so any special clean up can be done
// at a safepoint, e.g., TestHumongousClassLoader.java.
ObjectSynchronizer::set_is_special_deflation_requested(true);
}
Universe::heap()->soft_ref_policy()->set_should_clear_all_soft_refs(true);
Universe::heap()->collect(GCCause::_wb_full_gc);
#if INCLUDE_G1GC
@ -1797,6 +1810,13 @@ WB_ENTRY(jboolean, WB_IsMonitorInflated(JNIEnv* env, jobject wb, jobject obj))
WB_END
WB_ENTRY(void, WB_ForceSafepoint(JNIEnv* env, jobject wb))
if (AsyncDeflateIdleMonitors) {
// AsyncDeflateIdleMonitors needs to know when System.gc() or
// the equivalent is called so any special clean up can be done
// at a safepoint, e.g., TestRTMTotalCountIncrRate.java or
// TestUseRTMForStackLocks.java.
ObjectSynchronizer::set_is_special_deflation_requested(true);
}
VM_ForceSafepoint force_safepoint_op;
VMThread::execute(&force_safepoint_op);
WB_END

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2020, 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
@ -36,24 +36,24 @@ void BasicLock::print_on(outputStream* st) const {
void BasicLock::move_to(oop obj, BasicLock* dest) {
// Check to see if we need to inflate the lock. This is only needed
// if an object is locked using "this" lightweight monitor. In that
// case, the displaced_header() is unlocked, because the
// case, the displaced_header() is unlocked/is_neutral, because the
// displaced_header() contains the header for the originally unlocked
// object. However the object could have already been inflated. But it
// does not matter, the inflation will just a no-op. For other cases,
// object. However the lock could have already been inflated. But it
// does not matter, this inflation will just a no-op. For other cases,
// the displaced header will be either 0x0 or 0x3, which are location
// independent, therefore the BasicLock is free to move.
//
// During OSR we may need to relocate a BasicLock (which contains a
// displaced word) from a location in an interpreter frame to a
// new location in a compiled frame. "this" refers to the source
// basiclock in the interpreter frame. "dest" refers to the destination
// basiclock in the new compiled frame. We *always* inflate in move_to().
// The always-Inflate policy works properly, but in 1.5.0 it can sometimes
// cause performance problems in code that makes heavy use of a small # of
// uncontended locks. (We'd inflate during OSR, and then sync performance
// would subsequently plummet because the thread would be forced thru the slow-path).
// This problem has been made largely moot on IA32 by inlining the inflated fast-path
// operations in Fast_Lock and Fast_Unlock in i486.ad.
// BasicLock in the interpreter frame. "dest" refers to the destination
// BasicLock in the new compiled frame. We *always* inflate in move_to()
// when the object is locked using "this" lightweight monitor.
//
// The always-Inflate policy works properly, but it depends on the
// inflated fast-path operations in fast_lock and fast_unlock to avoid
// performance problems. See x86/macroAssembler_x86.cpp: fast_lock()
// and fast_unlock() for examples.
//
// Note that there is a way to safely swing the object's markword from
// one stack location to another. This avoids inflation. Obviously,
@ -63,8 +63,10 @@ void BasicLock::move_to(oop obj, BasicLock* dest) {
// we'll leave that optimization for another time.
if (displaced_header().is_neutral()) {
// The object is locked and the resulting ObjectMonitor* will also be
// locked so it can't be async deflated until ownership is dropped.
ObjectSynchronizer::inflate_helper(obj);
// WARNING: We can not put check here, because the inflation
// WARNING: We cannot put a check here, because the inflation
// will not update the displaced header. Once BasicLock is inflated,
// no one should ever look at its content.
} else {

View File

@ -683,11 +683,21 @@ const size_t minimumSymbolTableSize = 1024;
"Disable the use of stack guard pages if the JVM is loaded " \
"on the primordial process thread") \
\
diagnostic(bool, AsyncDeflateIdleMonitors, true, \
"Deflate idle monitors using the ServiceThread.") \
\
/* notice: the max range value here is max_jint, not max_intx */ \
/* because of overflow issue */ \
diagnostic(intx, AsyncDeflationInterval, 250, \
"Async deflate idle monitors every so many milliseconds when " \
"MonitorUsedDeflationThreshold is exceeded (0 is off).") \
range(0, max_jint) \
\
experimental(intx, MonitorUsedDeflationThreshold, 90, \
"Percentage of used monitors before triggering cleanup " \
"safepoint which deflates monitors (0 is off). " \
"The check is performed on GuaranteedSafepointInterval.") \
range(0, 100) \
"Percentage of used monitors before triggering deflation (0 is " \
"off). The check is performed on GuaranteedSafepointInterval " \
"or AsyncDeflationInterval.") \
range(0, 100) \
\
experimental(intx, hashCode, 5, \
"(Unstable) select hashCode generation algorithm") \

View File

@ -172,8 +172,12 @@ void exit_globals() {
if (log_is_enabled(Info, monitorinflation)) {
// The ObjectMonitor subsystem uses perf counters so
// do this before perfMemory_exit().
// ObjectSynchronizer::finish_deflate_idle_monitors()'s call
// to audit_and_print_stats() is done at the Debug level.
// These other two audit_and_print_stats() calls are done at the
// Debug level at a safepoint:
// - for safepoint based deflation auditing:
// ObjectSynchronizer::finish_deflate_idle_monitors()
// - for async deflation auditing:
// ObjectSynchronizer::do_safepoint_work()
ObjectSynchronizer::audit_and_print_stats(true /* on_exit */);
}
perfMemory_exit();

View File

@ -240,7 +240,7 @@ void ObjectMonitor::operator delete[] (void *p) {
// -----------------------------------------------------------------------------
// Enter support
void ObjectMonitor::enter(TRAPS) {
bool ObjectMonitor::enter(TRAPS) {
// 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;
@ -248,20 +248,20 @@ void ObjectMonitor::enter(TRAPS) {
void* cur = try_set_owner_from(NULL, Self);
if (cur == NULL) {
assert(_recursions == 0, "invariant");
return;
return true;
}
if (cur == Self) {
// TODO-FIXME: check for integer overflow! BUGID 6557169.
_recursions++;
return;
return true;
}
if (Self->is_lock_owned((address)cur)) {
assert(_recursions == 0, "internal state error");
_recursions = 1;
set_owner_from_BasicLock(cur, Self); // Convert from BasicLock* to Thread*.
return;
return true;
}
// We've encountered genuine contention.
@ -281,7 +281,7 @@ void ObjectMonitor::enter(TRAPS) {
", encoded this=" INTPTR_FORMAT, ((oop)object())->mark().value(),
markWord::encode(this).value());
Self->_Stalled = 0;
return;
return true;
}
assert(_owner != Self, "invariant");
@ -290,12 +290,25 @@ void ObjectMonitor::enter(TRAPS) {
JavaThread * jt = (JavaThread *) Self;
assert(!SafepointSynchronize::is_at_safepoint(), "invariant");
assert(jt->thread_state() != _thread_blocked, "invariant");
assert(this->object() != NULL, "invariant");
assert(_contentions >= 0, "invariant");
assert(AsyncDeflateIdleMonitors || this->object() != NULL, "invariant");
assert(AsyncDeflateIdleMonitors || contentions() >= 0, "must not be negative: contentions=%d", contentions());
// Prevent deflation at STW-time. See deflate_idle_monitors() and is_busy().
// Ensure the object-monitor relationship remains stable while there's contention.
Atomic::inc(&_contentions);
// Keep track of contention for JVM/TI and M&M queries.
add_to_contentions(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.
const oop l_object = (oop)object();
if (l_object != NULL) {
// 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.
install_displaced_markword_in_object(l_object);
}
Self->_Stalled = 0;
add_to_contentions(-1);
return false;
}
JFR_ONLY(JfrConditionalFlushWithStacktrace<EventJavaMonitorEnter> flush(jt);)
EventJavaMonitorEnter event;
@ -356,8 +369,8 @@ void ObjectMonitor::enter(TRAPS) {
// acquire it.
}
Atomic::dec(&_contentions);
assert(_contentions >= 0, "invariant");
add_to_contentions(-1);
assert(contentions() >= 0, "must not be negative: contentions=%d", contentions());
Self->_Stalled = 0;
// Must either set _recursions = 0 or ASSERT _recursions == 0.
@ -393,6 +406,7 @@ void ObjectMonitor::enter(TRAPS) {
event.commit();
}
OM_PERFDATA_OP(ContendedLockAttempts, inc());
return true;
}
// Caveat: TryLock() is not necessarily serializing if it returns failure.
@ -412,12 +426,86 @@ int ObjectMonitor::TryLock(Thread * Self) {
return -1;
}
// Install the displaced mark word (dmw) of a deflating ObjectMonitor
// into the header of the object associated with the monitor. This
// idempotent method is called by a thread that is deflating a
// monitor and by other threads that have detected a race with the
// deflation process.
void ObjectMonitor::install_displaced_markword_in_object(const oop obj) {
// This function must only be called when (owner == DEFLATER_MARKER
// && contentions <= 0), but we can't guarantee that here because
// those values could change when the ObjectMonitor gets moved from
// the global free list to a per-thread free list.
guarantee(obj != NULL, "must be non-NULL");
// Separate loads in is_being_async_deflated(), which is almost always
// called before this function, from the load of dmw/header below.
if (support_IRIW_for_not_multiple_copy_atomic_cpu) {
// A non-multiple copy atomic (nMCA) machine needs a bigger
// hammer to separate the loads before and the load below.
OrderAccess::fence();
} else {
OrderAccess::loadload();
}
const oop l_object = (oop)object();
if (l_object == NULL) {
// ObjectMonitor's object ref has already been cleared by async
// deflation so we're done here.
return;
}
ADIM_guarantee(l_object == obj, "object=" INTPTR_FORMAT " must equal obj="
INTPTR_FORMAT, p2i(l_object), p2i(obj));
markWord dmw = header();
// The dmw has to be neutral (not NULL, not locked and not marked).
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. 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.
log_info(monitorinflation)("install_displaced_markword_in_object: "
"failed cas_set_mark: new_mark=" INTPTR_FORMAT
", old_mark=" INTPTR_FORMAT ", res=" INTPTR_FORMAT,
dmw.value(), markWord::encode(this).value(),
res.value());
}
// Note: It does not matter which thread restored the header/dmw
// 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.
}
// 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) {
ss->print("is_busy: contentions=%d, waiters=%d, owner=" INTPTR_FORMAT
", cxq=" INTPTR_FORMAT ", EntryList=" INTPTR_FORMAT, _contentions,
_waiters, p2i(_owner), p2i(_cxq), p2i(_EntryList));
ss->print("is_busy: waiters=%d, ", _waiters);
if (!AsyncDeflateIdleMonitors) {
ss->print("contentions=%d, ", contentions());
ss->print("owner=" INTPTR_FORMAT, p2i(_owner));
} else {
if (contentions() > 0) {
ss->print("contentions=%d, ", contentions());
} else {
ss->print("contentions=0");
}
if (_owner != DEFLATER_MARKER) {
ss->print("owner=" INTPTR_FORMAT, p2i(_owner));
} else {
// We report NULL instead of DEFLATER_MARKER here because is_busy()
// ignores DEFLATER_MARKER values.
ss->print("owner=" INTPTR_FORMAT, NULL);
}
}
ss->print(", cxq=" INTPTR_FORMAT ", EntryList=" INTPTR_FORMAT, p2i(_cxq),
p2i(_EntryList));
return ss->base();
}
@ -436,6 +524,20 @@ void ObjectMonitor::EnterI(TRAPS) {
return;
}
if (AsyncDeflateIdleMonitors &&
try_set_owner_from(DEFLATER_MARKER, Self) == DEFLATER_MARKER) {
// Cancelled the in-progress async deflation. We bump contentions an
// extra time to prevent the async deflater thread from temporarily
// changing it to -max_jint and back to zero (no flicker to confuse
// is_being_async_deflated()). The async deflater thread will
// decrement contentions after it recognizes that the async
// deflation was cancelled.
add_to_contentions(1);
assert(_succ != Self, "invariant");
assert(_Responsible != Self, "invariant");
return;
}
assert(InitDone, "Unexpectedly not initialized");
// We try one round of spinning *before* enqueueing Self.
@ -552,6 +654,18 @@ void ObjectMonitor::EnterI(TRAPS) {
if (TryLock(Self) > 0) break;
if (AsyncDeflateIdleMonitors &&
try_set_owner_from(DEFLATER_MARKER, Self) == DEFLATER_MARKER) {
// Cancelled the in-progress async deflation. We bump contentions an
// extra time to prevent the async deflater thread from temporarily
// changing it to -max_jint and back to zero (no flicker to confuse
// is_being_async_deflated()). The async deflater thread will
// decrement contentions after it recognizes that the async
// deflation was cancelled.
add_to_contentions(1);
break;
}
// The lock is still contested.
// Keep a tally of the # of futile wakeups.
// Note that the counter is not protected by a lock or updated by atomics.
@ -816,7 +930,7 @@ void ObjectMonitor::UnlinkAfterAcquire(Thread *Self, ObjectWaiter *SelfNode) {
// We'd like to assert that: (THREAD->thread_state() != _thread_blocked) ;
// There's one exception to the claim above, however. EnterI() can call
// exit() to drop a lock if the acquirer has been externally suspended.
// In that case exit() is called with _thread_state as _thread_blocked,
// In that case exit() is called with _thread_state == _thread_blocked,
// but the monitor's _contentions field is > 0, which inhibits reclamation.
//
// 1-0 exit
@ -1091,7 +1205,7 @@ void ObjectMonitor::ExitEpilog(Thread * Self, ObjectWaiter * Wakee) {
// out-of-scope (non-extant).
Wakee = NULL;
// Drop the lock
// Drop the lock.
// Uses a fence to separate release_store(owner) from the LD in unpark().
release_clear_owner(Self);
OrderAccess::fence();
@ -1139,16 +1253,19 @@ intx ObjectMonitor::complete_exit(TRAPS) {
// reenter() enters a lock and sets recursion count
// complete_exit/reenter operate as a wait without waiting
void ObjectMonitor::reenter(intx recursions, TRAPS) {
bool ObjectMonitor::reenter(intx recursions, TRAPS) {
Thread * const Self = THREAD;
assert(Self->is_Java_thread(), "Must be Java thread!");
JavaThread *jt = (JavaThread *)THREAD;
guarantee(_owner != Self, "reenter already owner");
enter(THREAD); // enter the monitor
if (!enter(THREAD)) {
return false;
}
// Entered the monitor.
guarantee(_recursions == 0, "reenter recursion");
_recursions = recursions;
return;
return true;
}
// Checks that the current THREAD owns this monitor and causes an
@ -1962,14 +2079,20 @@ void ObjectMonitor::print() const { print_on(tty); }
// (ObjectMonitor) 0x00007fdfb6012e40 = {
// _header = 0x0000000000000001
// _object = 0x000000070ff45fd0
// _next_om = 0x0000000000000000
// _allocation_state = Old
// _pad_buf0 = {
// [0] = '\0'
// ...
// [103] = '\0'
// [43] = '\0'
// }
// _owner = 0x0000000000000000
// _previous_owner_tid = 0
// _pad_buf1 = {
// [0] = '\0'
// ...
// [47] = '\0'
// }
// _next_om = 0x0000000000000000
// _recursions = 0
// _EntryList = 0x0000000000000000
// _cxq = 0x0000000000000000
@ -1987,7 +2110,17 @@ 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_cr(" _next_om = " INTPTR_FORMAT, p2i(next_om()));
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(" ...");
@ -1995,6 +2128,12 @@ void ObjectMonitor::print_debug_style_on(outputStream* st) const {
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(" _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));
@ -2002,7 +2141,7 @@ void ObjectMonitor::print_debug_style_on(outputStream* st) const {
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(" _contentions = %d", contentions());
st->print_cr(" _WaitSet = " INTPTR_FORMAT, p2i(_WaitSet));
st->print_cr(" _waiters = %d", _waiters);
st->print_cr(" _WaitSetLock = %d", _WaitSetLock);

View File

@ -136,13 +136,21 @@ class ObjectMonitor {
// Enforced by the assert() in header_addr().
volatile markWord _header; // displaced object header word - mark
void* volatile _object; // backward object pointer - strong root
private:
typedef enum {
Free = 0, // Free must be 0 for monitor to be free after memset(..,0,..).
New,
Old
} AllocationState;
AllocationState _allocation_state;
// Separate _header and _owner on different cache lines since both can
// have busy multi-threaded access. _header and _object are set at
// initial inflation and _object doesn't change until deflation so
// _object is a good choice to share the cache line with _header.
DEFINE_PAD_MINUS_SIZE(0, OM_CACHE_LINE_SIZE,
sizeof(volatile markWord) + sizeof(void* volatile));
// have busy multi-threaded access. _header, _object and _allocation_state
// are set at initial inflation. _object and _allocation_state don't
// change until deflation so _object and _allocation_state are good
// choices to share the cache line with _header.
DEFINE_PAD_MINUS_SIZE(0, OM_CACHE_LINE_SIZE, sizeof(volatile markWord) +
sizeof(void* volatile) + sizeof(AllocationState));
// Used by async deflation as a marker in the _owner field:
#define DEFLATER_MARKER reinterpret_cast<void*>(-1)
void* volatile _owner; // pointer to owning thread OR BasicLock
volatile jlong _previous_owner_tid; // thread id of the previous owner of the monitor
// Separate _owner and _next_om on different cache lines since
@ -164,9 +172,10 @@ class ObjectMonitor {
volatile int _Spinner; // for exit->spinner handoff optimization
volatile int _SpinDuration;
volatile jint _contentions; // Number of active contentions in enter(). It is used by is_busy()
jint _contentions; // Number of active contentions in enter(). It is used by is_busy()
// along with other fields to determine if an ObjectMonitor can be
// deflated. See ObjectSynchronizer::deflate_monitor().
// deflated. It is also used by the async deflation protocol. See
// ObjectSynchronizer::deflate_monitor() and deflate_monitor_using_JT().
protected:
ObjectWaiter* volatile _WaitSet; // LL of threads wait()ing on the monitor
volatile jint _waiters; // number of waiting threads
@ -233,17 +242,34 @@ class ObjectMonitor {
intptr_t is_busy() const {
// TODO-FIXME: assert _owner == null implies _recursions = 0
return _contentions|_waiters|intptr_t(_owner)|intptr_t(_cxq)|intptr_t(_EntryList);
intptr_t ret_code = _waiters | intptr_t(_cxq) | intptr_t(_EntryList);
if (!AsyncDeflateIdleMonitors) {
ret_code |= contentions() | intptr_t(_owner);
} else {
if (contentions() > 0) {
ret_code |= contentions();
}
if (_owner != DEFLATER_MARKER) {
ret_code |= intptr_t(_owner);
}
}
return ret_code;
}
const char* is_busy_to_string(stringStream* ss);
intptr_t is_entered(Thread* current) const;
void* owner() const;
void* owner() const; // Returns NULL if DEFLATER_MARKER is observed.
// Returns true if owner field == DEFLATER_MARKER and false otherwise.
bool owner_is_DEFLATER_MARKER();
// Returns true if 'this' is being async deflated and false otherwise.
bool is_being_async_deflated();
// Clear _owner field; current value must match old_value.
void release_clear_owner(void* old_value);
// Simply set _owner field to new_value; current value must match old_value.
void set_owner_from(void* old_value, void* new_value);
// Simply set _owner field to new_value; current value must match old_value1 or old_value2.
void set_owner_from(void* old_value1, void* old_value2, void* new_value);
// Simply set _owner field to self; current value must match basic_lock_p.
void set_owner_from_BasicLock(void* basic_lock_p, Thread* self);
// Try to set _owner field to new_value if the current value matches
@ -262,6 +288,7 @@ class ObjectMonitor {
jint waiters() const;
jint contentions() const;
void add_to_contentions(jint value);
intx recursions() const { return _recursions; }
// JVM/TI GetObjectMonitorUsage() needs this:
@ -286,7 +313,9 @@ class ObjectMonitor {
// _cxq == 0 _succ == NULL _owner == NULL _waiters == 0
// _contentions == 0 EntryList == NULL
// _recursions == 0 _WaitSet == NULL
DEBUG_ONLY(stringStream ss;)
#ifdef ASSERT
stringStream ss;
#endif
assert((is_busy() | _recursions) == 0, "freeing in-use monitor: %s, "
"recursions=" INTX_FORMAT, is_busy_to_string(&ss), _recursions);
_succ = NULL;
@ -301,13 +330,19 @@ class ObjectMonitor {
void* object() const;
void* object_addr();
void set_object(void* obj);
void set_allocation_state(AllocationState s);
AllocationState allocation_state() const;
bool is_free() const;
bool is_old() const;
bool is_new() const;
// Returns true if the specified thread owns the ObjectMonitor. Otherwise
// returns false and throws IllegalMonitorStateException (IMSE).
bool check_owner(Thread* THREAD);
void clear();
void clear_common();
void enter(TRAPS);
bool enter(TRAPS);
void exit(bool not_suspended, TRAPS);
void wait(jlong millis, bool interruptable, TRAPS);
void notify(TRAPS);
@ -321,7 +356,7 @@ class ObjectMonitor {
// Use the following at your own risk
intx complete_exit(TRAPS);
void reenter(intx recursions, TRAPS);
bool reenter(intx recursions, TRAPS);
private:
void AddWaiter(ObjectWaiter* waiter);
@ -332,10 +367,22 @@ class ObjectMonitor {
void ReenterI(Thread* self, ObjectWaiter* self_node);
void UnlinkAfterAcquire(Thread* self, ObjectWaiter* self_node);
int TryLock(Thread* self);
int NotRunnable(Thread* self, Thread * Owner);
int NotRunnable(Thread* self, Thread* Owner);
int TrySpin(Thread* self);
void ExitEpilog(Thread* self, ObjectWaiter* Wakee);
bool ExitSuspendEquivalent(JavaThread* self);
void install_displaced_markword_in_object(const oop obj);
};
// Macro to use guarantee() for more strict AsyncDeflateIdleMonitors
// checks and assert() otherwise.
#define ADIM_guarantee(p, ...) \
do { \
if (AsyncDeflateIdleMonitors) { \
guarantee(p, __VA_ARGS__); \
} else { \
assert(p, __VA_ARGS__); \
} \
} while (0)
#endif // SHARE_RUNTIME_OBJECTMONITOR_HPP

View File

@ -52,19 +52,51 @@ inline jint ObjectMonitor::waiters() const {
return _waiters;
}
// Returns NULL if DEFLATER_MARKER is observed.
inline void* ObjectMonitor::owner() const {
return _owner;
void* owner = _owner;
return owner != DEFLATER_MARKER ? owner : NULL;
}
// Returns true if owner field == DEFLATER_MARKER and false otherwise.
// 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 Atomic::load(&_owner) == DEFLATER_MARKER;
}
// Returns true if 'this' is being async deflated and false otherwise.
inline bool ObjectMonitor::is_being_async_deflated() {
return AsyncDeflateIdleMonitors && contentions() < 0;
}
inline void ObjectMonitor::clear() {
assert(Atomic::load(&_header).value() != 0, "must be non-zero");
assert(_contentions == 0, "must be 0: contentions=%d", _contentions);
assert(_waiters == 0, "must be 0: waiters=%d", _waiters);
assert(_recursions == 0, "must be 0: recursions=" INTX_FORMAT, _recursions);
assert(_object != NULL, "must be non-NULL");
assert(_owner == NULL, "must be NULL: owner=" INTPTR_FORMAT, p2i(_owner));
Atomic::store(&_header, markWord::zero());
clear_common();
}
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 list, we leave those three fields alone; contentions < 0
// will force any racing threads to retry. The header field is used
// by install_displaced_markword_in_object() to restore the object's
// header so we cannot check its value here.
guarantee(_owner == NULL || _owner == DEFLATER_MARKER,
"must be NULL or DEFLATER_MARKER: owner=" INTPTR_FORMAT,
p2i(_owner));
}
assert(contentions() <= 0, "must not be positive: contentions=%d", contentions());
assert(_waiters == 0, "must be 0: waiters=%d", _waiters);
assert(_recursions == 0, "must be 0: recursions=" INTX_FORMAT, _recursions);
assert(_object != NULL, "must be non-NULL");
set_allocation_state(Free);
_object = NULL;
}
@ -80,16 +112,21 @@ inline void ObjectMonitor::set_object(void* obj) {
_object = obj;
}
// return number of threads contending for this monitor
// Return number of threads contending for this monitor.
inline jint ObjectMonitor::contentions() const {
return _contentions;
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) {
DEBUG_ONLY(void* prev = Atomic::load(&_owner);)
assert(prev == old_value, "unexpected prev owner=" INTPTR_FORMAT
", expected=" INTPTR_FORMAT, p2i(prev), p2i(old_value));
void* prev = Atomic::load(&_owner);
ADIM_guarantee(prev == old_value, "unexpected prev owner=" INTPTR_FORMAT
", expected=" INTPTR_FORMAT, p2i(prev), p2i(old_value));
Atomic::release_store(&_owner, (void*)NULL);
log_trace(monitorinflation, owner)("release_clear_owner(): mid="
INTPTR_FORMAT ", old_value=" INTPTR_FORMAT,
@ -99,9 +136,9 @@ inline void ObjectMonitor::release_clear_owner(void* old_value) {
// Simply set _owner field to new_value; current value must match old_value.
// (Simple means no memory sync needed.)
inline void ObjectMonitor::set_owner_from(void* old_value, void* new_value) {
DEBUG_ONLY(void* prev = Atomic::load(&_owner);)
assert(prev == old_value, "unexpected prev owner=" INTPTR_FORMAT
", expected=" INTPTR_FORMAT, p2i(prev), p2i(old_value));
void* prev = Atomic::load(&_owner);
ADIM_guarantee(prev == old_value, "unexpected prev owner=" INTPTR_FORMAT
", expected=" INTPTR_FORMAT, p2i(prev), p2i(old_value));
Atomic::store(&_owner, new_value);
log_trace(monitorinflation, owner)("set_owner_from(): mid="
INTPTR_FORMAT ", old_value=" INTPTR_FORMAT
@ -109,11 +146,28 @@ inline void ObjectMonitor::set_owner_from(void* old_value, void* new_value) {
p2i(old_value), p2i(new_value));
}
// Simply set _owner field to new_value; current value must match old_value1 or old_value2.
// (Simple means no memory sync needed.)
inline void ObjectMonitor::set_owner_from(void* old_value1, void* old_value2, void* new_value) {
void* prev = Atomic::load(&_owner);
ADIM_guarantee(prev == old_value1 || prev == old_value2,
"unexpected prev owner=" INTPTR_FORMAT ", expected1="
INTPTR_FORMAT " or expected2=" INTPTR_FORMAT, p2i(prev),
p2i(old_value1), p2i(old_value2));
_owner = new_value;
log_trace(monitorinflation, owner)("set_owner_from(old1=" INTPTR_FORMAT
", old2=" INTPTR_FORMAT "): mid="
INTPTR_FORMAT ", prev=" INTPTR_FORMAT
", new=" INTPTR_FORMAT, p2i(old_value1),
p2i(old_value2), p2i(this), p2i(prev),
p2i(new_value));
}
// Simply set _owner field to self; current value must match basic_lock_p.
inline void ObjectMonitor::set_owner_from_BasicLock(void* basic_lock_p, Thread* self) {
DEBUG_ONLY(void* prev = Atomic::load(&_owner);)
assert(prev == basic_lock_p, "unexpected prev owner=" INTPTR_FORMAT
", expected=" INTPTR_FORMAT, p2i(prev), p2i(basic_lock_p));
void* prev = Atomic::load(&_owner);
ADIM_guarantee(prev == basic_lock_p, "unexpected prev owner=" INTPTR_FORMAT
", expected=" INTPTR_FORMAT, p2i(prev), p2i(basic_lock_p));
// Non-null owner field to non-null owner field is safe without
// cmpxchg() as long as all readers can tolerate either flavor.
Atomic::store(&_owner, self);
@ -137,6 +191,26 @@ inline void* ObjectMonitor::try_set_owner_from(void* old_value, void* new_value)
return prev;
}
inline void ObjectMonitor::set_allocation_state(ObjectMonitor::AllocationState s) {
_allocation_state = s;
}
inline ObjectMonitor::AllocationState ObjectMonitor::allocation_state() const {
return _allocation_state;
}
inline bool ObjectMonitor::is_free() const {
return _allocation_state == Free;
}
inline bool ObjectMonitor::is_old() const {
return _allocation_state == Old;
}
inline bool ObjectMonitor::is_new() const {
return _allocation_state == New;
}
// The _next_om field can be concurrently read and modified so we
// use Atomic operations to disable compiler optimizations that
// might try to elide loading and/or storing this field.

View File

@ -490,8 +490,9 @@ void SafepointSynchronize::end() {
}
bool SafepointSynchronize::is_cleanup_needed() {
// Need a safepoint if there are many monitors to deflate.
if (ObjectSynchronizer::is_cleanup_needed()) return true;
// Need a cleanup safepoint if there are too many monitors in use
// and the monitor deflation needs to be done at a safepoint.
if (ObjectSynchronizer::is_safepoint_deflation_needed()) return true;
// Need a safepoint if some inline cache buffers is non-empty
if (!InlineCacheBuffer::is_empty()) return true;
if (StringTable::needs_rehashing()) return true;
@ -510,6 +511,10 @@ public:
_counters(counters) {}
void do_thread(Thread* thread) {
// deflate_thread_local_monitors() handles or requests deflation of
// this thread's idle monitors. If !AsyncDeflateIdleMonitors or if
// there is a special cleanup request, deflation is handled now.
// Otherwise, async deflation is requested via a flag.
ObjectSynchronizer::deflate_thread_local_monitors(thread, _counters);
if (_nmethod_cl != NULL && thread->is_Java_thread() &&
! thread->is_Code_cache_sweeper_thread()) {
@ -542,7 +547,11 @@ public:
const char* name = "deflating global idle monitors";
EventSafepointCleanupTask event;
TraceTime timer(name, TRACETIME_LOG(Info, safepoint, cleanup));
ObjectSynchronizer::deflate_idle_monitors(_counters);
// AsyncDeflateIdleMonitors only uses DeflateMonitorCounters
// when a special cleanup has been requested.
// Note: This logging output will include global idle monitor
// elapsed times, but not global idle monitor deflation count.
ObjectSynchronizer::do_safepoint_work(_counters);
post_safepoint_cleanup_task_event(event, safepoint_id, name);
}

View File

@ -110,6 +110,7 @@ void ServiceThread::service_thread_entry(JavaThread* jt, TRAPS) {
bool thread_id_table_work = false;
bool protection_domain_table_work = false;
bool oopstorage_work = false;
bool deflate_idle_monitors = false;
JvmtiDeferredEvent jvmti_event;
{
// Need state transition ThreadBlockInVM so that this thread
@ -136,10 +137,14 @@ void ServiceThread::service_thread_entry(JavaThread* jt, TRAPS) {
(resolved_method_table_work = ResolvedMethodTable::has_work()) |
(thread_id_table_work = ThreadIdTable::has_work()) |
(protection_domain_table_work = SystemDictionary::pd_cache_table()->has_work()) |
(oopstorage_work = OopStorage::has_cleanup_work_and_reset())
(oopstorage_work = OopStorage::has_cleanup_work_and_reset()) |
(deflate_idle_monitors = ObjectSynchronizer::is_async_deflation_needed())
) == 0) {
// Wait until notified that there is some work to do.
ml.wait();
// If AsyncDeflateIdleMonitors, then we wait for
// GuaranteedSafepointInterval so that is_async_deflation_needed()
// is checked at the same interval.
ml.wait(AsyncDeflateIdleMonitors ? GuaranteedSafepointInterval : 0);
}
if (has_jvmti_events) {
@ -191,6 +196,10 @@ void ServiceThread::service_thread_entry(JavaThread* jt, TRAPS) {
if (oopstorage_work) {
cleanup_oopstorages();
}
if (deflate_idle_monitors) {
ObjectSynchronizer::deflate_idle_monitors_using_JT();
}
}
}

View File

@ -65,6 +65,7 @@
#include "runtime/javaCalls.hpp"
#include "runtime/sharedRuntime.hpp"
#include "runtime/stubRoutines.hpp"
#include "runtime/synchronizer.hpp"
#include "runtime/vframe.inline.hpp"
#include "runtime/vframeArray.hpp"
#include "utilities/copy.hpp"
@ -3070,10 +3071,15 @@ JRT_LEAF(intptr_t*, SharedRuntime::OSR_migration_begin( JavaThread *thread) )
kptr2 = fr.next_monitor_in_interpreter_frame(kptr2) ) {
if (kptr2->obj() != NULL) { // Avoid 'holes' in the monitor array
BasicLock *lock = kptr2->lock();
// Inflate so the displaced header becomes position-independent
if (lock->displaced_header().is_unlocked())
// Inflate so the object's header no longer refers to the BasicLock.
if (lock->displaced_header().is_unlocked()) {
// The object is locked and the resulting ObjectMonitor* will also be
// locked so it can't be async deflated until ownership is dropped.
// See the big comment in basicLock.cpp: BasicLock::move_to().
ObjectSynchronizer::inflate_helper(kptr2->obj());
// Now the displaced header is free to move
}
// Now the displaced header is free to move because the
// object's header no longer refers to it.
buf[i++] = (intptr_t)lock->displaced_header().value();
buf[i++] = cast_from_oop<intptr_t>(kptr2->obj());
}

File diff suppressed because it is too large Load Diff

View File

@ -43,11 +43,11 @@ class ThreadsList;
typedef PaddedEnd<ObjectMonitor, OM_CACHE_LINE_SIZE> PaddedObjectMonitor;
struct DeflateMonitorCounters {
int n_in_use; // currently associated with objects
int n_in_circulation; // extant
int n_scavenged; // reclaimed (global and per-thread)
int per_thread_scavenged; // per-thread scavenge total
double per_thread_times; // per-thread scavenge times
volatile int n_in_use; // currently associated with objects
volatile int n_in_circulation; // extant
volatile int n_scavenged; // reclaimed (global and per-thread)
volatile int per_thread_scavenged; // per-thread scavenge total
double per_thread_times; // per-thread scavenge times
};
class ObjectSynchronizer : AllStatic {
@ -132,6 +132,10 @@ class ObjectSynchronizer : AllStatic {
// Basically we deflate all monitors that are not busy.
// An adaptive profile-based deflation policy could be used if needed
static void deflate_idle_monitors(DeflateMonitorCounters* counters);
static void deflate_idle_monitors_using_JT();
static void deflate_global_idle_monitors_using_JT();
static void deflate_per_thread_idle_monitors_using_JT(JavaThread* target);
static void deflate_common_idle_monitors_using_JT(bool is_global, JavaThread* target);
static void deflate_thread_local_monitors(Thread* thread, DeflateMonitorCounters* counters);
static void prepare_deflate_idle_monitors(DeflateMonitorCounters* counters);
static void finish_deflate_idle_monitors(DeflateMonitorCounters* counters);
@ -141,10 +145,26 @@ class ObjectSynchronizer : AllStatic {
int* count_p,
ObjectMonitor** free_head_p,
ObjectMonitor** free_tail_p);
// For a given in-use monitor list: global or per-thread, deflate idle
// monitors using a JavaThread.
static int deflate_monitor_list_using_JT(ObjectMonitor** list_p,
int* count_p,
ObjectMonitor** free_head_p,
ObjectMonitor** free_tail_p,
ObjectMonitor** saved_mid_in_use_p);
static bool deflate_monitor(ObjectMonitor* mid, oop obj,
ObjectMonitor** free_head_p,
ObjectMonitor** free_tail_p);
static bool is_cleanup_needed();
static bool deflate_monitor_using_JT(ObjectMonitor* mid,
ObjectMonitor** free_head_p,
ObjectMonitor** free_tail_p);
static bool is_async_deflation_needed();
static bool is_safepoint_deflation_needed();
static bool is_async_deflation_requested() { return _is_async_deflation_requested; }
static bool is_special_deflation_requested() { return _is_special_deflation_requested; }
static void set_is_async_deflation_requested(bool new_value) { _is_async_deflation_requested = new_value; }
static void set_is_special_deflation_requested(bool new_value) { _is_special_deflation_requested = new_value; }
static jlong time_since_last_async_deflation_ms();
static void oops_do(OopClosure* f);
// Process oops in thread local used monitors
static void thread_local_used_oops_do(Thread* thread, OopClosure* f);
@ -155,6 +175,8 @@ class ObjectSynchronizer : AllStatic {
outputStream * out, int *error_cnt_p);
static void chk_global_free_list_and_count(outputStream * out,
int *error_cnt_p);
static void chk_global_wait_list_and_count(outputStream * out,
int *error_cnt_p);
static void chk_global_in_use_list_and_count(outputStream * out,
int *error_cnt_p);
static void chk_in_use_entry(JavaThread* jt, ObjectMonitor* n,
@ -169,12 +191,17 @@ class ObjectSynchronizer : AllStatic {
static int log_monitor_list_counts(outputStream * out);
static int verify_objmon_isinpool(ObjectMonitor *addr) PRODUCT_RETURN0;
static void do_safepoint_work(DeflateMonitorCounters* counters);
private:
friend class SynchronizerTest;
enum { _BLOCKSIZE = 128 };
// global list of blocks of monitors
static PaddedObjectMonitor* g_block_list;
static volatile bool _is_async_deflation_requested;
static volatile bool _is_special_deflation_requested;
static jlong _last_async_deflation_time_ns;
// Function to prepend new blocks to the appropriate lists:
static void prepend_block_to_lists(PaddedObjectMonitor* new_blk);

View File

@ -4692,6 +4692,8 @@ GrowableArray<JavaThread*>* Threads::get_pending_threads(ThreadsList * t_list,
DO_JAVA_THREADS(t_list, p) {
if (!p->can_call_java()) continue;
// The first stage of async deflation does not affect any field
// used by this comparison so the ObjectMonitor* is usable here.
address pending = (address)p->current_pending_monitor();
if (pending == monitor) { // found a match
if (i < count) result->append(p); // save the first count matches

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2020, 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
@ -122,8 +122,14 @@ GrowableArray<MonitorInfo*>* javaVFrame::locked_monitors() {
if (mons->is_empty()) return result;
bool found_first_monitor = false;
ObjectMonitor *pending_monitor = thread()->current_pending_monitor();
// 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 exit the ObjectMonitor so it remains busy.
ObjectMonitor *waiting_monitor = thread()->current_waiting_monitor();
ObjectMonitor *pending_monitor = NULL;
if (waiting_monitor == NULL) {
pending_monitor = thread()->current_pending_monitor();
}
oop pending_obj = (pending_monitor != NULL ? (oop) pending_monitor->object() : (oop) NULL);
oop waiting_obj = (waiting_monitor != NULL ? (oop) waiting_monitor->object() : (oop) NULL);
@ -231,6 +237,8 @@ void javaVFrame::print_lock_info_on(outputStream* st, int frame_count) {
// an inflated monitor that is first on the monitor list in
// the first frame can block us on a monitor enter.
markWord mark = monitor->owner()->mark();
// The first stage of async deflation does not affect any field
// used by this comparison so the ObjectMonitor* is usable here.
if (mark.has_monitor() &&
( // we have marked ourself as pending on this monitor
mark.monitor() == thread()->current_pending_monitor() ||

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2020, 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
@ -41,6 +41,7 @@
#include "runtime/frame.inline.hpp"
#include "runtime/interfaceSupport.inline.hpp"
#include "runtime/sweeper.hpp"
#include "runtime/synchronizer.hpp"
#include "runtime/thread.inline.hpp"
#include "runtime/threadSMR.inline.hpp"
#include "runtime/vmOperations.hpp"
@ -433,6 +434,17 @@ int VM_Exit::wait_for_threads_in_native_to_block() {
}
}
bool VM_Exit::doit_prologue() {
if (AsyncDeflateIdleMonitors && log_is_enabled(Info, monitorinflation)) {
// AsyncDeflateIdleMonitors does a special deflation at the VM_Exit
// safepoint in order to reduce the in-use monitor population that
// is reported by ObjectSynchronizer::log_in_use_monitor_details()
// at VM exit.
ObjectSynchronizer::set_is_special_deflation_requested(true);
}
return true;
}
void VM_Exit::doit() {
if (VerifyBeforeExit) {

View File

@ -420,6 +420,7 @@ class VM_Exit: public VM_Operation {
}
}
VMOp_Type type() const { return VMOp_Exit; }
bool doit_prologue();
void doit();
};

View File

@ -94,6 +94,7 @@
#include "runtime/serviceThread.hpp"
#include "runtime/sharedRuntime.hpp"
#include "runtime/stubRoutines.hpp"
#include "runtime/synchronizer.hpp"
#include "runtime/thread.inline.hpp"
#include "runtime/threadSMR.hpp"
#include "runtime/vframeArray.hpp"
@ -899,14 +900,14 @@ typedef HashtableEntry<InstanceKlass*, mtClass> KlassHashtableEntry;
volatile_nonstatic_field(ObjectMonitor, _header, markWord) \
unchecked_nonstatic_field(ObjectMonitor, _object, sizeof(void *)) /* NOTE: no type */ \
unchecked_nonstatic_field(ObjectMonitor, _owner, sizeof(void *)) /* NOTE: no type */ \
volatile_nonstatic_field(ObjectMonitor, _contentions, jint) \
volatile_nonstatic_field(ObjectMonitor, _next_om, ObjectMonitor*) \
volatile_nonstatic_field(BasicLock, _displaced_header, markWord) \
nonstatic_field(ObjectMonitor, _contentions, jint) \
volatile_nonstatic_field(ObjectMonitor, _waiters, jint) \
volatile_nonstatic_field(ObjectMonitor, _recursions, intx) \
nonstatic_field(ObjectMonitor, _next_om, ObjectMonitor*) \
volatile_nonstatic_field(BasicLock, _displaced_header, markWord) \
nonstatic_field(BasicObjectLock, _lock, BasicLock) \
nonstatic_field(BasicObjectLock, _obj, oop) \
static_ptr_volatile_field(ObjectSynchronizer, g_block_list, PaddedObjectMonitor*) \
static_field(ObjectSynchronizer, g_block_list, PaddedObjectMonitor*) \
\
/*********************/ \
/* Matcher (C2 only) */ \

View File

@ -41,6 +41,7 @@
#include "runtime/mutexLocker.hpp"
#include "runtime/os.hpp"
#include "runtime/safepoint.hpp"
#include "runtime/synchronizer.hpp"
#include "runtime/thread.inline.hpp"
#include "runtime/vmThread.hpp"
#include "runtime/vmOperations.hpp"
@ -283,6 +284,14 @@ void VMThread::run() {
assert(should_terminate(), "termination flag must be set");
}
if (AsyncDeflateIdleMonitors && log_is_enabled(Info, monitorinflation)) {
// AsyncDeflateIdleMonitors does a special deflation at the final
// safepoint in order to reduce the in-use monitor population that
// is reported by ObjectSynchronizer::log_in_use_monitor_details()
// at VM exit.
ObjectSynchronizer::set_is_special_deflation_requested(true);
}
// 4526887 let VM thread exit at Safepoint
_cur_vm_operation = &halt_op;
SafepointSynchronize::begin();

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2003, 2020, 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
@ -208,19 +208,27 @@ Handle ThreadService::get_current_contended_monitor(JavaThread* thread) {
assert(thread != NULL, "should be non-NULL");
debug_only(Thread::check_for_dangling_thread_pointer(thread);)
// This function can be called on a target JavaThread that is not
// the caller and we are not at a safepoint. So it is possible for
// the waiting or pending condition to be over/stale and for the
// first stage of async deflation to clear the object field in
// the ObjectMonitor. It is also possible for the object to be
// inflated again and to be associated with a completely different
// ObjectMonitor by the time this object reference is processed
// by the caller.
ObjectMonitor *wait_obj = thread->current_waiting_monitor();
oop obj = NULL;
if (wait_obj != NULL) {
// thread is doing an Object.wait() call
obj = (oop) wait_obj->object();
assert(obj != NULL, "Object.wait() should have an object");
assert(AsyncDeflateIdleMonitors || obj != NULL, "Object.wait() should have an object");
} else {
ObjectMonitor *enter_obj = thread->current_pending_monitor();
if (enter_obj != NULL) {
// thread is trying to enter() an ObjectMonitor.
obj = (oop) enter_obj->object();
assert(obj != NULL, "ObjectMonitor should have an associated object!");
assert(AsyncDeflateIdleMonitors || obj != NULL, "ObjectMonitor should have an associated object!");
}
}
@ -391,6 +399,7 @@ DeadlockCycle* ThreadService::find_deadlocks_at_safepoint(ThreadsList * t_list,
cycle->reset();
// The ObjectMonitor* can't be async deflated since we are at a safepoint.
// When there is a deadlock, all the monitors involved in the dependency
// cycle must be contended and heavyweight. So we only care about the
// heavyweight monitor a thread is waiting to lock.
@ -967,13 +976,13 @@ void DeadlockCycle::print_on_with(ThreadsList * t_list, outputStream* st) const
st->print("=============================");
JavaThread* currentThread;
ObjectMonitor* waitingToLockMonitor;
JvmtiRawMonitor* waitingToLockRawMonitor;
oop waitingToLockBlocker;
int len = _threads->length();
for (int i = 0; i < len; i++) {
currentThread = _threads->at(i);
waitingToLockMonitor = currentThread->current_pending_monitor();
// The ObjectMonitor* can't be async deflated since we are at a safepoint.
ObjectMonitor* waitingToLockMonitor = currentThread->current_pending_monitor();
waitingToLockRawMonitor = currentThread->current_pending_raw_monitor();
waitingToLockBlocker = currentThread->current_park_blocker();
st->cr();

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2019, 2020, 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
@ -121,6 +121,10 @@ TEST_VM(markWord, printing) {
// This is no longer biased, because ObjectLocker revokes the bias.
assert_test_pattern(h_obj, "is_neutral no_hash");
// Hash the object then print it.
intx hash = h_obj->identity_hash();
assert_test_pattern(h_obj, "is_neutral hash=0x");
// Wait gets the lock inflated.
{
ObjectLocker ol(h_obj, THREAD);
@ -135,14 +139,18 @@ TEST_VM(markWord, printing) {
done.wait_with_safepoint_check(THREAD); // wait till the thread is done.
}
// Make the object older. Not all GCs use this field.
Universe::heap()->collect(GCCause::_java_lang_system_gc);
if (UseParallelGC) {
assert_test_pattern(h_obj, "is_neutral no_hash age 1");
}
if (!AsyncDeflateIdleMonitors) {
// With AsyncDeflateIdleMonitors, the collect() call below
// does not guarantee monitor deflation.
// Make the object older. Not all GCs use this field.
Universe::heap()->collect(GCCause::_java_lang_system_gc);
if (UseParallelGC) {
assert_test_pattern(h_obj, "is_neutral no_hash age 1");
}
// Hash the object then print it.
intx hash = h_obj->identity_hash();
assert_test_pattern(h_obj, "is_neutral hash=0x");
// Hash the object then print it.
intx hash = h_obj->identity_hash();
assert_test_pattern(h_obj, "is_neutral hash=0x");
}
}
#endif // PRODUCT

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2016, 2020, 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
@ -29,12 +29,17 @@
* @modules java.base/jdk.internal.misc
* java.management
* @run driver SafepointCleanupTest
* @run driver SafepointCleanupTest -XX:+AsyncDeflateIdleMonitors
*/
import jdk.test.lib.process.OutputAnalyzer;
import jdk.test.lib.process.ProcessTools;
public class SafepointCleanupTest {
static final String ASYNC_DISABLE_OPTION = "-XX:-AsyncDeflateIdleMonitors";
static final String ASYNC_ENABLE_OPTION = "-XX:+AsyncDeflateIdleMonitors";
static final String UNLOCK_DIAG_OPTION = "-XX:+UnlockDiagnosticVMOptions";
static void analyzeOutputOn(ProcessBuilder pb) throws Exception {
OutputAnalyzer output = new OutputAnalyzer(pb.start());
output.shouldContain("[safepoint,cleanup]");
@ -53,19 +58,40 @@ public class SafepointCleanupTest {
}
public static void main(String[] args) throws Exception {
String async_option;
if (args.length == 0) {
// By default test deflating idle monitors at a safepoint.
async_option = ASYNC_DISABLE_OPTION;
} else {
async_option = args[0];
}
if (!async_option.equals(ASYNC_DISABLE_OPTION) &&
!async_option.equals(ASYNC_ENABLE_OPTION)) {
throw new RuntimeException("Unknown async_option value: '"
+ async_option + "'");
}
ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-Xlog:safepoint+cleanup=info",
UNLOCK_DIAG_OPTION,
async_option,
InnerClass.class.getName());
analyzeOutputOn(pb);
pb = ProcessTools.createJavaProcessBuilder("-XX:+TraceSafepointCleanupTime",
UNLOCK_DIAG_OPTION,
async_option,
InnerClass.class.getName());
analyzeOutputOn(pb);
pb = ProcessTools.createJavaProcessBuilder("-Xlog:safepoint+cleanup=off",
UNLOCK_DIAG_OPTION,
async_option,
InnerClass.class.getName());
analyzeOutputOff(pb);
pb = ProcessTools.createJavaProcessBuilder("-XX:-TraceSafepointCleanupTime",
UNLOCK_DIAG_OPTION,
async_option,
InnerClass.class.getName());
analyzeOutputOff(pb);
}