...
T-hash ObjectMonitor T-deflate
---------------------- +-----------------------+ ----------------------------------------
save_om_ptr() { | owner=NULL | deflate_monitor_using_JT() {
: | contentions=0 | cmpxchg(DEFLATER_MARKER, &owner, NULL)
atomic inc ref_count | ref_count=0 |
+-----------------------+
...
T-hash ObjectMonitor T-deflate
---------------------- +-----------------------+ --------------------------------------------
save_om_ptr() { | owner=DEFLATER_MARKER | deflate_monitor_using_JT() {
: | contentions=0 | cmpxchg(DEFLATER_MARKER, &owner, NULL)
atomic inc ref_count | ref_count=0 | if (waiters != 0 || ref_count != 0) {
+-----------------------+ }
prev = cmpxchg(-max_jint, &contentions, 0)
...
T-hash ObjectMonitor T-deflate
------------------------ +-----------------------+ --------------------------------------------
save_om_ptr() { | owner=DEFLATER_MARKER | deflate_monitor_using_JT() {
atomic inc ref_count | contentions=-max_jint | cmpxchg(DEFLATER_MARKER, &owner, NULL)
1> if (owner == | ref_count=1 | if (waiters != 0 || ref_count != 0) {
DEFLATER_MARKER && +-----------------------+ }
contentions <= 0) { || prev = cmpxchg(-max_jint, &contentions, 0)
atomic dec ref_count \/ 1> if (prev == 0 &&
2> return false to +-----------------------+ owner == DEFLATER_MARKER) {&&
cause a retry | owner=DEFLATER_MARKER | restore obj headerref_count == 0) {
} | contentions=-max_jint | 2> finishrestore theobj deflationheader
| ref_count=0 | 2> finish the }deflation
+-----------------------+ }
- T-deflate made it past the first ref_count check before T-hash incremented it.
- T-deflate set the contentions field to -max_jint and T-enter incremented the ref_count field.
- The first ObjectMonitor box is showing the fields at this point and the "1>" markers are showing where each thread is at for that ObjectMonitor box.
- T-deflate has won the race so it restores obj header (not shown) and finishes the deflation.T-hash observes "owner == DEFLATER_MARKER && contentions <= 0" so it decrements ref_count and returns false to cause a retry.
- The second ObjectMonitor box is showing the fields at this point and the "2>" markers are showing where each thread is at for that ObjectMonitor box.
- If T-deflate sees "prev == 0 && owner == DEFLATER_MARKER && ref_count == 0", then it has won the race so it restores obj header (not shown) and finishes the deflation.
- The second ObjectMonitor box is showing the fields at this point and the "2>" markers are showing where each thread is at for that ObjectMonitor box.
- When T-hash When T-hash retries:
- if it observes "owner == DEFLATER_MARKER && contentions <= 0" it will retry again.
- if it observes the restored object header:
- if the object's header does not have a hash, then generate a hash and merge it with the object's header.
- extract the hash from the object's header and return it.
T-hash Wins Scenario 1
If T-hash wins the race, then the ref_count will cause T-deflate to bail out on deflating the monitor. Note: header is not mentioned in any of the previous sections for simplicity.
T-hash ObjectMonitor T-deflate
------------------------ +-----------------------+ --------------------------------------------
save_om_ptr() { | header=dmw_no_hash | deflate_monitor_using_JT() {
atomic inc ref_count | owner=DEFLATER_MARKER | cmpxchg(DEFLATER_MARKER, &owner, NULL)
1> if (owner == | contentions=0 | 1> if (waiters != 0 || ref_count != 0) {
DEFLATER_MARKER && | ref_count=1 | cmpxchg(NULL, &owner, DEFLATER_MARKER)
contentions <= 0) { +-----------------------+ 2> bailout on deflation
} || }
if (object no longer \/ prev = cmpxchg(-max_jint, &contentions, 0)
has a monitor or +-----------------------+
is a different | header=dmw_no_hash |
monitor) { | owner=NULL |
atomic dec ref_count | contentions=0 |
return false to | ref_count=1 |
cause a retry +-----------------------+
} ||
2> save om_ptr in the \/
ObjectMonitorHandle +-----------------------+
} | header=dmw_hash |
if save_om_ptr() { | owner=NULL |
if no hash | contentions=0 |
gen hash & merge | ref_count=1 |
hash = hash(header) +-----------------------+
}
3> atomic dec ref_count
return hash
- T-hash has incremented ref_count before T-deflate made it past that check.
- The first ObjectMonitor box is showing the fields at this point and the "1>" markers are showing where each thread is at for that ObjectMonitor box.
- T-deflate bails out on deflation, but first it tries to restore the owner field.:
- The return value of cmpxchg() is not checked here.
- If T-deflate cannot restore the owner field to NULL, then another thread has managed to enter the monitor (or enter and exit the monitor) and we don't want to overwrite that information.
- T-hash observes:
- "owner == DEFLATER_MARKER && contentions == 0" or
- "owner == NULL && contentions == 0" so it does not cause a retry.
- T-hash verifies that the object still has a monitor and that monitor still refers to our current ObjectMonitor.
- The second ObjectMonitor box is showing the fields at this point and the "2>" markers are showing where each thread is at for that ObjectMonitor box.
- if save_om_ptr() returns true ObjectMonitor is safe:
- if ObjectMonitor's 'header/dmw' field does not have a hash, then generate a hash and merge it with the 'header/dmw' field.
- extract the hash from the ObjectMonitor's 'header/dmw' field.
- The third ObjectMonitor box is showing the fields at this point and the "3>" marker is showing where T-hash is at for that ObjectMonitor box.
- T-hash decrements the ref_count field.
- T-hash returns the hash value.
T-hash Wins Scenario 2
If T-hash wins the race, then the ref_count will cause T-deflate to bail out on deflating the monitor. Note: header is not mentioned in any of the previous sections for simplicity.
T-hash ObjectMonitor T-deflate
------------------------ +-----------------------+ ------------------------------------------
save_om_ptr() { | header=dmw_no_hash | deflate_monitor_using_JT() {
atomic inc ref_count | owner=DEFLATER_MARKER | cmpxchg(DEFLATER_MARKER, &owner, NULL)
if (owner == | contentions=0 | if (waiters != 0 || ref_count != 0) {
DEFLATER_MARKER && | ref_count=1 | }
contentions <= 0) { +-----------------------+ 1> prev = cmpxchg(-max_jint, &contentions, 0)
} || 2> if (prev == 0 &&
1> if (object no longer \/ owner == DEFLATER_MARKER &&
has a monitor or +-----------------------+ ref_count == 0) {
is a different | header=dmw_no_hash | cmpxchg(NULL, &owner, DEFLATER_MARKER)
monitor) { | owner=DEFLATER_MARKER | atomic add max_jint to contentions
atomic dec ref_count | contentions=-max_jint | 3> bailout on deflation
return false to | ref_count=1 | }
cause a retry +-----------------------+
} ||
2> save om_ptr in the \/
ObjectMonitorHandle +-----------------------+
} | header=dmw_hash |
if save_om_ptr() { | owner=NULL |
if no hash | contentions=0 |
gen hash & merge | ref_count=1 |
hash = hash(header) +-----------------------+
}
3> atomic dec ref_count
return hash
- T-deflate made it past the first ref_count check before T-hash incremented it.
- T-hash made it past the "owner == DEFLATER_MARKER && contentions <= 0" check before T-deflate updated contentions.
- The first ObjectMonitor box is showing the fields at this point and the "1>" markers are showing where each thread is at for that ObjectMonitor box.
- T-deflate set the contentions field to -max_jint and is about the make the last of the protocol checks.
- The second ObjectMonitor box is showing the fields at this point and the "2>" markers are showing where each thread is at for that ObjectMonitor box.
- T-deflate sees that "ref_count != 0" and bails out on deflation but it has to restore some data if possible:
- The return value of cmpxchg() is not checked here.
- If T-deflate cannot restore the owner field to NULL, then another thread has managed to enter the monitor (or enter and exit the monitor) and we don't want to overwrite that information.
- Add back max_jint to restore the contentions field to its proper value (which may not be the same as when we started).
- T-hash verifies that the object still has a monitor and that monitor still refers to our current ObjectMonitor.
- if save_om_ptr() returns true ObjectMonitor is safe:
- if ObjectMonitor's 'header/dmw' field does not have a hash, then generate a hash and merge it with the 'header/dmw' field.
- extract the hash from the ObjectMonitor's 'header/dmw' field.
- The third ObjectMonitor box is showing the fields at this point and the "3>" markers are showing where each thread is at for that ObjectMonitor box.
- T-hash decrements the ref_count field.
- T-hash returns the hash value.
...