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:
parent
421a7c3b41
commit
2e19026d45
src
hotspot/share
oops
runtime
jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime
test/hotspot
gtest/runtime
jtreg
@ -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 " \
|
||||
|
98
src/hotspot/share/runtime/monitorDeflationThread.cpp
Normal file
98
src/hotspot/share/runtime/monitorDeflationThread.cpp
Normal file
@ -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();
|
||||
}
|
||||
}
|
48
src/hotspot/share/runtime/monitorDeflationThread.hpp
Normal file
48
src/hotspot/share/runtime/monitorDeflationThread.hpp
Normal file
@ -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 */ \
|
||||
/**********************/ \
|
||||
\
|
||||
|
41
src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/MonitorDeflationThread.java
Normal file
41
src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/MonitorDeflationThread.java
Normal file
@ -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",
|
||||
|
Loading…
x
Reference in New Issue
Block a user