8253064: monitor list simplifications and getting rid of TSM

Co-authored-by: Erik Österlund <eosterlund@openjdk.org>
Reviewed-by: eosterlund, rehn, coleenp
This commit is contained in:
Daniel D. Daugherty 2020-11-11 16:20:11 +00:00
parent 421a7c3b41
commit 2e19026d45
25 changed files with 817 additions and 1912 deletions

@ -25,9 +25,42 @@
#include "precompiled.hpp"
#include "oops/markWord.hpp"
#include "runtime/thread.inline.hpp"
#include "runtime/objectMonitor.hpp"
#include "runtime/objectMonitor.inline.hpp"
#include "utilities/ostream.hpp"
markWord markWord::displaced_mark_helper() const {
assert(has_displaced_mark_helper(), "check");
if (has_monitor()) {
// Has an inflated monitor. Must be checked before has_locker().
ObjectMonitor* monitor = this->monitor();
return monitor->header();
}
if (has_locker()) { // has a stack lock
BasicLock* locker = this->locker();
return locker->displaced_header();
}
// This should never happen:
fatal("bad header=" INTPTR_FORMAT, value());
return markWord(value());
}
void markWord::set_displaced_mark_helper(markWord m) const {
assert(has_displaced_mark_helper(), "check");
if (has_monitor()) {
// Has an inflated monitor. Must be checked before has_locker().
ObjectMonitor* monitor = this->monitor();
monitor->set_header(m);
return;
}
if (has_locker()) { // has a stack lock
BasicLock* locker = this->locker();
locker->set_displaced_header(m);
return;
}
// This should never happen:
fatal("bad header=" INTPTR_FORMAT, value());
}
void markWord::print_on(outputStream* st, bool print_monitor_info) const {
if (is_marked()) { // last bits = 11
st->print(" marked(" INTPTR_FORMAT ")", value());

@ -286,16 +286,8 @@ class markWord {
bool has_displaced_mark_helper() const {
return ((value() & unlocked_value) == 0);
}
markWord displaced_mark_helper() const {
assert(has_displaced_mark_helper(), "check");
uintptr_t ptr = (value() & ~monitor_value);
return *(markWord*)ptr;
}
void set_displaced_mark_helper(markWord m) const {
assert(has_displaced_mark_helper(), "check");
uintptr_t ptr = (value() & ~monitor_value);
((markWord*)ptr)->_value = m._value;
}
markWord displaced_mark_helper() const;
void set_displaced_mark_helper(markWord m) const;
markWord copy_set_hash(intptr_t hash) const {
uintptr_t tmp = value() & (~hash_mask_in_place);
tmp |= ((hash & hash_mask) << hash_shift);

@ -728,6 +728,20 @@ const intx ObjectAlignmentInBytes = 8;
"MonitorUsedDeflationThreshold is exceeded (0 is off).") \
range(0, max_jint) \
\
/* notice: the max range value here is max_jint, not max_intx */ \
/* because of overflow issue */ \
product(intx, AvgMonitorsPerThreadEstimate, 1024, DIAGNOSTIC, \
"Used to estimate a variable ceiling based on number of threads " \
"for use with MonitorUsedDeflationThreshold (0 is off).") \
range(0, max_jint) \
\
/* notice: the max range value here is max_jint, not max_intx */ \
/* because of overflow issue */ \
product(intx, MonitorDeflationMax, 1000000, DIAGNOSTIC, \
"The maximum number of monitors to deflate, unlink and delete " \
"at one time (minimum is 1024).") \
range(1024, max_jint) \
\
product(intx, MonitorUsedDeflationThreshold, 90, EXPERIMENTAL, \
"Percentage of used monitors before triggering deflation (0 is " \
"off). The check is performed on GuaranteedSafepointInterval " \

@ -0,0 +1,98 @@
/*
* Copyright (c) 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
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
#include "precompiled.hpp"
#include "classfile/javaClasses.hpp"
#include "runtime/interfaceSupport.inline.hpp"
#include "runtime/java.hpp"
#include "runtime/javaCalls.hpp"
#include "runtime/monitorDeflationThread.hpp"
#include "runtime/mutexLocker.hpp"
MonitorDeflationThread* MonitorDeflationThread::_instance = NULL;
void MonitorDeflationThread::initialize() {
EXCEPTION_MARK;
const char* name = "Monitor Deflation Thread";
Handle string = java_lang_String::create_from_str(name, CHECK);
// Initialize thread_oop to put it into the system threadGroup
Handle thread_group (THREAD, Universe::system_thread_group());
Handle thread_oop = JavaCalls::construct_new_instance(
SystemDictionary::Thread_klass(),
vmSymbols::threadgroup_string_void_signature(),
thread_group,
string,
CHECK);
{
MutexLocker mu(THREAD, Threads_lock);
MonitorDeflationThread* thread = new MonitorDeflationThread(&monitor_deflation_thread_entry);
// At this point it may be possible that no osthread was created for the
// JavaThread due to lack of memory. We would have to throw an exception
// in that case. However, since this must work and we do not allow
// exceptions anyway, check and abort if this fails.
if (thread == NULL || thread->osthread() == NULL) {
vm_exit_during_initialization("java.lang.OutOfMemoryError",
os::native_thread_creation_failed_msg());
}
java_lang_Thread::set_thread(thread_oop(), thread);
java_lang_Thread::set_priority(thread_oop(), NearMaxPriority);
java_lang_Thread::set_daemon(thread_oop());
thread->set_threadObj(thread_oop());
_instance = thread;
Threads::add(thread);
Thread::start(thread);
}
}
void MonitorDeflationThread::monitor_deflation_thread_entry(JavaThread* jt, TRAPS) {
while (true) {
{
// Need state transition ThreadBlockInVM so that this thread
// will be handled by safepoint correctly when this thread is
// notified at a safepoint.
// This ThreadBlockInVM object is not also considered to be
// suspend-equivalent because MonitorDeflationThread is not
// visible to external suspension.
ThreadBlockInVM tbivm(jt);
MonitorLocker ml(MonitorDeflation_lock, Mutex::_no_safepoint_check_flag);
while (!ObjectSynchronizer::is_async_deflation_needed()) {
// Wait until notified that there is some work to do.
// We wait for GuaranteedSafepointInterval so that
// is_async_deflation_needed() is checked at the same interval.
ml.wait(GuaranteedSafepointInterval);
}
}
(void)ObjectSynchronizer::deflate_idle_monitors();
}
}

@ -0,0 +1,48 @@
/*
* Copyright (c) 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
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
#ifndef SHARE_RUNTIME_MONITORDEFLATIONTHREAD_HPP
#define SHARE_RUNTIME_MONITORDEFLATIONTHREAD_HPP
#include "runtime/thread.hpp"
// A hidden from external view JavaThread for deflating idle monitors.
class MonitorDeflationThread : public JavaThread {
friend class VMStructs;
private:
static MonitorDeflationThread* _instance;
static void monitor_deflation_thread_entry(JavaThread* thread, TRAPS);
MonitorDeflationThread(ThreadFunction entry_point) : JavaThread(entry_point) {};
public:
static void initialize();
// Hide this thread from external view.
bool is_hidden_from_external_view() const { return true; }
bool is_monitor_deflation_thread() const { return true; }
};
#endif // SHARE_RUNTIME_MONITORDEFLATIONTHREAD_HPP

@ -116,6 +116,7 @@ Mutex* OldSets_lock = NULL;
Monitor* RootRegionScan_lock = NULL;
Mutex* Management_lock = NULL;
Monitor* MonitorDeflation_lock = NULL;
Monitor* Service_lock = NULL;
Monitor* Notification_lock = NULL;
Monitor* PeriodicTask_lock = NULL;
@ -244,6 +245,7 @@ void mutex_init() {
def(Patching_lock , PaddedMutex , special, true, _safepoint_check_never); // used for safepointing and code patching.
def(CompiledMethod_lock , PaddedMutex , special-1, true, _safepoint_check_never);
def(MonitorDeflation_lock , PaddedMonitor, tty-2, true, _safepoint_check_never); // used for monitor deflation thread operations
def(Service_lock , PaddedMonitor, tty-2, true, _safepoint_check_never); // used for service thread operations
if (UseNotificationThread) {

@ -111,6 +111,7 @@ extern Mutex* OldSets_lock; // protects the old region sets
extern Monitor* RootRegionScan_lock; // used to notify that the CM threads have finished scanning the IM snapshot regions
extern Mutex* Management_lock; // a lock used to serialize JVM management
extern Monitor* MonitorDeflation_lock; // a lock used for monitor deflation thread operation
extern Monitor* Service_lock; // a lock used for service thread operation
extern Monitor* Notification_lock; // a lock used for notification thread operation
extern Monitor* PeriodicTask_lock; // protects the periodic task structure

@ -265,6 +265,29 @@ static void check_object_context() {
#endif // ASSERT
}
ObjectMonitor::ObjectMonitor(oop object) :
_header(markWord::zero()),
_object(_oop_storage, object),
_owner(NULL),
_previous_owner_tid(0),
_next_om(NULL),
_recursions(0),
_EntryList(NULL),
_cxq(NULL),
_succ(NULL),
_Responsible(NULL),
_Spinner(0),
_SpinDuration(ObjectMonitor::Knob_SpinLimit),
_contentions(0),
_WaitSet(NULL),
_waiters(0),
_WaitSetLock(0)
{ }
ObjectMonitor::~ObjectMonitor() {
_object.release(_oop_storage);
}
oop ObjectMonitor::object() const {
check_object_context();
if (_object.is_null()) {
@ -280,15 +303,6 @@ oop ObjectMonitor::object_peek() const {
return _object.peek();
}
void ObjectMonitor::set_object(oop obj) {
check_object_context();
if (_object.is_null()) {
_object = WeakHandle(_oop_storage, obj);
} else {
_object.replace(obj);
}
}
// -----------------------------------------------------------------------------
// Enter support
@ -363,7 +377,10 @@ bool ObjectMonitor::enter(TRAPS) {
EventJavaMonitorEnter event;
if (event.should_commit()) {
event.set_monitorClass(object()->klass());
event.set_address((uintptr_t)object_addr());
// Set an address that is 'unique enough', such that events close in
// time and with the same address are likely (but not guaranteed) to
// belong to the same object.
event.set_address((uintptr_t)this);
}
{ // Change java thread status to indicate blocked on monitor enter.
@ -475,6 +492,110 @@ int ObjectMonitor::TryLock(Thread * Self) {
return -1;
}
// Deflate the specified ObjectMonitor if not in-use. Returns true if it
// was deflated and false otherwise.
//
// The async deflation protocol sets owner to DEFLATER_MARKER and
// makes contentions negative as signals to contending threads that
// an async deflation is in progress. There are a number of checks
// as part of the protocol to make sure that the calling thread has
// not lost the race to a contending thread.
//
// The ObjectMonitor has been successfully async deflated when:
// (contentions < 0)
// Contending threads that see that condition know to retry their operation.
//
bool ObjectMonitor::deflate_monitor() {
if (is_busy() != 0) {
// Easy checks are first - the ObjectMonitor is busy so no deflation.
return false;
}
if (ObjectSynchronizer::is_final_audit() && owner_is_DEFLATER_MARKER()) {
// The final audit can see an already deflated ObjectMonitor on the
// in-use list because MonitorList::unlink_deflated() might have
// blocked for the final safepoint before unlinking all the deflated
// monitors.
assert(contentions() < 0, "must be negative: contentions=%d", contentions());
// Already returned 'true' when it was originally deflated.
return false;
}
const oop obj = object_peek();
if (obj == NULL) {
// If the object died, we can recycle the monitor without racing with
// Java threads. The GC already broke the association with the object.
set_owner_from(NULL, DEFLATER_MARKER);
assert(contentions() >= 0, "must be non-negative: contentions=%d", contentions());
_contentions = -max_jint;
} else {
// Attempt async deflation protocol.
// Set a NULL owner to DEFLATER_MARKER to force any contending thread
// through the slow path. This is just the first part of the async
// deflation dance.
if (try_set_owner_from(NULL, DEFLATER_MARKER) != NULL) {
// The owner field is no longer NULL so we lost the race since the
// ObjectMonitor is now busy.
return false;
}
if (contentions() > 0 || _waiters != 0) {
// Another thread has raced to enter the ObjectMonitor after
// is_busy() above or has already entered and waited on
// it which makes it busy so no deflation. Restore owner to
// NULL if it is still DEFLATER_MARKER.
if (try_set_owner_from(DEFLATER_MARKER, NULL) != DEFLATER_MARKER) {
// Deferred decrement for the JT EnterI() that cancelled the async deflation.
add_to_contentions(-1);
}
return false;
}
// 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(&_contentions, (jint)0, -max_jint) != 0) {
// 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:
if (try_set_owner_from(DEFLATER_MARKER, NULL) != DEFLATER_MARKER) {
// Deferred decrement for the JT EnterI() that cancelled the async deflation.
add_to_contentions(-1);
}
return false;
}
}
// Sanity checks for the races:
guarantee(owner_is_DEFLATER_MARKER(), "must be deflater marker");
guarantee(contentions() < 0, "must be negative: contentions=%d",
contentions());
guarantee(_waiters == 0, "must be 0: waiters=%d", _waiters);
guarantee(_cxq == NULL, "must be no contending threads: cxq="
INTPTR_FORMAT, p2i(_cxq));
guarantee(_EntryList == NULL,
"must be no entering threads: EntryList=" INTPTR_FORMAT,
p2i(_EntryList));
if (obj != NULL) {
if (log_is_enabled(Trace, monitorinflation)) {
ResourceMark rm;
log_trace(monitorinflation)("deflate_monitor: object=" INTPTR_FORMAT
", mark=" INTPTR_FORMAT ", type='%s'",
p2i(obj), obj->mark().value(),
obj->klass()->external_name());
}
// Install the old mark word if nobody else has already done it.
install_displaced_markword_in_object(obj);
}
// We leave owner == DEFLATER_MARKER and contentions < 0
// to force any racing threads to retry.
return true; // Success, ObjectMonitor has been deflated.
}
// 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
@ -1351,7 +1472,10 @@ static void post_monitor_wait_event(EventJavaMonitorWait* event,
assert(monitor != NULL, "invariant");
event->set_monitorClass(monitor->object()->klass());
event->set_timeout(timeout);
event->set_address((uintptr_t)monitor->object_addr());
// Set an address that is 'unique enough', such that events close in
// time and with the same address are likely (but not guaranteed) to
// belong to the same object.
event->set_address((uintptr_t)monitor);
event->set_notifier(notifier_tid);
event->set_timedOut(timedout);
event->commit();
@ -2124,7 +2248,6 @@ void ObjectMonitor::print() const { print_on(tty); }
// (ObjectMonitor) 0x00007fdfb6012e40 = {
// _header = 0x0000000000000001
// _object = 0x000000070ff45fd0
// _allocation_state = Old
// _pad_buf0 = {
// [0] = '\0'
// ...
@ -2155,17 +2278,6 @@ 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_peek()));
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(" ...");

@ -127,7 +127,7 @@ class ObjectWaiter : public StackObj {
#define OM_CACHE_LINE_SIZE DEFAULT_CACHE_LINE_SIZE
#endif
class ObjectMonitor {
class ObjectMonitor : public CHeapObj<mtInternal> {
friend class ObjectSynchronizer;
friend class ObjectWaiter;
friend class VMStructs;
@ -139,20 +139,12 @@ class ObjectMonitor {
// Enforced by the assert() in header_addr().
volatile markWord _header; // displaced object header word - mark
WeakHandle _object; // backward object pointer
typedef enum {
Free = 0, // Free must be 0 for monitor to be free after memset(..,0,..).
New,
Old,
ChainMarker
} AllocationState;
AllocationState _allocation_state;
// Separate _header and _owner on different cache lines since both can
// 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.
// have busy multi-threaded access. _header and _object are set at initial
// inflation. The _object does not change, so it is a good choice to share
// its cache line with _header.
DEFINE_PAD_MINUS_SIZE(0, OM_CACHE_LINE_SIZE, sizeof(volatile markWord) +
sizeof(WeakHandle) + sizeof(AllocationState));
sizeof(WeakHandle));
// 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
@ -179,7 +171,7 @@ class ObjectMonitor {
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. It is also used by the async deflation protocol. See
// ObjectSynchronizer::deflate_monitor().
// ObjectMonitor::deflate_monitor().
protected:
ObjectWaiter* volatile _WaitSet; // LL of threads wait()ing on the monitor
volatile jint _waiters; // number of waiting threads
@ -268,8 +260,6 @@ class ObjectMonitor {
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
@ -301,55 +291,15 @@ class ObjectMonitor {
ObjectWaiter* next_waiter(ObjectWaiter* o) { return o->_next; }
Thread* thread_of_waiter(ObjectWaiter* o) { return o->_thread; }
protected:
// We don't typically expect or want the ctors or dtors to run.
// normal ObjectMonitors are type-stable and immortal.
ObjectMonitor() { ::memset((void*)this, 0, sizeof(*this)); }
~ObjectMonitor() {
// TODO: Add asserts ...
// _cxq == 0 _succ == NULL _owner == NULL _waiters == 0
// _contentions == 0 _EntryList == NULL etc
}
private:
void Recycle() {
// TODO: add stronger asserts ...
// _cxq == 0 _succ == NULL _owner == NULL _waiters == 0
// _contentions == 0 EntryList == NULL
// _recursions == 0 _WaitSet == NULL
#ifdef ASSERT
stringStream ss;
assert((is_busy() | _recursions) == 0, "freeing in-use monitor: %s, "
"recursions=" INTX_FORMAT, is_busy_to_string(&ss), _recursions);
#endif
_succ = NULL;
_EntryList = NULL;
_cxq = NULL;
_WaitSet = NULL;
_recursions = 0;
}
public:
ObjectMonitor(oop object);
~ObjectMonitor();
oop object() const;
oop object_peek() const;
oop* object_addr();
void set_object(oop obj);
void release_set_allocation_state(AllocationState s);
void set_allocation_state(AllocationState s);
AllocationState allocation_state() const;
AllocationState allocation_state_acquire() const;
bool is_free() const;
bool is_old() const;
bool is_new() const;
bool is_chainmarker() 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();
bool enter(TRAPS);
void exit(bool not_suspended, TRAPS);
@ -380,6 +330,9 @@ class ObjectMonitor {
int TrySpin(Thread* self);
void ExitEpilog(Thread* self, ObjectWaiter* Wakee);
bool ExitSuspendEquivalent(JavaThread* self);
// Deflation support
bool deflate_monitor();
void install_displaced_markword_in_object(const oop obj);
};

@ -42,7 +42,6 @@ inline markWord ObjectMonitor::header() const {
}
inline volatile markWord* ObjectMonitor::header_addr() {
assert((intptr_t)this == (intptr_t)&_header, "sync code expects this");
return &_header;
}
@ -72,37 +71,6 @@ inline bool ObjectMonitor::is_being_async_deflated() {
return contentions() < 0;
}
inline void ObjectMonitor::clear() {
assert(Atomic::load(&_header).value() != 0, "must be non-zero");
assert(_owner == NULL, "must be NULL: owner=" INTPTR_FORMAT, p2i(_owner));
Atomic::store(&_header, markWord::zero());
clear_common();
}
inline void ObjectMonitor::clear_common() {
// 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);
set_allocation_state(Free);
set_object(NULL);
}
inline oop* ObjectMonitor::object_addr() {
return (oop*)&_object;
}
// Return number of threads contending for this monitor.
inline jint ObjectMonitor::contentions() const {
return Atomic::load(&_contentions);
@ -141,23 +109,6 @@ 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);
assert(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) {
#ifdef ASSERT
@ -188,38 +139,6 @@ inline void* ObjectMonitor::try_set_owner_from(void* old_value, void* new_value)
return prev;
}
inline void ObjectMonitor::release_set_allocation_state(ObjectMonitor::AllocationState s) {
Atomic::release_store(&_allocation_state, s);
}
inline void ObjectMonitor::set_allocation_state(ObjectMonitor::AllocationState s) {
_allocation_state = s;
}
inline ObjectMonitor::AllocationState ObjectMonitor::allocation_state() const {
return _allocation_state;
}
inline ObjectMonitor::AllocationState ObjectMonitor::allocation_state_acquire() const {
return Atomic::load_acquire(&_allocation_state);
}
inline bool ObjectMonitor::is_free() const {
return _allocation_state == Free;
}
inline bool ObjectMonitor::is_old() const {
return allocation_state_acquire() == Old;
}
inline bool ObjectMonitor::is_new() const {
return _allocation_state == New;
}
inline bool ObjectMonitor::is_chainmarker() const {
return _allocation_state == ChainMarker;
}
// 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.

@ -544,11 +544,6 @@ public:
Threads::threads_do(&cl);
}
if (_subtasks.try_claim_task(SafepointSynchronize::SAFEPOINT_CLEANUP_DEFLATE_MONITORS)) {
Tracer t("deflating idle monitors");
ObjectSynchronizer::do_safepoint_work();
}
if (_subtasks.try_claim_task(SafepointSynchronize::SAFEPOINT_CLEANUP_UPDATE_INLINE_CACHES)) {
Tracer t("updating inline caches");
InlineCacheBuffer::update_inline_caches();
@ -610,6 +605,12 @@ void SafepointSynchronize::do_cleanup_tasks() {
}
assert(InlineCacheBuffer::is_empty(), "should have cleaned up ICBuffer");
if (log_is_enabled(Debug, monitorinflation)) {
// The VMThread calls do_final_audit_and_print_stats() which calls
// audit_and_print_stats() at the Info level at VM exit time.
ObjectSynchronizer::audit_and_print_stats(false /* on_exit */);
}
}
// Methods for determining if a JavaThread is safepoint safe.

@ -71,7 +71,6 @@ class SafepointSynchronize : AllStatic {
// The enums are listed in the order of the tasks when done serially.
enum SafepointCleanupTasks {
SAFEPOINT_CLEANUP_LAZY_ROOT_PROCESSING,
SAFEPOINT_CLEANUP_DEFLATE_MONITORS,
SAFEPOINT_CLEANUP_UPDATE_INLINE_CACHES,
SAFEPOINT_CLEANUP_COMPILATION_POLICY,
SAFEPOINT_CLEANUP_SYMBOL_TABLE_REHASH,

@ -143,7 +143,6 @@ 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;
bool oop_handles_to_release = false;
bool cldg_cleanup_work = false;
@ -174,13 +173,10 @@ void ServiceThread::service_thread_entry(JavaThread* jt, TRAPS) {
(protection_domain_table_work = SystemDictionary::pd_cache_table()->has_work()) |
(oopstorage_work = OopStorage::has_cleanup_work_and_reset()) |
(oop_handles_to_release = (_oop_handle_list != NULL)) |
(cldg_cleanup_work = ClassLoaderDataGraph::should_clean_metaspaces_and_reset()) |
(deflate_idle_monitors = ObjectSynchronizer::is_async_deflation_needed())
(cldg_cleanup_work = ClassLoaderDataGraph::should_clean_metaspaces_and_reset())
) == 0) {
// Wait until notified that there is some work to do.
// We wait for GuaranteedSafepointInterval so that
// is_async_deflation_needed() is checked at the same interval.
ml.wait(GuaranteedSafepointInterval);
ml.wait();
}
if (has_jvmti_events) {
@ -233,10 +229,6 @@ void ServiceThread::service_thread_entry(JavaThread* jt, TRAPS) {
cleanup_oopstorages();
}
if (deflate_idle_monitors) {
ObjectSynchronizer::deflate_idle_monitors();
}
if (oop_handles_to_release) {
release_oop_handles();
}

File diff suppressed because it is too large Load Diff

@ -31,19 +31,13 @@
#include "runtime/handles.hpp"
#include "runtime/perfData.hpp"
class LogStream;
class ObjectMonitor;
class ThreadsList;
#ifndef OM_CACHE_LINE_SIZE
// Use DEFAULT_CACHE_LINE_SIZE if not already specified for
// the current build platform.
#define OM_CACHE_LINE_SIZE DEFAULT_CACHE_LINE_SIZE
#endif
typedef PaddedEnd<ObjectMonitor, OM_CACHE_LINE_SIZE> PaddedObjectMonitor;
class ObjectSynchronizer : AllStatic {
friend class VMStructs;
public:
typedef enum {
owner_self,
@ -99,12 +93,6 @@ class ObjectSynchronizer : AllStatic {
static intx complete_exit(Handle obj, TRAPS);
static void reenter (Handle obj, intx recursions, TRAPS);
// thread-specific and global ObjectMonitor free list accessors
static ObjectMonitor* om_alloc(Thread* self);
static void om_release(Thread* self, ObjectMonitor* m,
bool FromPerThreadAlloc);
static void om_flush(Thread* self);
// Inflate light weight monitor to heavy weight monitor
static ObjectMonitor* inflate(Thread* self, oop obj, const InflateCause cause);
// This version is only for internal use
@ -127,23 +115,18 @@ class ObjectSynchronizer : AllStatic {
static void monitors_iterate(MonitorClosure* m);
// GC: we current use aggressive monitor deflation policy
// 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();
static void deflate_global_idle_monitors(Thread* self);
static void deflate_per_thread_idle_monitors(Thread* self,
JavaThread* target);
static void deflate_common_idle_monitors(Thread* self, bool is_global,
JavaThread* target);
// Basically we try to deflate all monitors that are not busy.
static size_t deflate_idle_monitors();
// For a given in-use monitor list: global or per-thread, deflate idle
// monitors.
static int deflate_monitor_list(Thread* self, 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, ObjectMonitor** free_head_p,
ObjectMonitor** free_tail_p);
// Deflate idle monitors:
static void chk_for_block_req(JavaThread* self, const char* op_name,
const char* cnt_name, size_t cnt, LogStream* ls,
elapsedTimer* timer_p);
static size_t deflate_monitor_list(Thread* self, LogStream* ls,
elapsedTimer* timer_p);
static size_t in_use_list_ceiling();
static void dec_in_use_list_ceiling();
static void inc_in_use_list_ceiling();
static bool is_async_deflation_needed();
static bool is_async_deflation_requested() { return _is_async_deflation_requested; }
static bool is_final_audit() { return _is_final_audit; }
@ -155,42 +138,19 @@ class ObjectSynchronizer : AllStatic {
// debugging
static void audit_and_print_stats(bool on_exit);
static void chk_free_entry(JavaThread* jt, ObjectMonitor* n,
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,
outputStream * out, int *error_cnt_p);
static void chk_per_thread_in_use_list_and_count(JavaThread *jt,
outputStream * out,
int *error_cnt_p);
static void chk_per_thread_free_list_and_count(JavaThread *jt,
outputStream * out,
int *error_cnt_p);
static void chk_in_use_list(outputStream* out, int* error_cnt_p);
static void chk_in_use_entry(ObjectMonitor* n, outputStream* out,
int* error_cnt_p);
static void do_final_audit_and_print_stats();
static void log_in_use_monitor_details(outputStream * out);
static int log_monitor_list_counts(outputStream * out);
static int verify_objmon_isinpool(ObjectMonitor *addr) PRODUCT_RETURN0;
static void do_safepoint_work();
static void log_in_use_monitor_details(outputStream* out);
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_final_audit;
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);
// Support for SynchronizerTest access to GVars fields:
static u_char* get_gvars_addr();
static u_char* get_gvars_hc_sequence_addr();

@ -81,6 +81,7 @@
#include "runtime/jniHandles.inline.hpp"
#include "runtime/jniPeriodicChecker.hpp"
#include "runtime/memprofiler.hpp"
#include "runtime/monitorDeflationThread.hpp"
#include "runtime/mutexLocker.hpp"
#include "runtime/objectMonitor.hpp"
#include "runtime/orderAccess.hpp"
@ -262,11 +263,6 @@ Thread::Thread() {
_current_pending_monitor_is_from_java = true;
_current_waiting_monitor = NULL;
_current_pending_raw_monitor = NULL;
om_free_list = NULL;
om_free_count = 0;
om_free_provision = 32;
om_in_use_list = NULL;
om_in_use_count = 0;
#ifdef ASSERT
_visited_for_critical_count = false;
@ -3691,6 +3687,9 @@ jint Threads::create_vm(JavaVMInitArgs* args, bool* canTryAgain) {
// and other cleanups. Needs to start before the compilers start posting events.
ServiceThread::initialize();
// Start the monitor deflation thread:
MonitorDeflationThread::initialize();
// initialize compiler(s)
#if defined(COMPILER1) || COMPILER2_OR_JVMCI
#if INCLUDE_JVMCI
@ -4233,6 +4232,9 @@ void Threads::add(JavaThread* p, bool force_daemon) {
// Maintain fast thread list
ThreadsSMRSupport::add_thread(p);
// Increase the ObjectMonitor ceiling for the new thread.
ObjectSynchronizer::inc_in_use_list_ceiling();
// Possible GC point.
Events::log(p, "Thread added: " INTPTR_FORMAT, p2i(p));
@ -4241,19 +4243,14 @@ void Threads::add(JavaThread* p, bool force_daemon) {
}
void Threads::remove(JavaThread* p, bool is_daemon) {
// Reclaim the ObjectMonitors from the om_in_use_list and om_free_list of the moribund thread.
ObjectSynchronizer::om_flush(p);
// Extra scope needed for Thread_lock, so we can check
// that we do not remove thread without safepoint code notice
{ MonitorLocker ml(Threads_lock);
// We must flush any deferred card marks and other various GC barrier
// related buffers (e.g. G1 SATB buffer and G1 dirty card queue buffer)
// before removing a thread from the list of active threads.
// This must be done after ObjectSynchronizer::om_flush(), as GC barriers
// are used in om_flush().
// BarrierSet state must be destroyed after the last thread transition
// before the thread terminates. Thread transitions result in calls to
// StackWatermarkSet::on_safepoint(), which performs GC processing,
// requiring the GC state to be alive.
BarrierSet::barrier_set()->on_thread_detach(p);
assert(ThreadsSMRSupport::get_java_thread_list()->includes(p), "p must be present");
@ -4283,6 +4280,9 @@ void Threads::remove(JavaThread* p, bool is_daemon) {
EscapeBarrier::thread_removed(p);
} // unlock Threads_lock
// Reduce the ObjectMonitor ceiling for the exiting thread.
ObjectSynchronizer::dec_in_use_list_ceiling();
// Since Events::log uses a lock, we grab it outside the Threads_lock
Events::log(p, "Thread exited: " INTPTR_FORMAT, p2i(p));
}

@ -416,14 +416,6 @@ class Thread: public ThreadShadow {
// ObjectMonitor on which this thread called Object.wait()
ObjectMonitor* _current_waiting_monitor;
// Per-thread ObjectMonitor lists:
public:
ObjectMonitor* om_free_list; // SLL of free ObjectMonitors
int om_free_count; // # on om_free_list
int om_free_provision; // # to try to allocate next
ObjectMonitor* om_in_use_list; // SLL of in-use ObjectMonitors
int om_in_use_count; // # on om_in_use_list
#ifdef ASSERT
private:
volatile uint64_t _visited_for_critical_count;
@ -485,6 +477,7 @@ class Thread: public ThreadShadow {
virtual bool is_Compiler_thread() const { return false; }
virtual bool is_Code_cache_sweeper_thread() const { return false; }
virtual bool is_service_thread() const { return false; }
virtual bool is_monitor_deflation_thread() const { return false; }
virtual bool is_hidden_from_external_view() const { return false; }
virtual bool is_jvmti_agent_thread() const { return false; }
// True iff the thread can perform GC operations at a safepoint.

@ -86,6 +86,7 @@
#include "runtime/globals.hpp"
#include "runtime/java.hpp"
#include "runtime/javaCalls.hpp"
#include "runtime/monitorDeflationThread.hpp"
#include "runtime/notificationThread.hpp"
#include "runtime/os.hpp"
#include "runtime/perfMemory.hpp"
@ -887,7 +888,6 @@ typedef HashtableEntry<InstanceKlass*, mtClass> KlassHashtableEntry;
volatile_nonstatic_field(ObjectMonitor, _recursions, intx) \
nonstatic_field(BasicObjectLock, _lock, BasicLock) \
nonstatic_field(BasicObjectLock, _obj, oop) \
static_field(ObjectSynchronizer, g_block_list, PaddedObjectMonitor*) \
\
/*********************/ \
/* Matcher (C2 only) */ \
@ -1338,6 +1338,7 @@ typedef HashtableEntry<InstanceKlass*, mtClass> KlassHashtableEntry;
declare_type(WatcherThread, NonJavaThread) \
declare_type(JavaThread, Thread) \
declare_type(JvmtiAgentThread, JavaThread) \
declare_type(MonitorDeflationThread, JavaThread) \
declare_type(ServiceThread, JavaThread) \
declare_type(NotificationThread, JavaThread) \
declare_type(CompilerThread, JavaThread) \
@ -1462,7 +1463,6 @@ typedef HashtableEntry<InstanceKlass*, mtClass> KlassHashtableEntry;
/************/ \
\
declare_toplevel_type(ObjectMonitor) \
declare_toplevel_type(PaddedObjectMonitor) \
declare_toplevel_type(ObjectSynchronizer) \
declare_toplevel_type(BasicLock) \
declare_toplevel_type(BasicObjectLock) \
@ -1993,7 +1993,6 @@ typedef HashtableEntry<InstanceKlass*, mtClass> KlassHashtableEntry;
declare_toplevel_type(nmethod*) \
COMPILER2_PRESENT(declare_unsigned_integer_type(node_idx_t)) \
declare_toplevel_type(ObjectMonitor*) \
declare_toplevel_type(PaddedObjectMonitor*) \
declare_toplevel_type(oop*) \
declare_toplevel_type(OopMapCache*) \
declare_toplevel_type(VMReg) \
@ -2522,12 +2521,6 @@ typedef HashtableEntry<InstanceKlass*, mtClass> KlassHashtableEntry;
declare_constant(JNIHandleBlock::block_size_in_oops) \
\
/**********************/ \
/* ObjectSynchronizer */ \
/**********************/ \
\
declare_constant(ObjectSynchronizer::_BLOCKSIZE) \
\
/**********************/ \
/* PcDesc */ \
/**********************/ \
\

@ -0,0 +1,41 @@
/*
* Copyright (c) 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
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
package sun.jvm.hotspot.runtime;
import java.io.*;
import sun.jvm.hotspot.debugger.*;
import sun.jvm.hotspot.types.*;
public class MonitorDeflationThread extends JavaThread {
public MonitorDeflationThread(Address addr) {
super(addr);
}
public boolean isJavaThread() { return false; }
public boolean isHiddenFromExternalView() { return true; }
public boolean isMonitorDeflationThread() { return true; }
}

@ -103,10 +103,6 @@ public class ObjectMonitor extends VMObject {
return contentionsField.getValue(addr);
}
// FIXME
// oop* object_addr();
// void set_object(oop obj);
// The following four either aren't expressed as typed fields in
// vmStructs.cpp because they aren't strongly typed in the VM, or
// would confuse the SA's type system.

@ -121,6 +121,7 @@ public class Thread extends VMObject {
public boolean isJvmtiAgentThread() { return false; }
public boolean isWatcherThread() { return false; }
public boolean isServiceThread() { return false; }
public boolean isMonitorDeflationThread() { return false; }
/** Memory operations */
public void oopsDo(AddressVisitor oopVisitor) {

@ -149,6 +149,7 @@ public class Threads {
}
virtualConstructor.addMapping("JvmtiAgentThread", JvmtiAgentThread.class);
virtualConstructor.addMapping("ServiceThread", ServiceThread.class);
virtualConstructor.addMapping("MonitorDeflationThread", MonitorDeflationThread.class);
virtualConstructor.addMapping("NotificationThread", NotificationThread.class);
}
@ -157,7 +158,7 @@ public class Threads {
}
/** NOTE: this returns objects of type JavaThread, CompilerThread,
JvmtiAgentThread, NotificationThread, and ServiceThread.
JvmtiAgentThread, NotificationThread, MonitorDeflationThread and ServiceThread.
The latter four are subclasses of the former. Most operations
(fetching the top frame, etc.) are only allowed to be performed on
a "pure" JavaThread. For this reason, {@link
@ -188,7 +189,7 @@ public class Threads {
return thread;
} catch (Exception e) {
throw new RuntimeException("Unable to deduce type of thread from address " + threadAddr +
" (expected type JavaThread, CompilerThread, ServiceThread, JvmtiAgentThread or CodeCacheSweeperThread)", e);
" (expected type JavaThread, CompilerThread, MonitorDeflationThread, ServiceThread, JvmtiAgentThread or CodeCacheSweeperThread)", e);
}
}

@ -27,9 +27,6 @@
#include "unittest.hpp"
TEST_VM(ObjectMonitor, sanity) {
EXPECT_EQ(0, ObjectMonitor::header_offset_in_bytes()) << "Offset for _header must be zero.";
uint cache_line_size = VM_Version::L1_data_cache_line_size();
if (cache_line_size != 0) {

@ -39,7 +39,6 @@ public class SafepointCleanupTest {
OutputAnalyzer output = new OutputAnalyzer(pb.start());
output.shouldContain("[safepoint,cleanup]");
output.shouldContain("safepoint cleanup tasks");
output.shouldContain("deflating idle monitors");
output.shouldContain("updating inline caches");
output.shouldContain("compilation policy safepoint handler");
output.shouldHaveExitValue(0);

@ -59,7 +59,6 @@ public class ClhsdbPrintStatics {
"Abstract_VM_Version::_vm_major_version",
"ClassLoaderDataGraph::_head",
"JNIHandles::_weak_global_handles", "PerfMemory::_top",
"ObjectSynchronizer::g_block_list",
"java_lang_Class::_oop_size_offset"));
expStrMap.put("printstatics SystemDictionary", List.of(
"Static fields of SystemDictionary",