- Loading...
...
For example, when ObjectMonitor::enter() detects genuine contention via the owner field, it atomically increments the count field to indicate that the ObjectMonitor is busy. The thread calling enter() (T-enter) is potentially racing with an Async Monitor Deflation by another JavaThread (T-deflate) so both threads have to check the result of the race.
...
ObjectMonitor T-deflate
...
T-enter +-----------------------+ --------------------------------------
...
---------------- | owner=NULL | cmpxchg(DEFLATER_MARKER, &owner, NULL)
...
| count=0 |
...
+-----------------------+
ObjectMonitor T-deflate
T-enter +-----------------------+ --------------------------------------
---------------- | owner=DEFLATER_MARKER | cmpxchg(DEFLATER_MARKER, &owner, NULL)
owner contended | count=0 | :
atomic inc count +-----------------------+ prev = cmpxchg(-max_jint, &count, 0)
If T-enter and T-deflate observe owner == DEFLATER_MARKER and a negative count field, then T-enter has lost the race and it retries. T-deflate will finish deflation of the ObjectMonitor.
ObjectMonitor T-deflate
T-enter +-----------------------+ --------------------------------------
---------------- | owner=DEFLATER_MARKER | cmpxchg(DEFLATER_MARKER, &owner, NULL)
owner contended | count=-max_jint | :
atomic inc count +-----------------------+ prev = cmpxchg(-max_jint, &count, 0)
if (count <= 0 && owner if (prev == 0 &&
== DEFLATER_MARKER) { owner == DEFLATER_MARKER) {
restore header restore header
retry enter finish the deflation
} }
If T-enter and T-deflate observe a count field > 0, then T-enter has won the race and it can proceed with the normal contended enter work. T-deflate will detect that it has lost the race and will bailout on deflating that ObjectMonitor.
ObjectMonitor T-deflate
T-enter +-----------------------+ --------------------------------------
---------------- | owner=DEFLATER_MARKER | cmpxchg(DEFLATER_MARKER, &owner, NULL)
owner contended | count=1 | :
atomic inc count +-----------------------+ prev = cmpxchg(-max_jint, &count, 0)
if (count > 0) if (prev != 0 ||
do contended owner != DEFLATER_MARKER)
enter work bailout on deflation
...
ObjectMonitor::install_displaced_markword_in_object() is called from two places so we can have a race between a T-enter thread and a T-deflate thread:
T-enter object T-deflate
----------------------------------------- +-------------+ -----------------------------------------
dmw = header() | mark=om_ptr | dmw = header()
if (!dmw->is_marked() && +-------------+ if (!dmw->is_marked() &&
dmw->hash() == 0) { dmw->hash() == 0) {
create marked_dmw create marked_dmw
dmw = cmpxchg(marked_dmw, &header, dmw) dmw = cmpxchg(marked_dmw, &header, dmw)
} }
T-enter object T-deflate
----------------------------------------- +-------------+ -----------------------------------------
dmw = header() | mark=om_ptr | dmw = header()
if (!dmw->is_marked() && +-------------+ if (!dmw->is_marked() &&
dmw->hash() == 0) { dmw->hash() == 0) {
create marked_dmw create marked_dmw
dmw = cmpxchg(marked_dmw, &header, dmw) dmw = cmpxchg(marked_dmw, &header, dmw)
} }
// dmw == marked_dmw here // dmw == original dmw here
if (dmw->is_marked()) if (dmw->is_marked())
unmark dmw unmark dmw
obj = object() obj = object()
obj->cas_set_mark(dmw, this) obj->cas_set_mark(dmw, this)
T-enter object T-deflate
----------------------------------------- +-------------+ -----------------------------------------
dmw = header() | mark=om_ptr | dmw = header()
if (!dmw->is_marked() && +-------------+ if (!dmw->is_marked() &&
dmw->hash() == 0) { dmw->hash() == 0) {
create marked_dmw create marked_dmw
dmw = cmpxchg(marked_dmw, &header, dmw) dmw = cmpxchg(marked_dmw, &header, dmw)
} }
// dmw == original dmw here // dmw == marked_dmw here
if (dmw->is_marked()) if (dmw->is_marked())
unmark dmw unmark dmw
obj = object() obj = object()
obj->cas_set_mark(dmw, this) obj->cas_set_mark(dmw, this)
T-enter object T-deflate
----------------------------------------- +-------------+ -----------------------------------------
dmw = header() | mark=dmw | dmw = header()
if (!dmw->is_marked() && +-------------+ if (!dmw->is_marked() &&
dmw->hash() == 0) { dmw->hash() == 0) {
create marked_dmw create marked_dmw
dmw = cmpxchg(marked_dmw, &header, dmw) dmw = cmpxchg(marked_dmw, &header, dmw)
} }
// dmw == original dmw here // dmw == marked_dmw here
if (dmw->is_marked()) if (dmw->is_marked())
unmark dmw unmark dmw
obj = object() obj = object()
obj->cas_set_mark(dmw, this) obj->cas_set_mark(dmw, this)
Please notice that install_displaced_markword_in_object() does not do any retries on any code path. Instead the code adapts to being the loser in a cmpxchg() by unmarking its copy of the dmw. In the second race, if a thread loses the cas_set_mark() race, there is
also no need to retry because the object's header has been restored by the other thread.
...
If we have a race between a T-deflate thread and a thread trying to get/set a hash code (T-hash), then the first race is between the
ObjectMonitorHandle.save_om_ptr(obj, mark) call in T-hash and deflation protocol in T-deflate.
T-hash ObjectMonitor T-deflate
---------------------- +-----------------------+ --------------------------------------
save_om_ptr() { | owner=NULL | cmpxchg(DEFLATER_MARKER, &owner, NULL)
: | count=0 |
atomic inc ref_count | ref_count=0 |
+-----------------------+
T-hash ObjectMonitor T-deflate
---------------------- +-----------------------+ --------------------------------------
save_om_ptr() { | owner=DEFLATER_MARKER | cmpxchg(DEFLATER_MARKER, &owner, NULL)
atomic inc ref_count | count=-max_jint | if (waiters != 0 or ref_count != 0) {
| ref_count=1 | }
+-----------------------+ prev = cmpxchg(-max_jint, &count, 0)
T-hash ObjectMonitor T-deflate
------------------------ +-----------------------+ --------------------------------------
save_om_ptr() { | owner=DEFLATER_MARKER | cmpxchg(DEFLATER_MARKER, &owner, NULL)
atomic inc ref_count | count=-max_jint | if (waiters != 0 or ref_count != 0) {
if (owner == | ref_count=0 | }
DEFLATER_MARKER) { +-----------------------+ prev = cmpxchg(-max_jint, &count, 0)
atomic dec ref_count if (prev == 0 &&
return false to owner == DEFLATER_MARKER) {
cause a retry restore header
} finish the deflation
}
T-hash ObjectMonitor T-deflate
------------------------ +-----------------------+ ----------------------------------------
save_om_ptr() { | owner=NULL | cmpxchg(DEFLATER_MARKER, &owner, NULL)
atomic inc ref_count | count=0 | if (waiters != 0 or ref_count != 0) {
if (owner == | ref_count=1 | cmpxchg(NULL, &owner, DEFLATER_MARKER)
DEFLATER_MARKER) { +-----------------------+ return false to cause a retry
} if (prev == 0 &&
if (object no longer owner == DEFLATER_MARKER) {
has a monitor or restore header
is a different finish the deflation
monitor) { }
atomic dec ref_count
return false to
cause a retry
}
save om_ptr in the
ObjectMonitorHandle
}
If T-hash wins the first race, then the ref_count will cause T-deflate to bail out on deflating the monitor; ref_count is not mentioned in any of the previous examples for simplicity. If T-deflate wins the race, then T-hash will retry which will bring us to the second race.
...