Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: Add "T-deflate and T-hash Both Lose" subsection.

...

    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)else {
        monitor) { | owner=DEFLATER_MARKER | atomic add max_jint to contentionscmpxchg(NULL, &owner, DEFLATER_MARKER)
        atomic dec ref_count | contentions=-max_jint | atomic 3>add bailoutmax_jint onto deflationcontentions
        return false to | ref_count=1 | 3> bailout on }deflation
      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.

T-deflate and T-hash Both Lose

This subsection title is NOT a typo. It is possible for both T-deflate and T-hash to lose the race.

    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=NULL |    ref_count == 0) {
      }        | contentions=0 |  } else {
| ref_count=0 | cmpxchg(NULL, &owner, DEFLATER_MARKER)
+-----------------------+ atomic add max_jint to contentions
2> bailout on 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-hash observes "owner == DEFLATER_MARKER && contentions <= 0" and starts to bail out.
    • T-deflate sees "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 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.
    • When T-hash retries:
      • the object's header will still refer to the ObjectMonitor (i.e., not deflated)
      • it will observe "owner != DEFLATER_MARKER"
        • if the ObjectMonitor's header/dmw does not have a hash, then generate a hash and merge it with the ObjectMonitor's header/dmw.
        • extract the hash from the ObjectMonitor's header/dmw and return it.

Please note that in Carsten's original prototype, there was another race in ObjectSynchronizer::FastHashCode() when the object's monitor had to be inflated. The setting of the hashcode in the ObjectMonitor's header/dmw could race with T-deflate. That race is resolved in this version by the use of an ObjectMonitorHandle in the call to ObjectSynchronizer::inflate(). The ObjectMonitor* returned by ObjectMonitorHandle.om_ptr() has a non-zero ref_count so no additional races with T-deflate are possible.

...