< prev index next >
src/hotspot/share/runtime/synchronizer.cpp
Print this page
rev 58110 : v2.09a with 8235795, 8235931 and 8236035 extracted; rebased to jdk-14+28; merge with 8236035.patch.cr1; merge with 8235795.patch.cr1; merge with 8236035.patch.cr2; merge with 8235795.patch.cr2; merge with 8235795.patch.cr3.
rev 58111 : See CR9-to-CR10-changes; merge with jdk-15+11.
*** 137,151 ****
// Global ObjectMonitor in-use list. When a JavaThread is exiting,
// ObjectMonitors on its per-thread in-use list are prepended here.
ObjectMonitor* _in_use_list;
DEFINE_PAD_MINUS_SIZE(2, OM_CACHE_LINE_SIZE, sizeof(ObjectMonitor*));
! // Global ObjectMonitor wait list. If HandshakeAfterDeflateIdleMonitors
! // is true, deflated ObjectMonitors wait on this list until after a
! // handshake or a safepoint for platforms that don't support handshakes.
! // After the handshake or safepoint, the deflated ObjectMonitors are
! // prepended to free_list.
ObjectMonitor* _wait_list;
DEFINE_PAD_MINUS_SIZE(3, OM_CACHE_LINE_SIZE, sizeof(ObjectMonitor*));
int _free_count; // # on free_list
DEFINE_PAD_MINUS_SIZE(4, OM_CACHE_LINE_SIZE, sizeof(int));
--- 137,150 ----
// Global ObjectMonitor in-use list. When a JavaThread is exiting,
// ObjectMonitors on its per-thread in-use list are prepended here.
ObjectMonitor* _in_use_list;
DEFINE_PAD_MINUS_SIZE(2, OM_CACHE_LINE_SIZE, sizeof(ObjectMonitor*));
! // Global ObjectMonitor wait list. Deflated ObjectMonitors wait on
! // this list until after a handshake or a safepoint for platforms
! // that don't support handshakes. After the handshake or safepoint,
! // the deflated ObjectMonitors are prepended to free_list.
ObjectMonitor* _wait_list;
DEFINE_PAD_MINUS_SIZE(3, OM_CACHE_LINE_SIZE, sizeof(ObjectMonitor*));
int _free_count; // # on free_list
DEFINE_PAD_MINUS_SIZE(4, OM_CACHE_LINE_SIZE, sizeof(int));
*** 318,328 ****
// Prepend a list of ObjectMonitors to om_list_globals._wait_list.
// 'tail' is the last ObjectMonitor in the list and there are 'count'
// on the list. Also updates om_list_globals._wait_count.
static void prepend_list_to_global_wait_list(ObjectMonitor* list,
ObjectMonitor* tail, int count) {
- assert(HandshakeAfterDeflateIdleMonitors, "sanity check");
prepend_list_to_common(list, tail, count, &om_list_globals._wait_list,
&om_list_globals._wait_count);
}
// Prepend a list of ObjectMonitors to om_list_globals._in_use_list.
--- 317,326 ----
*** 533,544 ****
if (AsyncDeflateIdleMonitors &&
m->try_set_owner_from(DEFLATER_MARKER, self) == DEFLATER_MARKER) {
// The deflation protocol finished the first part (setting owner),
// but it failed the second part (making ref_count negative) and
! // bailed. Or the ObjectMonitor was async deflated and reused.
! // Acquired the monitor.
assert(m->_recursions == 0, "invariant");
return true;
}
}
break;
--- 531,541 ----
if (AsyncDeflateIdleMonitors &&
m->try_set_owner_from(DEFLATER_MARKER, self) == DEFLATER_MARKER) {
// The deflation protocol finished the first part (setting owner),
// but it failed the second part (making ref_count negative) and
! // bailed. Acquired the monitor.
assert(m->_recursions == 0, "invariant");
return true;
}
}
break;
*** 1033,1046 ****
assert(AsyncDeflateIdleMonitors, "sanity check");
continue;
}
monitor = omh.om_ptr();
temp = monitor->header();
! // Allow for a lagging install_displaced_markword_in_object() to
! // have marked the ObjectMonitor's header/dmw field.
! assert(temp.is_neutral() || (AsyncDeflateIdleMonitors && temp.is_marked()),
! "invariant: header=" INTPTR_FORMAT, temp.value());
hash = temp.hash();
if (hash != 0) { // if it has a hash, just return it
return hash;
}
// Fall thru so we only have one place that installs the hash in
--- 1030,1040 ----
assert(AsyncDeflateIdleMonitors, "sanity check");
continue;
}
monitor = omh.om_ptr();
temp = monitor->header();
! assert(temp.is_neutral(), "invariant: header=" INTPTR_FORMAT, temp.value());
hash = temp.hash();
if (hash != 0) { // if it has a hash, just return it
return hash;
}
// Fall thru so we only have one place that installs the hash in
*** 1068,1107 ****
ObjectMonitorHandle omh;
inflate(&omh, self, obj, inflate_cause_hash_code);
monitor = omh.om_ptr();
// Load ObjectMonitor's header/dmw field and see if it has a hash.
mark = monitor->header();
! // Allow for a lagging install_displaced_markword_in_object() to
! // have marked the ObjectMonitor's header/dmw field.
! assert(mark.is_neutral() || (AsyncDeflateIdleMonitors && mark.is_marked()),
! "invariant: header=" INTPTR_FORMAT, mark.value());
hash = mark.hash();
if (hash == 0) { // if it does not have a hash
hash = get_next_hash(self, obj); // get a new hash
temp = mark.copy_set_hash(hash); // merge the hash into header
- if (AsyncDeflateIdleMonitors && temp.is_marked()) {
- // A lagging install_displaced_markword_in_object() has marked
- // the ObjectMonitor's header/dmw field. We clear it to avoid
- // any confusion if we are able to set the hash.
- temp.set_unmarked();
- }
assert(temp.is_neutral(), "invariant: header=" INTPTR_FORMAT, temp.value());
uintptr_t v = Atomic::cmpxchg((volatile uintptr_t*)monitor->header_addr(), mark.value(), temp.value());
test = markWord(v);
if (test != mark) {
// The attempt to update the ObjectMonitor's header/dmw field
// did not work. This can happen if another thread managed to
! // merge in the hash just before our cmpxchg(). With async
! // deflation, a lagging install_displaced_markword_in_object()
! // could have just marked or just unmarked the header/dmw field.
// If we add any new usages of the header/dmw field, this code
// will need to be updated.
- if (AsyncDeflateIdleMonitors) {
- // Since async deflation gives us two possible reasons for
- // the cmwxchg() to fail, it is easier to simply retry.
- continue;
- }
hash = test.hash();
assert(test.is_neutral(), "invariant: header=" INTPTR_FORMAT, test.value());
assert(hash != 0, "should only have lost the race to a thread that set a non-zero hash");
}
}
--- 1062,1085 ----
ObjectMonitorHandle omh;
inflate(&omh, self, obj, inflate_cause_hash_code);
monitor = omh.om_ptr();
// Load ObjectMonitor's header/dmw field and see if it has a hash.
mark = monitor->header();
! assert(mark.is_neutral(), "invariant: header=" INTPTR_FORMAT, mark.value());
hash = mark.hash();
if (hash == 0) { // if it does not have a hash
hash = get_next_hash(self, obj); // get a new hash
temp = mark.copy_set_hash(hash); // merge the hash into header
assert(temp.is_neutral(), "invariant: header=" INTPTR_FORMAT, temp.value());
uintptr_t v = Atomic::cmpxchg((volatile uintptr_t*)monitor->header_addr(), mark.value(), temp.value());
test = markWord(v);
if (test != mark) {
// The attempt to update the ObjectMonitor's header/dmw field
// did not work. This can happen if another thread managed to
! // merge in the hash just before our cmpxchg().
// If we add any new usages of the header/dmw field, this code
// will need to be updated.
hash = test.hash();
assert(test.is_neutral(), "invariant: header=" INTPTR_FORMAT, test.value());
assert(hash != 0, "should only have lost the race to a thread that set a non-zero hash");
}
}
*** 1263,1273 ****
while (block != NULL) {
assert(block->object() == CHAINMARKER, "must be a block header");
for (int i = _BLOCKSIZE - 1; i > 0; i--) {
ObjectMonitor* mid = (ObjectMonitor *)(block + i);
ObjectMonitorHandle omh;
! if (!mid->is_free() && omh.set_om_ptr_if_safe(mid)) {
// The ObjectMonitor* is not free and it has been made safe.
if (mid->object() == NULL) {
// Only process with closure if the object is set.
continue;
}
--- 1241,1251 ----
while (block != NULL) {
assert(block->object() == CHAINMARKER, "must be a block header");
for (int i = _BLOCKSIZE - 1; i > 0; i--) {
ObjectMonitor* mid = (ObjectMonitor *)(block + i);
ObjectMonitorHandle omh;
! if (!mid->is_free() && omh.save_om_ptr_if_safe(mid)) {
// The ObjectMonitor* is not free and it has been made safe.
if (mid->object() == NULL) {
// Only process with closure if the object is set.
continue;
}
*** 1284,1297 ****
int population = Atomic::load(&om_list_globals._population);
if (population == 0) {
return false;
}
if (MonitorUsedDeflationThreshold > 0) {
! int monitors_used = population - Atomic::load(&om_list_globals._free_count);
! if (HandshakeAfterDeflateIdleMonitors) {
! monitors_used -= Atomic::load(&om_list_globals._wait_count);
! }
int monitor_usage = (monitors_used * 100LL) / population;
return monitor_usage > MonitorUsedDeflationThreshold;
}
return false;
}
--- 1262,1273 ----
int population = Atomic::load(&om_list_globals._population);
if (population == 0) {
return false;
}
if (MonitorUsedDeflationThreshold > 0) {
! int monitors_used = population - Atomic::load(&om_list_globals._free_count) -
! Atomic::load(&om_list_globals._wait_count);
int monitor_usage = (monitors_used * 100LL) / population;
return monitor_usage > MonitorUsedDeflationThreshold;
}
return false;
}
*** 1320,1333 ****
// in order to not swamp the ServiceThread.
_last_async_deflation_time_ns = os::javaTimeNanos();
return true;
}
int monitors_used = Atomic::load(&om_list_globals._population) -
! Atomic::load(&om_list_globals._free_count);
! if (HandshakeAfterDeflateIdleMonitors) {
! monitors_used -= Atomic::load(&om_list_globals._wait_count);
! }
if (is_MonitorBound_exceeded(monitors_used)) {
// Not enough ObjectMonitors on the global free list.
return true;
}
return false;
--- 1296,1307 ----
// in order to not swamp the ServiceThread.
_last_async_deflation_time_ns = os::javaTimeNanos();
return true;
}
int monitors_used = Atomic::load(&om_list_globals._population) -
! Atomic::load(&om_list_globals._free_count) -
! Atomic::load(&om_list_globals._wait_count);
if (is_MonitorBound_exceeded(monitors_used)) {
// Not enough ObjectMonitors on the global free list.
return true;
}
return false;
*** 1496,1510 ****
break; // No more are available.
}
guarantee(take->object() == NULL, "invariant");
if (AsyncDeflateIdleMonitors) {
// We allowed 3 field values to linger during async deflation.
! // We clear header and restore ref_count here, but we leave
! // owner == DEFLATER_MARKER so the simple C2 ObjectMonitor
! // enter optimization can no longer race with async deflation
! // and reuse.
take->set_header(markWord::zero());
if (take->ref_count() < 0) {
// Add back max_jint to restore the ref_count field to its
// proper value.
Atomic::add(&take->_ref_count, max_jint);
--- 1470,1483 ----
break; // No more are available.
}
guarantee(take->object() == NULL, "invariant");
if (AsyncDeflateIdleMonitors) {
// We allowed 3 field values to linger during async deflation.
! // Clear or restore them as appropriate.
take->set_header(markWord::zero());
+ // DEFLATER_MARKER is the only non-NULL value we should see here.
+ take->try_set_owner_from(DEFLATER_MARKER, NULL);
if (take->ref_count() < 0) {
// Add back max_jint to restore the ref_count field to its
// proper value.
Atomic::add(&take->_ref_count, max_jint);
*** 2041,2053 ****
ADIM_guarantee(mark.is_neutral(), "invariant: header=" INTPTR_FORMAT, mark.value());
ObjectMonitor* m = om_alloc(self);
// prepare m for installation - set monitor to initial state
m->Recycle();
m->set_header(mark);
! // If we leave _owner == DEFLATER_MARKER here, then the simple C2
! // ObjectMonitor enter optimization can no longer race with async
! // deflation and reuse.
m->set_object(object);
m->_Responsible = NULL;
m->_SpinDuration = ObjectMonitor::Knob_SpinLimit; // consider: keep metastats by type/class
omh_p->set_om_ptr(m);
--- 2014,2027 ----
ADIM_guarantee(mark.is_neutral(), "invariant: header=" INTPTR_FORMAT, mark.value());
ObjectMonitor* m = om_alloc(self);
// prepare m for installation - set monitor to initial state
m->Recycle();
m->set_header(mark);
! if (AsyncDeflateIdleMonitors) {
! // DEFLATER_MARKER is the only non-NULL value we should see here.
! m->try_set_owner_from(DEFLATER_MARKER, NULL);
! }
m->set_object(object);
m->_Responsible = NULL;
m->_SpinDuration = ObjectMonitor::Knob_SpinLimit; // consider: keep metastats by type/class
omh_p->set_om_ptr(m);
*** 2179,2192 ****
}
// Restore the header back to obj
obj->release_set_mark(dmw);
if (AsyncDeflateIdleMonitors) {
! // clear() expects the owner field to be NULL and we won't race
! // with the simple C2 ObjectMonitor enter optimization since
! // we're at a safepoint. DEFLATER_MARKER is the only non-NULL
! // value we should see here.
mid->try_set_owner_from(DEFLATER_MARKER, NULL);
}
mid->clear();
assert(mid->object() == NULL, "invariant: object=" INTPTR_FORMAT,
--- 2153,2164 ----
}
// Restore the header back to obj
obj->release_set_mark(dmw);
if (AsyncDeflateIdleMonitors) {
! // clear() expects the owner field to be NULL.
! // DEFLATER_MARKER is the only non-NULL value we should see here.
mid->try_set_owner_from(DEFLATER_MARKER, NULL);
}
mid->clear();
assert(mid->object() == NULL, "invariant: object=" INTPTR_FORMAT,
*** 2309,2320 ****
p2i(mid->object()));
assert(mid->is_free(), "must be free: allocation_state=%d",
(int) mid->allocation_state());
// Move the deflated ObjectMonitor to the working free list
! // defined by free_head_p and free_tail_p. No races on this list
! // so no need for load_acquire() or store_release().
if (*free_head_p == NULL) {
// First one on the list.
*free_head_p = mid;
}
if (*free_tail_p != NULL) {
--- 2281,2291 ----
p2i(mid->object()));
assert(mid->is_free(), "must be free: allocation_state=%d",
(int) mid->allocation_state());
// Move the deflated ObjectMonitor to the working free list
! // defined by free_head_p and free_tail_p.
if (*free_head_p == NULL) {
// First one on the list.
*free_head_p = mid;
}
if (*free_tail_p != NULL) {
*** 2467,2478 ****
om_lock(mid);
next = unmarked_next(mid);
}
while (true) {
! // The current mid's next field is marked at this point. If we have
! // a cur_mid_in_use, then its next field is also marked at this point.
if (next != NULL) {
// We lock next so that an om_flush() thread that is behind us
// cannot pass us when we unlock the current mid.
om_lock(next);
--- 2438,2449 ----
om_lock(mid);
next = unmarked_next(mid);
}
while (true) {
! // The current mid is locked at this point. If we have a
! // cur_mid_in_use, then it is also locked at this point.
if (next != NULL) {
// We lock next so that an om_flush() thread that is behind us
// cannot pass us when we unlock the current mid.
om_lock(next);
*** 2667,2678 ****
Atomic::load(&om_list_globals._wait_count));
// The ServiceThread's async deflation request has been processed.
set_is_async_deflation_requested(false);
! if (HandshakeAfterDeflateIdleMonitors &&
! Atomic::load(&om_list_globals._wait_count) > 0) {
// There are deflated ObjectMonitors waiting for a handshake
// (or a safepoint) for safety.
ObjectMonitor* list = Atomic::load(&om_list_globals._wait_list);
ADIM_guarantee(list != NULL, "om_list_globals._wait_list must not be NULL");
--- 2638,2648 ----
Atomic::load(&om_list_globals._wait_count));
// The ServiceThread's async deflation request has been processed.
set_is_async_deflation_requested(false);
! if (Atomic::load(&om_list_globals._wait_count) > 0) {
// There are deflated ObjectMonitors waiting for a handshake
// (or a safepoint) for safety.
ObjectMonitor* list = Atomic::load(&om_list_globals._wait_list);
ADIM_guarantee(list != NULL, "om_list_globals._wait_list must not be NULL");
*** 2749,2759 ****
deflate_monitor_list_using_JT(&om_list_globals._in_use_list,
&om_list_globals._in_use_count,
&free_head_p, &free_tail_p,
&saved_mid_in_use_p);
} else {
! local_deflated_count = deflate_monitor_list_using_JT(&target->om_in_use_list, &target->om_in_use_count, &free_head_p, &free_tail_p, &saved_mid_in_use_p);
}
deflated_count += local_deflated_count;
if (free_head_p != NULL) {
// Move the deflated ObjectMonitors to the global free list.
--- 2719,2732 ----
deflate_monitor_list_using_JT(&om_list_globals._in_use_list,
&om_list_globals._in_use_count,
&free_head_p, &free_tail_p,
&saved_mid_in_use_p);
} else {
! local_deflated_count =
! deflate_monitor_list_using_JT(&target->om_in_use_list,
! &target->om_in_use_count, &free_head_p,
! &free_tail_p, &saved_mid_in_use_p);
}
deflated_count += local_deflated_count;
if (free_head_p != NULL) {
// Move the deflated ObjectMonitors to the global free list.
*** 2769,2783 ****
#ifdef ASSERT
ObjectMonitor* l_next_om = unmarked_next(free_tail_p);
#endif
assert(l_next_om == NULL, "must be NULL: _next_om=" INTPTR_FORMAT, p2i(l_next_om));
- if (HandshakeAfterDeflateIdleMonitors) {
prepend_list_to_global_wait_list(free_head_p, free_tail_p, local_deflated_count);
- } else {
- prepend_list_to_global_free_list(free_head_p, free_tail_p, local_deflated_count);
- }
OM_PERFDATA_OP(Deflations, inc(local_deflated_count));
}
if (saved_mid_in_use_p != NULL) {
--- 2742,2752 ----
*** 3041,3054 ****
chk_global_in_use_list_and_count(ls, &error_cnt);
// Check om_list_globals._free_list and om_list_globals._free_count:
chk_global_free_list_and_count(ls, &error_cnt);
- if (HandshakeAfterDeflateIdleMonitors) {
// Check om_list_globals._wait_list and om_list_globals._wait_count:
chk_global_wait_list_and_count(ls, &error_cnt);
- }
ls->print_cr("Checking per-thread lists:");
for (JavaThreadIteratorWithHandle jtiwh; JavaThread *jt = jtiwh.next(); ) {
// Check om_in_use_list and om_in_use_count:
--- 3010,3021 ----
*** 3431,3444 ****
int l_free_count = Atomic::load(&om_list_globals._free_count);
int l_wait_count = Atomic::load(&om_list_globals._wait_count);
out->print_cr("%18s %10d %10d %10d %10d", "", l_in_use_count,
l_free_count, l_wait_count,
Atomic::load(&om_list_globals._population));
! pop_count += l_in_use_count + l_free_count;
! if (HandshakeAfterDeflateIdleMonitors) {
! pop_count += l_wait_count;
! }
out->print_cr("%18s %10s %10s %10s",
"Per-Thread Lists:", "InUse", "Free", "Provision");
out->print_cr("================== ========== ========== ==========");
--- 3398,3408 ----
int l_free_count = Atomic::load(&om_list_globals._free_count);
int l_wait_count = Atomic::load(&om_list_globals._wait_count);
out->print_cr("%18s %10d %10d %10d %10d", "", l_in_use_count,
l_free_count, l_wait_count,
Atomic::load(&om_list_globals._population));
! pop_count += l_in_use_count + l_free_count + l_wait_count;
out->print_cr("%18s %10s %10s %10s",
"Per-Thread Lists:", "InUse", "Free", "Provision");
out->print_cr("================== ========== ========== ==========");
< prev index next >