/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* 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/vmSymbols.hpp"
#include "memory/resourceArea.hpp"
#include "oops/markOop.hpp"
#include "oops/oop.inline.hpp"
#include "runtime/biasedLocking.hpp"
#include "runtime/handles.inline.hpp"
#include "runtime/interfaceSupport.hpp"
#include "runtime/mutexLocker.hpp"
#include "runtime/objectMonitor.hpp"
#include "runtime/objectMonitor.inline.hpp"
#include "runtime/osThread.hpp"
#include "runtime/stubRoutines.hpp"
#include "runtime/synchronizer.hpp"
#include "utilities/dtrace.hpp"
#include "utilities/events.hpp"
#include "utilities/preserveException.hpp"
#ifdef TARGET_OS_FAMILY_linux
# include "os_linux.inline.hpp"
# include "thread_linux.inline.hpp"
#endif
#ifdef TARGET_OS_FAMILY_solaris
# include "os_solaris.inline.hpp"
# include "thread_solaris.inline.hpp"
#endif
#ifdef TARGET_OS_FAMILY_windows
# include "os_windows.inline.hpp"
# include "thread_windows.inline.hpp"
#endif
#ifdef TARGET_OS_FAMILY_bsd
# include "os_bsd.inline.hpp"
# include "thread_bsd.inline.hpp"
#endif
// Need to inhibit inlining for older versions of GCC to avoid build-time failures
#else
#define ATTR
#endif
// The "core" versions of monitor enter and exit reside in this file.
// The interpreter and compilers contain specialized transliterated
// variants of the enter-exit fast-path operations. See i486.ad fast_lock(),
// for instance. If you make changes here, make sure to modify the
// interpreter, and both C1 and C2 fast-path inline locking code emission.
//
//
// -----------------------------------------------------------------------------
#ifdef DTRACE_ENABLED
// Only bother with this argument setup if dtrace is available
// TODO-FIXME: probes should not fire when caller is _blocked. assert() accordingly.
int len = 0; \
}
#ifndef USDT2
{ \
if (DTraceMonitorProbes) { \
} \
}
{ \
if (DTraceMonitorProbes) { \
} \
}
#else /* USDT2 */
{ \
if (DTraceMonitorProbes) { \
} \
}
{ \
if (DTraceMonitorProbes) { \
} \
}
#endif /* USDT2 */
#else // ndef DTRACE_ENABLED
#endif // ndef DTRACE_ENABLED
// This exists only as a workaround of dtrace bug 6254741
return 0;
}
// -----------------------------------------------------------------------------
// This the fast monitor enter. The interpreter and compiler use
// some assembly copies of this code. Make sure update those code
// if the following function is changed. The implementation is
// extremely sensitive to race condition. Be careful.
if (UseBiasedLocking) {
if (!SafepointSynchronize::is_at_safepoint()) {
return;
}
} else {
}
}
}
// if displaced header is null, the previous enter is recursive enter, no-op
// Recursive stack-lock.
// Diagnostics -- Could be: stack-locked, inflating, inflated.
}
if (mark->has_monitor()) {
}
return ;
}
// If the object is stack-locked by the current thread, try to
// swing the displaced header from the box back to the mark.
return;
}
}
}
// -----------------------------------------------------------------------------
// Interpreter/Compiler Slow Case
// This routine is used to handle interpreter/compiler slow case
// We don't need to use fast path here, because it must have been
// failed in the interpreter/compiler code.
if (mark->is_neutral()) {
// Anticipate successful CAS -- the ST of the displaced mark must
// be visible <= the ST performed by the CAS.
return ;
}
// Fall through to inflate() ...
} else
return;
}
#if 0
// The following optimization isn't particularly useful.
return ;
}
#endif
// The object header will never be displaced to this lock,
// so it does not matter what the value is, except that it
// must be non-zero to avoid looking like a re-entrant lock,
// and must not look locked either.
}
// This routine is used to handle interpreter/compiler slow case
// We don't need to use fast path here, because it must have
// failed in the interpreter/compiler code. Simply use the heavy
// weight monitor should be ok, unless someone find otherwise.
}
// -----------------------------------------------------------------------------
// Class Loader support to workaround deadlocks on the class loader lock objects
// Also used by GC
// complete_exit()/reenter() are used to wait on a nested lock
// i.e. to give up an outer lock completely and then re-enter
// Used when holding nested locks - lock acquisition order: lock1 then lock2
// 1) complete_exit lock1 - saving recursion count
// 2) wait on lock2
// 3) when notified on lock2, unlock lock2
// 4) reenter lock1 with original recursion count
// 5) lock lock2
// NOTE: must use heavy weight monitor to handle complete_exit/reenter()
TEVENT (complete_exit) ;
if (UseBiasedLocking) {
}
}
// NOTE: must use heavy weight monitor to handle complete_exit/reenter()
if (UseBiasedLocking) {
}
}
// -----------------------------------------------------------------------------
// JNI locks on java objects
// NOTE: must use heavy weight monitor to handle jni monitor enter
// the current locking is from JNI instead of Java code
if (UseBiasedLocking) {
}
}
// NOTE: must use heavy weight monitor to handle jni monitor enter
if (UseBiasedLocking) {
}
}
// NOTE: must use heavy weight monitor to handle jni monitor exit
if (UseBiasedLocking) {
}
// If this thread has locked the object, exit the monitor. Note: can't use
// monitor->check(CHECK); must exit even if an exception is pending.
}
}
// -----------------------------------------------------------------------------
// Internal VM locks on java objects
// standard constructor, allows locking failures
if (_dolock) {
TEVENT (ObjectLocker) ;
}
}
ObjectLocker::~ObjectLocker() {
if (_dolock) {
}
}
// -----------------------------------------------------------------------------
// NOTE: must use heavy weight monitor to handle wait()
if (UseBiasedLocking) {
}
if (millis < 0) {
}
/* This dummy call is in place to get around dtrace bug 6254741. Once
that's fixed we can uncomment the following line and remove the call */
// DTRACE_MONITOR_PROBE(waited, monitor, obj(), THREAD);
}
if (UseBiasedLocking) {
}
if (millis < 0) {
}
}
if (UseBiasedLocking) {
}
return;
}
}
// NOTE: see comment of notify()
if (UseBiasedLocking) {
}
return;
}
}
// -----------------------------------------------------------------------------
// Hash Code handling
//
// Performance concern:
// OrderAccess::storestore() calls release() which STs 0 into the global volatile
// OrderAccess::Dummy variable. This store is unnecessary for correctness.
// Many threads STing into a common location causes considerable cache migration
// or "sloshing" on large SMP system. As such, I avoid using OrderAccess::storestore()
// until it's repaired. In some cases OrderAccess::fence() -- which incurs local
// latency on the executing processor -- is a better choice as it scales on SMP
// systems. See http://blogs.sun.com/dave/entry/biased_locking_in_hotspot for a
// discussion of coherency costs. Note that all our current reference platforms
// provide strong ST-ST order, so the issue is moot on IA32, x64, and SPARC.
//
// As a general policy we use "volatile" to control compiler-based reordering
// and explicit fences (barriers) to control for architectural reordering performed
// by the CPU(s) or platform.
struct SharedGlobals {
// These are highly shared mostly-read variables.
// To avoid false-sharing they need to be the sole occupants of a $ line.
volatile int stwRandom ;
volatile int stwCycle ;
// Hot RW variables -- Sequester to avoid false-sharing
volatile int hcSequence ;
} ;
if (!mark->is_being_inflated()) {
return mark ; // normal fast-path return
}
int its = 0 ;
for (;;) {
if (!mark->is_being_inflated()) {
return mark ; // normal fast-path return
}
// The object is being inflated by some other thread.
// The caller of ReadStableMark() must wait for inflation to complete.
// Avoid live-lock
// TODO: consider calling SafepointSynchronize::do_call_back() while
// spinning to see if there's a safepoint pending. If so, immediately
// yielding or blocking would be appropriate. Avoid spinning while
// there is a safepoint pending.
// TODO: add inflation contention performance counters.
// TODO: restrict the aggregate number of spinners.
++its ;
if (its & 1) {
os::NakedYield() ;
} else {
// Note that the following code attenuates the livelock problem but is not
// a complete remedy. A more complete solution would require that the inflating
// thread hold the associated inflation lock. The following code simply restricts
// the number of spinners to at most one. We'll have N-2 threads blocked
// on the inflationlock, 1 thread holding the inflation lock and using
// A more refined approach would be to change the encoding of INFLATING
// to allow encapsulation of a native thread pointer. Threads waiting for
// inflation to complete would use CAS to push themselves onto a singly linked
// list rooted at the markword. Once enqueued, they'd loop, checking a per-thread flag
// and calling park(). When inflation was complete the thread that accomplished inflation
// would detach the list and set the markword to inflated with a single CAS and
// then for each thread on the list, set the flag and unpark() the thread.
// This is conceptually similar to muxAcquire-muxRelease, except that muxRelease
// wakes at most one thread whereas we need to wake the entire list.
int YieldThenBlock = 0 ;
// Beware: NakedYield() is advisory and has almost no effect on some platforms
// so we periodically call Self->_ParkEvent->park(1).
if ((YieldThenBlock++) >= 16) {
} else {
os::NakedYield() ;
}
}
}
} else {
SpinPause() ; // SMP-polite spinning
}
}
}
// hashCode() generation :
//
// Possibilities:
// * MD5Digest of {obj,stwRandom}
// * CRC32 of {obj,stwRandom} or any linear-feedback shift register function.
// * A DES- or AES-style SBox[] mechanism
// * One of the Phi-based schemes, such as:
// 2654435761 = 2^32 * Phi (golden ratio)
// HashCodeValue = ((uintptr_t(obj) >> 3) * 2654435761) ^ GVars.stwRandom ;
// * A variation of Marsaglia's shift-xor RNG scheme.
// * (obj ^ stwRandom) is appealing, but can result
// in undesirable regularity in the hashCode values of adjacent objects
// (objects allocated back-to-back, in particular). This could potentially
// result in hashtable collisions and reduced hashtable efficiency.
// There are simple ways to "diffuse" the middle address bits over the
// generated hashCode values:
//
if (hashCode == 0) {
// This form uses an unguarded global Park-Miller RNG,
// so it's possible for two threads to race and generate the same RNG.
// On MP system we'll have lots of RW access to a global, so the
// mechanism induces lots of coherency traffic.
} else
if (hashCode == 1) {
// This variation has the property of being stable (idempotent)
// between STW operations. This can be useful in some of the 1-0
// synchronization schemes.
} else
if (hashCode == 2) {
} else
if (hashCode == 3) {
} else
if (hashCode == 4) {
} else {
// Marsaglia's xor-shift scheme with thread-specific state
// This is probably the best overall implementation -- we'll
// likely make this the default in future releases.
unsigned t = Self->_hashStateX ;
t ^= (t << 11) ;
unsigned v = Self->_hashStateW ;
v = (v ^ (v >> 19)) ^ (t ^ (t >> 8)) ;
Self->_hashStateW = v ;
value = v ;
}
return value;
}
//
if (UseBiasedLocking) {
// NOTE: many places throughout the JVM do not expect a safepoint
// to be taken here, in particular most operations on perm gen
// objects. However, we only ever bias Java instances and all of
// the call sites of identity_hash that might revoke biases have
// been checked to make sure they can handle a safepoint. The
// added check of the bias pattern is to avoid useless calls to
// thread-local storage.
// Box and unbox the raw reference just in case we cause a STW safepoint.
// Relaxing assertion for bug 6320749.
"biases should not be seen by VM thread here");
}
}
// hashCode() is a heap mutator ...
// Relaxing assertion for bug 6320749.
// object should remain ineligible for biased locking
if (mark->is_neutral()) {
if (hash) { // if it has hash, just return it
return hash;
}
// use (machine word version) atomic operation to install the hash
return hash;
}
// If atomic operation failed, we must inflate the header
// into heavy weight monitor. We could add more code here
// for fast path, but it does not worth the complexity.
} else if (mark->has_monitor()) {
if (hash) {
return hash;
}
// Skip to the following code to reduce code size
if (hash) { // header contains hash code
return hash;
}
// WARNING:
// The displaced header is strictly immutable.
// It can NOT be changed in ANY cases. So we have
// to inflate the header into heavyweight monitor
// even the current thread owns the lock. The reason
// is the BasicLock (stack slot) will be asynchronously
// read by other threads during the inflate() function.
// Any change to stack may not propagate to other threads
// correctly.
}
// Inflate the monitor to set hash code
// Load displaced header and check it has hash code
if (hash == 0) {
// The only update to the header in the monitor (outside GC)
// is install the hash code. If someone add new usage of
// displaced header, please update this code
}
}
// We finally get the hash
return hash;
}
// Deprecated -- use FastHashCode() instead.
}
if (UseBiasedLocking) {
}
// Uncontended case, header points to stack
if (mark->has_locker()) {
}
// Contended case, header points to ObjectMonitor (tagged pointer)
if (mark->has_monitor()) {
}
// Unlocked case, header in place
return false;
}
// Be aware of this method could revoke bias of the lock object.
// This method querys the ownership of the lock handle specified by 'h_obj'.
// If the current thread owns the lock, it returns owner_self. If no
// thread owns the lock, it returns owner_none. Otherwise, it will return
// ower_other.
// The caller must beware this method can revoke bias, and
// revocation can result in a safepoint.
// Possible mark states: neutral, biased, stack-locked, inflated
// CASE: biased
"biases should be revoked by now");
}
// CASE: stack-locked. Mark points to a BasicLock on the owner's stack.
if (mark->has_locker()) {
}
// CASE: inflated. Mark (tagged pointer) points to an objectMonitor.
// The Object:ObjectMonitor relationship is stable as long as we're
// not at a safepoint.
if (mark->has_monitor()) {
}
// CASE: neutral
return owner_none ; // it's unlocked
}
// FIXME: jvmti should call this
if (UseBiasedLocking) {
if (SafepointSynchronize::is_at_safepoint()) {
} else {
}
}
// Uncontended case, header points to stack
if (mark->has_locker()) {
}
// Contended case, header points to ObjectMonitor (tagged pointer)
if (mark->has_monitor()) {
}
}
// Unlocked case, header in place
// Cannot have assertion since this object may have been
// locked by another thread when reaching here.
// assert(mark->is_neutral(), "sanity check");
return NULL;
}
// Visitors ...
while (block) {
for (int i = _BLOCKSIZE - 1; i > 0; i--) {
}
}
}
}
// Get the next block in the block list.
return block;
}
for (int i = 1; i < _BLOCKSIZE; i++) {
}
}
}
}
// -----------------------------------------------------------------------------
// ObjectMonitor Lifecycle
// -----------------------
// Inflation unlinks monitors from the global gFreeList and
// associates them with objects. Deflation -- which occurs at
// STW-time -- disassociates idle monitors from objects. Such
// scavenged monitors are returned to the gFreeList.
//
// The global list is protected by ListLock. All the critical sections
// are short and operate in constant-time.
//
// ObjectMonitors reside in type-stable memory (TSM) and are immortal.
//
// Lifecycle:
// -- unassigned and on the global free list
// -- unassigned and on a thread's private omFreeList
// -- assigned to an object. The object is inflated and the mark refers
// to the objectmonitor.
//
// Constraining monitor pool growth via MonitorBound ...
//
// The monitor pool is grow-only. We scavenge at STW safepoint-time, but the
// the rate of scavenging is driven primarily by GC. As such, we can find
// an inordinate number of monitors in circulation.
// To avoid that scenario we can artificially induce a STW safepoint
// if the pool appears to be growing past some reasonable bound.
// Generally we favor time in space-time tradeoffs, but as there's no
// natural back-pressure on the # of extant monitors we need to impose some
// type of limit. Beware that if MonitorBound is set to too low a value
// we could just loop. In addition, if MonitorBound is set to a low value
// we'll incur more safepoints, which are harmful to performance.
// See also: GuaranteedSafepointInterval
//
// The current implementation uses asynchronous VM operations.
//
// Induce STW safepoint to trim monitors
// Ultimately, this results in a call to deflate_idle_monitors() in the near future.
// More precisely, trigger an asynchronous STW safepoint as the number
// of active monitors passes the specified threshold.
// TODO: assert thread state is reasonable
if (ObjectMonitor::Knob_Verbose) {
}
// Induce a 'null' safepoint to scavenge monitors
// Must VM_Operation instance be heap allocated as the op will be enqueue and posted
// to the VMthread and have a lifespan longer than that of this activation record.
// The VMThread will delete the op when completed.
if (ObjectMonitor::Knob_Verbose) {
}
}
}
/* Too slow for general assert or debug
void ObjectSynchronizer::verifyInUse (Thread *Self) {
ObjectMonitor* mid;
int inusetally = 0;
for (mid = Self->omInUseList; mid != NULL; mid = mid->FreeNext) {
inusetally ++;
}
assert(inusetally == Self->omInUseCount, "inuse count off");
int freetally = 0;
for (mid = Self->omFreeList; mid != NULL; mid = mid->FreeNext) {
freetally ++;
}
assert(freetally == Self->omFreeCount, "free count off");
}
*/
// A large MAXPRIVATE value reduces both list lock contention
// and list coherency traffic, but also tends to increase the
// number of objectMonitors in circulation as well as the STW
// scavenge costs. As usual, we lean toward time in space-time
// tradeoffs.
for (;;) {
ObjectMonitor * m ;
// 1: try to allocate from the thread's local omFreeList.
// Threads will attempt to allocate first from their local list, then
// from the global list, and only after those attempts fail will the thread
// attempt to instantiate new monitors. Thread-local free lists take
// heat off the ListLock and improve allocation latency, as well as reducing
// coherency traffic on the shared global list.
m = Self->omFreeList ;
if (m != NULL) {
Self->omFreeCount -- ;
// CONSIDER: set m->FreeNext = BAD -- diagnostic hygiene
if (MonitorInUseLists) {
Self->omInUseList = m;
Self->omInUseCount ++;
// verifyInUse(Self);
} else {
}
return m ;
}
// 2: try to allocate from the global gFreeList
// CONSIDER: use muxTry() instead of muxAcquire().
// If the muxTry() fails then drop immediately into case 3.
// If we're using thread-local free lists then try
// to reprovision the caller's free list.
// Reprovision the thread's omFreeList.
// Use bulk transfers to reduce the allocation rate and heat
// on various locks.
MonitorFreeCount --;
}
// We can't safely induce a STW safepoint from omAlloc() as our thread
// state may not be appropriate for such activities and callers may hold
// naked oops, so instead we defer the action.
}
continue;
}
// 3: allocate a block of new ObjectMonitors
// Both the local and global free lists are empty -- resort to malloc().
// In the current implementation objectMonitors are TSM - immortal.
// NOTE: (almost) no way to recover if allocation failed.
// We might be able to induce a STW safepoint and scavenge enough
// objectMonitors to permit progress.
}
// Format the block.
// initialize the linked list, each monitor points to its next
// forming the single linked free list, the very first monitor
// will points to next block, which forms the block list.
// The trick of using the 1st element in the block as gBlockList
// linkage should be reconsidered. A better implementation would
// look like: class Block { Block * next; int N; ObjectMonitor Body [N] ; }
for (int i = 1; i < _BLOCKSIZE ; i++) {
}
// terminate the last monitor as the end of list
// Element [0] is reserved for global list linkage
// Consider carving out this thread's current request from the
// block in hand. This avoids some lock traffic and redundant
// list activity.
// Acquire the ListLock to manipulate BlockList and FreeList.
// An Oyama-Taura-Yonezawa scheme might be more efficient.
// Add the new block to the list of extant blocks (gBlockList).
// The very first objectMonitor in a block is reserved and dedicated.
// It serves as blocklist "next" linkage.
gBlockList = temp;
// Add the new string of objectMonitors to the global free list
}
}
// Place "m" on the caller's private per-thread omFreeList.
// In practice there's no need to clamp or limit the number of
// monitors on a thread's omFreeList as the only time we'll call
// omRelease is to return a monitor to the free list after a CAS
// attempt failed. This doesn't allow unbounded #s of monitors to
// accumulate on a thread's free list.
//
// Remove from omInUseList
if (MonitorInUseLists && fromPerThreadAlloc) {
if (m == mid) {
// extract from per-thread in-use-list
} else if (curmidinuse != NULL) {
}
Self->omInUseCount --;
// verifyInUse(Self);
break;
} else {
curmidinuse = mid;
}
}
}
// FreeNext is used for both onInUseList and omFreeList, so clear old before setting new
Self->omFreeList = m ;
Self->omFreeCount ++ ;
}
// Return the monitors of a moribund thread's local free list to
// the global free list. Typically a thread calls omFlush() when
// it's dying. We could also consider having the VM thread steal
// monitors from threads that have not run java code over a few
// consecutive STW safepoints. Relatedly, we might decay
// omFreeProvision at STW safepoints.
//
// Also return the monitors of a moribund thread"s omInUseList to
// a global gOmInUseList under the global list lock so these
// will continue to be scanned.
//
// We currently call omFlush() from the Thread:: dtor _after the thread
// has been excised from the thread list and is no longer a mutator.
// That means that omFlush() can run concurrently with a safepoint and
// the scavenge operator. Calling omFlush() from JavaThread::exit() might
// be a better choice as we could safely reason that that the JVM is
// not at a safepoint at the time of the call, and thus there could
// be not inopportune interleavings between omFlush() and the scavenge
// operator.
int Tally = 0;
ObjectMonitor * s ;
Tally ++ ;
Tail = s ;
}
}
int InUseTally = 0;
InUseTally++;
}
// TODO debug
Self->omInUseCount = 0;
}
}
}
}
// Fast path code shared by multiple functions
if (mark->has_monitor()) {
}
}
// Note that we could encounter some performance loss through false-sharing as
// multiple locks occupy the same $ line. Padding might be appropriate.
// Inflate mutates the heap ...
// Relaxing assertion for bug 6320749.
for (;;) {
// The mark can be in one of the following states:
// * Inflated - just return
// * Stack-locked - coerce it to inflated
// * INFLATING - busy wait for conversion to complete
// * Neutral - aggressively inflate the object.
// * BIASED - Illegal. We should never see this
// CASE: inflated
if (mark->has_monitor()) {
return inf ;
}
// CASE: inflation in progress - inflating over a stack-lock.
// Some other thread is converting from stack-locked to inflated.
// Only that thread can complete inflation -- other threads must wait.
// The INFLATING value is transient.
// We could always eliminate polling by parking the thread on some auxiliary list.
continue ;
}
// CASE: stack-locked
// Could be stack-locked either by this thread or by some other thread.
//
// Note that we allocate the objectmonitor speculatively, _before_ attempting
// to install INFLATING into the mark word. We originally installed INFLATING,
// allocated the objectmonitor, and then finally STed the address of the
// objectmonitor into the mark. This was correct, but artificially lengthened
// the interval in which INFLATED appeared in the mark, thus increasing
// the odds of inflation contention.
//
// We now use per-thread private objectmonitor free lists.
// These list are reprovisioned from the global free list outside the
// critical INFLATING...ST interval. A thread can transfer
// multiple objectmonitors en-mass from the global free list to its local free list.
// This reduces coherency traffic and lock contention on the global free list.
// Using such local free lists, it doesn't matter if the omAlloc() call appears
// before or after the CAS(INFLATING) operation.
// See the comments in omAlloc().
if (mark->has_locker()) {
// Optimistically prepare the objectmonitor - anticipate successful CAS
// We do this before the CAS in order to minimize the length of time
// in which INFLATING appears in the mark.
m->Recycle();
m->_Responsible = NULL ;
m->OwnerIsThread = 0 ;
m->_recursions = 0 ;
continue ; // Interference -- just retry
}
// We've successfully installed INFLATING (0) into the mark-word.
// This is the only case where 0 will appear in a mark-work.
// Only the singular thread that successfully swings the mark-word
// to 0 can perform (or more precisely, complete) inflation.
//
// Why do we CAS a 0 into the mark-word instead of just CASing the
// mark-word from the stack-locked value directly to the new inflated state?
// Consider what happens when a thread unlocks a stack-locked object.
// It attempts to use CAS to swing the displaced header value from the
// on-stack basiclock back into the object header. Recall also that the
// header value (hashcode, etc) can reside in (a) the object header, or
// (b) a displaced header associated with the stack-lock, or (c) a displaced
// header in an objectMonitor. The inflate() routine must copy the header
// value from the basiclock on the owner's stack to the objectMonitor, all
// the while preserving the hashCode stability invariants. If the owner
// decides to release the lock while the value is 0, the unlock will fail
// and control will eventually pass from slow_exit() to inflate. The owner
// will then spin, waiting for the 0 value to disappear. Put another way,
// the 0 causes the owner to stall if the owner happens to try to
// drop the lock (restoring the header from the basiclock to the object)
// while inflation is in-progress. This protocol avoids races that might
// would otherwise permit hashCode values to change or "flicker" for an object.
// Critically, while object->mark is 0 mark->displaced_mark_helper() is stable.
// 0 serves as a "BUSY" inflate-in-progress indicator.
// fetch the displaced mark from the owner's stack.
// The owner can't die or unwind past the lock while our INFLATING
// object is in the mark. Furthermore the owner can't complete
// an unlock on the object, either.
// Setup monitor fields to proper values -- prepare the monitor
m->set_header(dmw) ;
// Optimization: if the mark->locker stack address is associated
// with this thread we could simply set m->_owner = Self and
// m->OwnerIsThread = 1. Note that a thread can inflate an object
// that it has stack-locked -- as might happen in wait() -- directly
// with CAS. That is, we can avoid the xchg-NULL .... ST idiom.
m->set_object(object);
// TODO-FIXME: assert BasicLock->dhw != 0.
// Must preserve store ordering. The monitor state must
// be stable at the time of publishing the monitor address.
// Hopefully the performance counters are allocated on distinct cache lines
// to avoid false sharing on MP systems ...
if (TraceMonitorInflation) {
if (object->is_instance()) {
}
}
return m ;
}
// CASE: neutral
// TODO-FIXME: for entry we currently inflate and then try to CAS _owner.
// If we know we're inflating for entry it's better to inflate by swinging a
// pre-locked objectMonitor pointer into the object header. A successful
// CAS inflates the object *and* confers ownership to the inflating thread.
// In the current implementation we use a 2-step mechanism where we CAS()
// to inflate and then CAS() again to try to swing _owner from NULL to Self.
// An inflateTry() method that we could call from fast_enter() and slow_enter()
// would be useful.
// prepare m for installation - set monitor to initial state
m->Recycle();
m->set_header(mark);
m->set_object(object);
m->OwnerIsThread = 1 ;
m->_recursions = 0 ;
m->_Responsible = NULL ;
m->set_object (NULL) ;
m->OwnerIsThread = 0 ;
m->Recycle() ;
m = NULL ;
continue ;
// interference - the markword changed - just retry.
// The state-transitions are one-way, so there's no chance of
// live-lock -- "Inflated" is an absorbing state.
}
// Hopefully the performance counters are allocated on distinct
// cache lines to avoid false sharing on MP systems ...
if (TraceMonitorInflation) {
if (object->is_instance()) {
}
}
return m ;
}
}
// Note that we could encounter some performance loss through false-sharing as
// multiple locks occupy the same $ line. Padding might be appropriate.
// Deflate_idle_monitors() is called at all safepoints, immediately
// after all mutators are stopped, but before any objects have moved.
// It traverses the list of known monitors, deflating where possible.
// The scavenged monitor are returned to the monitor free list.
//
// Beware that we scavenge at *every* stop-the-world point.
// Having a large number of monitors in-circulation negatively
// impacts the performance of some applications (e.g., PointBase).
// Broadly, we want to minimize the # of monitors in circulation.
//
// We have added a flag, MonitorInUseLists, which creates a list
// of active monitors for each thread. deflate_idle_monitors()
// only scans the per-thread inuse lists. omAlloc() puts all
// assigned monitors on the per-thread list. deflate_idle_monitors()
// returns the non-busy monitors to the global free list.
// When a thread dies, omFlush() adds the list of active monitors for
// that thread to a global gOmInUseList acquiring the
// global list lock. deflate_idle_monitors() acquires the global
// list lock to scan for non-busy monitors to the global free list.
// An alternative could have used a single global inuse list. The
// downside would have been the additional cost of acquiring the global list lock
// for every omAlloc().
//
// Perversely, the heap size -- and thus the STW safepoint rate --
// typically drives the scavenge rate. Large heaps can mean infrequent GC,
// which in turn can mean large(r) numbers of objectmonitors in circulation.
// This is an unfortunate aspect of this design.
//
enum ManifestConstants {
} ;
// Deflate a single monitor if not in use
// Return true if deflated, false if in use
bool deflated;
// Normal case ... The monitor is associated with obj.
deflated = false;
} else {
// Deflate the monitor if it is no longer being used
// It's idle - scavenge and return to the global free list
// plain old deflation ...
if (TraceMonitorInflation) {
if (obj->is_instance()) {
}
}
// Restore the header back to obj
// Move the object to the working free list defined by FreeHead,FreeTail.
}
deflated = true;
}
return deflated;
}
// Caller acquires ListLock
int deflatedcount = 0;
bool deflated = false;
}
if (deflated) {
// extract from per-thread in-use-list
} else if (curmidinuse != NULL) {
}
} else {
curmidinuse = mid;
}
}
return deflatedcount;
}
bool deflated = false;
// Prevent omFlush from changing mids in Thread dtor's during deflation
// And in case the vm thread is acquiring a lock during a safepoint
// See e.g. 6320749
if (MonitorInUseLists) {
int inUse = 0;
// verifyInUse(cur);
}
// For moribund threads, scan gOmInUseList
if (gOmInUseList) {
nInuse += gOmInUseCount;
}
// Iterate over all extant monitors - Scavenge all idle monitors.
nInCirculation += _BLOCKSIZE ;
for (int i = 1 ; i < _BLOCKSIZE; i++) {
// The monitor is not associated with an object.
// The monitor should either be a thread-specific private
// free list or the global free list.
// obj == NULL IMPLIES mid->is_busy() == 0
continue ;
}
if (deflated) {
nScavenged ++ ;
} else {
nInuse ++;
}
}
}
// Consider: audit gFreeList to ensure that MonitorFreeCount and list agree.
if (ObjectMonitor::Knob_Verbose) {
::printf ("Deflate: InCirc=%d InUse=%d Scavenged=%d ForceMonitorScavenge=%d : pop=%d free=%d\n",
}
ForceMonitorScavenge = 0; // Reset
// Move the scavenged monitors back to the global free list.
// constant-time list splice - prepend scavenged segment to gFreeList
}
if (ObjectMonitor::_sync_MonExtant != NULL) ObjectMonitor::_sync_MonExtant ->set_value(nInCirculation);
// TODO: Add objectMonitor leak detection.
}
// Monitor cleanup on JavaThread::exit
// Iterate through monitor cache and attempt to release thread's monitors
// Gives up on a particular monitor if an exception occurs, but continues
// the overall iteration, swallowing the exception.
private:
public:
}
}
};
// Release all inflated monitors owned by THREAD. Lightweight monitors are
// ignored. This is meant to be called during JNI thread detach which assumes
// all remaining monitors are heavyweight. All exceptions are swallowed.
// Scanning the extant monitor list can be time consuming.
// A simple optimization is to add a per-thread flag that indicates a thread
// called jni_monitorenter() during its lifetime.
//
// Instead of No_Savepoint_Verifier it might be cheaper to
// use an idiom of the form:
// auto int tmp = SafepointSynchronize::_safepoint_counter ;
// <code that must not run at safepoint>
// guarantee (((tmp ^ _safepoint_counter) | (tmp & 1)) == 0) ;
// Since the tests are extremely cheap we could leave them enabled
// for normal product builds.
}
//------------------------------------------------------------------------------
// Non-product code
#ifndef PRODUCT
bool is_method, bool is_locking) {
// Don't know what to do here
}
// Verify all monitors in the monitor cache, the verification is weak.
while (block) {
for (int i = 1; i < _BLOCKSIZE; i++) {
}
}
}
}
// Check if monitor belongs to the monitor cache
// The list is grow-only so it's *relatively* safe to traverse
// the list of extant blocks without taking a lock.
while (block) {
return 1;
}
}
return 0;
}
#endif