< prev index next >
src/hotspot/share/runtime/objectMonitor.cpp
Print this page
rev 54415 : 8222295: more baseline cleanups from Async Monitor Deflation project
rev 54416 : Checkpoint latest preliminary review patches for full OpenJDK review; merge with 8222295.patch.
rev 54417 : imported patch dcubed.monitor_deflate_conc.v2.01
*** 298,310 ****
// Prevent deflation. See ObjectSynchronizer::deflate_monitor() and is_busy().
// Ensure the object-monitor relationship remains stable while there's contention.
const jint contentions = Atomic::add(1, &_contentions);
if (contentions <= 0 && _owner == DEFLATER_MARKER) {
! // Async deflation in progress. Help deflater thread install
! // the mark word (in case deflater thread is slow).
! install_displaced_markword_in_object();
Self->_Stalled = 0;
return false; // Caller should retry. Never mind about _contentions as this monitor has been deflated.
}
// The deflater thread will not deflate this monitor and the monitor is contended, continue.
--- 298,312 ----
// Prevent deflation. See ObjectSynchronizer::deflate_monitor() and is_busy().
// Ensure the object-monitor relationship remains stable while there's contention.
const jint contentions = Atomic::add(1, &_contentions);
if (contentions <= 0 && _owner == DEFLATER_MARKER) {
! // Async deflation is in progress. Attempt to restore the
! // header/dmw to the object's header so that we only retry once
! // if the deflater thread happens to be slow.
! const oop obj = (oop) object();
! install_displaced_markword_in_object(obj);
Self->_Stalled = 0;
return false; // Caller should retry. Never mind about _contentions as this monitor has been deflated.
}
// The deflater thread will not deflate this monitor and the monitor is contended, continue.
*** 424,492 ****
// We can either return -1 or retry.
// Retry doesn't make as much sense because the lock was just acquired.
return -1;
}
! // Install the displaced markword of a deflated monitor into the object
! // associated with the monitor.
! // This method is idempotent and is executed by both mutators wanting to
! // acquire a monitor for an object and the thread deflating monitors.
! // A mutator trying to install a hash in the monitor's _header field can
! // also run in parallel to this method.
! void ObjectMonitor::install_displaced_markword_in_object() {
markOop dmw = header();
if (dmw == NULL) {
! // The thread deflating monitors has won the race so we
! // have nothing to do.
return;
}
! // A non-NULL dmw has to be either neutral or is participating in
! // this restoration protocol.
assert(dmw->is_neutral() || (dmw->is_marked() && dmw->hash() == 0),
! "failed precondition: is_neutral=%d, is_marked=%d, hash="
! INTPTR_FORMAT, dmw->is_neutral(), dmw->is_marked(), dmw->hash());
if (!dmw->is_marked() && dmw->hash() == 0) {
! // This dmw is neutral and has not yet started the restoration
! // protocol so we mark a copy of the dmw to begin the protocol.
! markOop marked_dmw = dmw->set_marked();
! assert(marked_dmw->is_marked() && marked_dmw->hash() == 0,
! "sanity_check: is_marked=%d, hash=" INTPTR_FORMAT,
! marked_dmw->is_marked(), marked_dmw->hash());
!
! // There can be three different racers trying to update the _header
! // field and the return dmw value will tell us what cleanup needs
! // to be done (if any) after the race winner:
! // 1) A mutator trying to install a hash in the object.
! // Note: That mutator is not executing this code, but it is
! // trying to update the _header field.
! // If winner: dmw will contain the hash and be unmarked
! // 2a) A mutator trying to acquire the monitor via enter():
! // If winner: dmw is marked and hash() == 0
! // 2b) The thread deflating the monitor via deflate_monitor_using_JT():
! // If winner: dmw is marked and hash() == 0
dmw = (markOop) Atomic::cmpxchg(marked_dmw, &_header, dmw);
}
if (dmw->is_marked()) {
! // The dmw copy is marked which means a hash was not set by a racing
! // thread. Clear the mark from the copy in preparation for possible
! // restoration from this thread.
! assert(dmw->hash() == 0, "must be 0: hash=" INTPTR_FORMAT, dmw->hash());
dmw = dmw->set_unmarked();
}
! assert(dmw->is_neutral(), "must be a neutral markword");
! oop const obj = (oop) object();
! // Install displaced markword if object markword still points to this
! // monitor. Both the mutator trying to enter() and the thread deflating
! // the monitor will reach this point, but only one can win.
! // Note: If a mutator won the cmpxchg() race above and installed a hash
! // in _header, then the updated dmw contains that hash and we'll install
! // it in the object's markword here.
obj->cas_set_mark(dmw, markOopDesc::encode(this));
}
#define MAX_RECHECK_INTERVAL 1000
void ObjectMonitor::EnterI(TRAPS) {
--- 426,512 ----
// We can either return -1 or retry.
// Retry doesn't make as much sense because the lock was just acquired.
return -1;
}
! // Install the displaced mark word (dmw) of a deflating ObjectMonitor
! // into the header of the object associated with the monitor. This
! // idempotent method is called by a thread that is deflating a
! // monitor and by other threads that have detected a race with the
! // deflation process.
! void ObjectMonitor::install_displaced_markword_in_object(const oop obj) {
! // This function must only be called when (owner == DEFLATER_MARKER
! // && contentions <= 0), but we can't guarantee that here because
! // those values could change when the ObjectMonitor gets moved from
! // the global free list to a per-thread free list.
!
! guarantee(obj != NULL, "must be non-NULL");
! if (object() != obj) {
! // ObjectMonitor's object ref no longer refers to the target object
! // so the object's header has already been restored.
! return;
! }
!
markOop dmw = header();
if (dmw == NULL) {
! // ObjectMonitor's header/dmw has been cleared by the deflating
! // thread so the object's header has already been restored.
return;
}
! // A non-NULL dmw has to be either neutral (not locked and not marked)
! // or is already participating in this restoration protocol.
assert(dmw->is_neutral() || (dmw->is_marked() && dmw->hash() == 0),
! "failed precondition: dmw=" INTPTR_FORMAT, p2i(dmw));
+ markOop marked_dmw = NULL;
if (!dmw->is_marked() && dmw->hash() == 0) {
! // This dmw has not yet started the restoration protocol so we
! // mark a copy of the dmw to begin the protocol.
! // Note: A dmw with a hashcode does not take this code path.
! marked_dmw = dmw->set_marked();
!
! // All of the callers to this function can be racing with each
! // other trying to update the _header field.
dmw = (markOop) Atomic::cmpxchg(marked_dmw, &_header, dmw);
+ if (dmw == NULL) {
+ // ObjectMonitor's header/dmw has been cleared by the deflating
+ // thread so the object's header has already been restored.
+ return;
+ }
+ // The _header field is now marked. The winner's 'dmw' variable
+ // contains the original, unmarked header/dmw value and any
+ // losers have a marked header/dmw value that will be cleaned
+ // up below.
}
if (dmw->is_marked()) {
! // Clear the mark from the header/dmw copy in preparation for
! // possible restoration from this thread.
! assert(dmw->hash() == 0, "hashcode must be 0: dmw=" INTPTR_FORMAT,
! p2i(dmw));
dmw = dmw->set_unmarked();
}
! assert(dmw->is_neutral(), "must be neutral: dmw=" INTPTR_FORMAT, p2i(dmw));
! // Install displaced mark word if the object's header still points
! // to this ObjectMonitor. All racing callers to this function will
! // reach this point, but only one can win.
obj->cas_set_mark(dmw, markOopDesc::encode(this));
+
+ // Note: It does not matter which thread restored the header/dmw
+ // into the object's header. The thread deflating the monitor just
+ // wanted the object's header restored and it is. The threads that
+ // detected a race with the deflation process also wanted the
+ // object's header restored before they retry their operation and
+ // because it is restored they will only retry once.
+
+ if (marked_dmw != NULL) {
+ // Clear _header to NULL if it is still marked_dmw so a racing
+ // install_displaced_markword_in_object() can bail out sooner.
+ Atomic::cmpxchg((markOop)NULL, &_header, marked_dmw);
+ }
}
#define MAX_RECHECK_INTERVAL 1000
void ObjectMonitor::EnterI(TRAPS) {
*** 501,516 ****
assert(_Responsible != Self, "invariant");
return;
}
if (_owner == DEFLATER_MARKER) {
! guarantee(0 < _contentions, "_owner == DEFLATER_MARKER && _contentions <= 0 should have been handled by the caller");
! // Deflater thread tried to lock this monitor, but it failed to make _contentions negative and gave up.
! // Try to acquire monitor.
if (Atomic::cmpxchg(Self, &_owner, DEFLATER_MARKER) == DEFLATER_MARKER) {
assert(_succ != Self, "invariant");
- assert(_owner == Self, "invariant");
assert(_Responsible != Self, "invariant");
return;
}
}
--- 521,539 ----
assert(_Responsible != Self, "invariant");
return;
}
if (_owner == DEFLATER_MARKER) {
! // The deflation protocol finished the first part (setting _owner), but
! // it failed the second part (making _contentions negative) and bailed.
! // Because we're called from enter() we have at least one contention.
! guarantee(_contentions > 0, "owner == DEFLATER_MARKER && contentions <= 0 "
! "should have been handled by the caller: contentions=%d",
! _contentions);
if (Atomic::cmpxchg(Self, &_owner, DEFLATER_MARKER) == DEFLATER_MARKER) {
+ // Acquired the monitor.
assert(_succ != Self, "invariant");
assert(_Responsible != Self, "invariant");
return;
}
}
*** 629,640 ****
}
if (TryLock(Self) > 0) break;
if (_owner == DEFLATER_MARKER) {
! guarantee(0 < _contentions, "_owner == DEFLATER_MARKER && _contentions <= 0 should have been handled by the caller");
! // Deflater thread tried to lock this monitor, but it failed to make _contentions negative and gave up.
if (Atomic::cmpxchg(Self, &_owner, DEFLATER_MARKER) == DEFLATER_MARKER) {
// Acquired the monitor.
break;
}
}
--- 652,667 ----
}
if (TryLock(Self) > 0) break;
if (_owner == DEFLATER_MARKER) {
! // The deflation protocol finished the first part (setting _owner), but
! // it failed the second part (making _contentions negative) and bailed.
! // Because we're called from enter() we have at least one contention.
! guarantee(_contentions > 0, "owner == DEFLATER_MARKER && contentions <= 0 "
! "should have been handled by the caller: contentions=%d",
! _contentions);
if (Atomic::cmpxchg(Self, &_owner, DEFLATER_MARKER) == DEFLATER_MARKER) {
// Acquired the monitor.
break;
}
}
*** 759,769 ****
if (TryLock(Self) > 0) break;
if (TrySpin(Self) > 0) break;
if (_owner == DEFLATER_MARKER) {
! guarantee(0 <= _contentions, "Impossible: _owner == DEFLATER_MARKER && _contentions < 0, monitor must not be owned by deflater thread here");
if (Atomic::cmpxchg(Self, &_owner, DEFLATER_MARKER) == DEFLATER_MARKER) {
// Acquired the monitor.
break;
}
}
--- 786,801 ----
if (TryLock(Self) > 0) break;
if (TrySpin(Self) > 0) break;
if (_owner == DEFLATER_MARKER) {
! // The deflation protocol finished the first part (setting _owner),
! // but it will observe _waiters != 0 and will bail out. Because we're
! // called from wait() we may or may not have any contentions.
! guarantee(_contentions >= 0, "owner == DEFLATER_MARKER && contentions < 0 "
! "should have been handled by the caller: contentions=%d",
! _contentions);
if (Atomic::cmpxchg(Self, &_owner, DEFLATER_MARKER) == DEFLATER_MARKER) {
// Acquired the monitor.
break;
}
}
*** 973,983 ****
// see x86_32.ad Fast_Unlock() and the I1 and I2 properties.
// Upon deeper reflection, however, in a properly run JVM the only
// way we should encounter this situation is in the presence of
// unbalanced JNI locking. TODO: CheckJNICalls.
// See also: CR4414101
! assert(false, "Non-balanced monitor enter/exit! Likely JNI locking");
return;
}
}
if (_recursions != 0) {
--- 1005,1016 ----
// see x86_32.ad Fast_Unlock() and the I1 and I2 properties.
// Upon deeper reflection, however, in a properly run JVM the only
// way we should encounter this situation is in the presence of
// unbalanced JNI locking. TODO: CheckJNICalls.
// See also: CR4414101
! assert(false, "Non-balanced monitor enter/exit! Likely JNI locking: "
! "owner=" INTPTR_FORMAT, p2i(_owner));
return;
}
}
if (_recursions != 0) {
*** 1465,1475 ****
assert(_owner != Self, "invariant");
ObjectWaiter::TStates v = node.TState;
if (v == ObjectWaiter::TS_RUN) {
const bool success = enter(Self);
! guarantee(success, "enter signaled for a retry, but monitor should not have been deflated as waiters > 0");
} else {
guarantee(v == ObjectWaiter::TS_ENTER || v == ObjectWaiter::TS_CXQ, "invariant");
ReenterI(Self, &node);
node.wait_reenter_end(this);
}
--- 1498,1508 ----
assert(_owner != Self, "invariant");
ObjectWaiter::TStates v = node.TState;
if (v == ObjectWaiter::TS_RUN) {
const bool success = enter(Self);
! ADIM_guarantee(success, "enter signaled for a retry, but monitor should not have been deflated as waiters > 0");
} else {
guarantee(v == ObjectWaiter::TS_ENTER || v == ObjectWaiter::TS_CXQ, "invariant");
ReenterI(Self, &node);
node.wait_reenter_end(this);
}
*** 2054,2083 ****
// saved. This function returns false if we have lost a race with
// async deflation; the caller should retry as appropriate.
//
bool ObjectMonitorHandle::save_om_ptr(oop object, markOop mark) {
guarantee(mark->has_monitor(), "sanity check: mark=" INTPTR_FORMAT,
! p2i((address)mark));
ObjectMonitor * om_ptr = mark->monitor();
om_ptr->inc_ref_count();
if (AsyncDeflateIdleMonitors) {
// Race here if monitor is not owned! The above ref_count bump
// will cause subsequent async deflation to skip it. However,
// previous or concurrent async deflation is a race.
! if (om_ptr->_owner == DEFLATER_MARKER) {
! // Async deflation won the race so we have to retry.
om_ptr->dec_ref_count();
return false;
}
// The ObjectMonitor could have been deflated and reused for
// another object before we bumped the ref_count so make sure
// our object still refers to this ObjectMonitor.
const markOop tmp = object->mark();
if (!tmp->has_monitor() || tmp->monitor() != om_ptr) {
// Async deflation and reuse won the race so we have to retry.
om_ptr->dec_ref_count();
return false;
}
}
--- 2087,2120 ----
// saved. This function returns false if we have lost a race with
// async deflation; the caller should retry as appropriate.
//
bool ObjectMonitorHandle::save_om_ptr(oop object, markOop mark) {
guarantee(mark->has_monitor(), "sanity check: mark=" INTPTR_FORMAT,
! p2i(mark));
ObjectMonitor * om_ptr = mark->monitor();
om_ptr->inc_ref_count();
if (AsyncDeflateIdleMonitors) {
// Race here if monitor is not owned! The above ref_count bump
// will cause subsequent async deflation to skip it. However,
// previous or concurrent async deflation is a race.
! if (om_ptr->_owner == DEFLATER_MARKER && om_ptr->_contentions <= 0) {
! // Async deflation is in progress. Attempt to restore the
! // header/dmw to the object's header so that we only retry once
! // if the deflater thread happens to be slow.
! om_ptr->install_displaced_markword_in_object(object);
om_ptr->dec_ref_count();
return false;
}
// The ObjectMonitor could have been deflated and reused for
// another object before we bumped the ref_count so make sure
// our object still refers to this ObjectMonitor.
const markOop tmp = object->mark();
if (!tmp->has_monitor() || tmp->monitor() != om_ptr) {
// Async deflation and reuse won the race so we have to retry.
+ // Skip object header restoration since that's already done.
om_ptr->dec_ref_count();
return false;
}
}
*** 2087,2099 ****
return true;
}
// For internal use by ObjectSynchronizer::inflate().
void ObjectMonitorHandle::set_om_ptr(ObjectMonitor * om_ptr) {
! // Cannot guarantee() is_new() here. As soon as the ObjectMonitor*
! // is attached to the object in inflate(), it can be used by other
! // JavaThreads.
! // guarantee(om_ptr->is_new(), "sanity check: allocation_state=%d",
! // int(om_ptr->allocation_state()));
om_ptr->inc_ref_count();
_om_ptr = om_ptr;
}
--- 2124,2138 ----
return true;
}
// For internal use by ObjectSynchronizer::inflate().
void ObjectMonitorHandle::set_om_ptr(ObjectMonitor * om_ptr) {
! if (_om_ptr == NULL) {
! guarantee(om_ptr != NULL, "cannot clear an unset om_ptr");
om_ptr->inc_ref_count();
_om_ptr = om_ptr;
+ } else {
+ guarantee(om_ptr == NULL, "can only clear a set om_ptr");
+ _om_ptr->dec_ref_count();
+ _om_ptr = NULL;
+ }
}
< prev index next >