< 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 >