Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: Added "deflate_monitor_list_using_JT()" subsection; minor edits elsewhere.

...

    • L02 is used mark self's in-use list head:
      • 'mid' is self's in-use list head and its next field is marked.
      • 'next' is the unmarked next field from 'mid'.
    • L03 → L20: self's in-use list is traversed looking for the target ObjectMonitor 'm':
      • L04: if the current 'mid' matches 'm':
        • L05: if we can't cmpxchg self's in-use list head to the 'next' ObjectMonitor*:
          Note: This cmpxchg only works if 'm' is self's in-use list head and no-harm-no-foul if 'm' is not self's in-use list head. This is faster than doing a load-acquire of self's in-use list head, checking the value and then calling cmpxchg.
          • L06: make a marked copy of 'mid'
          • L07: we cmpxchg cur_mid_in_use's next field to from 'marked_mid' to 'next'.
            Note: We use cmpxchg here instead of release-store so that we can sanity check the result; see the real code.
        • L09 → L12: we've successfully extracted 'm' from self's in-use list so we decrement self's in-use counter, unmark the next field in 'mid' and we're done.
      • L1[45]: if cur_mid_in_use != NULL, then unmark its next field.
      • L17: set 'cur_mid_in_use' to 'mid'
        Note: cur_mid_in_use keeps the marked next field so that it remains stable for a possible next field change. It cannot be deflated while it is marked.
      • L18: set 'mid' to 'next'.
      • L19: mark next field in the new 'mid' and update 'next'; loop around and do it all again.

...

    • L09 marks the 'list_p' head (if it is not empty):
      • 'mid' is 'list_p's head and its next field is marked.
      • 'next' is the unmarked next field from 'mid'.
    • L12-L32: We walk each 'mid' in the list and determine if it can be deflated:
      • L14: if 'mid' is associated with an object and can be deflated:
        • L15: if we can't cmpxchg 'list_p' to the 'next' ObjectMonitor*:
          Note: This cmpxchg only works if 'mid' is 'list_p's list head and no-harm-no-foul if 'mid' is not 'list_p's list head. This is faster than doing a load-acquire of 'list_p', checking the value and then calling cmpxchg.
          • L16: we cmpxchg cur_mid_in_use's next field from 'mid' to 'next'.
            Note: We use cmpxchg here instead of release-store so that we can sanity check the result; see the real code.
        • L18 → L21: we've successfully extracted 'mid' from 'list_p's list so we increment 'deflated_count', decrement the counter referred to by 'count_p', set 'mid's next field to NULL and we're done.
          Note: 'mid' is the current tail in the 'free_head_p' list so we have to NULL terminate it (which also unmarks it).
      • L2[2-5]: 'mid' can't be deflated so unmark mid's next field and advance both 'cur_mid_in_use' and 'mid'.
      • L2[78]: we reached the end of the list so break out of the loop.
      • L30: mark next field in the new 'mid' and update 'next'; loop around and do it all again.
    • L32: all done so return 'deflated_count'.

ObjectSynchronizer::deflate_monitor_list_using_JT(ObjectMonitor* volatile * list_p, int volatile * count_p, ObjectMonitor** free_head_p, ObjectMonitor** free_tail_p, ObjectMonitor** saved_mid_p)

ObjectSynchronizer::deflate_monitor_list_using_JT() is responsible for asynchronously deflating idle ObjectMonitors using a JavaThread. This function uses the more complicated mark-cur_mid_in_use-and-mid-as-we-go protocol because om_release() can do list deletions in parallel. We also mark-next-next-as-we-go to prevent an om_flush() that is behind this thread from passing us. Because this function can asynchronously interact with so many other functions, this is the largest clip of code:

    L01:  int ObjectSynchronizer::deflate_monitor_list_using_JT(ObjectMonitor* volatile * list_p,
    L02:                                                        int volatile * count_p,
    L03:                                                        ObjectMonitor** free_head_p,
    L04:                                                        ObjectMonitor** free_tail_p,
    L05:                                                        ObjectMonitor** saved_mid_in_use_p) {
    L06:    ObjectMonitor* cur_mid_in_use = NULL;
    L07:    ObjectMonitor* mid = NULL;
    L08:    ObjectMonitor* next = NULL;
    L09:    ObjectMonitor* next_next = NULL;
    L10:    int deflated_count = 0;
    L11:    if (*saved_mid_in_use_p == NULL) {
    L12:      if (!mark_list_head(list_p, &mid, &next)) {
    L13:        return 0;  // The list is empty so nothing to deflate.
    L14:      }
    L15:    } else {
    L16:      cur_mid_in_use = *saved_mid_in_use_p;
    L17:      mid = mark_next_loop(cur_mid_in_use);
    L18:      if (mid == NULL) {
    L19:        set_next(cur_mid_in_use, NULL);  // unmark next field
    L20:        *saved_mid_in_use_p = NULL;
    L21:        return 0;  // The remainder is empty so nothing more to deflate.
    L22:      }
    L23:      next = mark_next_loop(mid);
    L24:    }
    L25:    while (true) {
    L26:      if (next != NULL) {
    L27:        next_next = mark_next_loop(next);
    L28:      }
    L29:      if (mid->object() != NULL && mid->is_old() &&
    L30:          deflate_monitor_using_JT(mid, free_head_p, free_tail_p)) {
    L31:        if (Atomic::cmpxchg(next, list_p, mid) != mid) {
    L32:          ObjectMonitor* marked_mid = mark_om_ptr(mid);
    L33:          ObjectMonitor* marked_next = mark_om_ptr(next);
    L34:          Atomic::cmpxchg(marked_next, &cur_mid_in_use->_next_om, marked_mid);
    L35:        }
    L36:        deflated_count++;
    L37:        Atomic::dec(count_p);
    L38:        set_next(mid, NULL);
    L39:        mid = next;  // mid keeps non-NULL next's marked next field
    L40:        next = next_next;
    L41:      } else {
    L42:        if (cur_mid_in_use != NULL) {
    L43:          set_next(cur_mid_in_use, mid);  // umark cur_mid_in_use
    L44:        }
    L45:        cur_mid_in_use = mid;
    L46:        mid = next;  // mid keeps non-NULL next's marked next field
    L47:        next = next_next;
    L48:        if (SafepointSynchronize::is_synchronizing() &&
    L49:            cur_mid_in_use != OrderAccess::load_acquire(list_p) &&
    L50:            cur_mid_in_use->is_old()) {
    L51:          *saved_mid_in_use_p = cur_mid_in_use;
    L52:          set_next(cur_mid_in_use, mid);  // umark cur_mid_in_use
    L53:          if (mid != NULL) {
    L54:            set_next(mid, next);  // umark mid
    L55:          }
    L56:          return deflated_count;
    L57:        }
    L58:      }
    L59:      if (mid == NULL) {
    L60:        if (cur_mid_in_use != NULL) {
    L61:          set_next(cur_mid_in_use, mid);  // umark cur_mid_in_use
    L62:        }
    L63:        break;  // Reached end of the list so nothing more to deflate.
    L64:      }
    L65:    }
    L66:    *saved_mid_in_use_p = NULL;
    L67:    return deflated_count;
    L68:  }

The above is not an exact copy of the code block from deflate_monitor_list_using_JT(), but it is the highlights. What the above code block needs to do is pretty simple:

    • Walk the list and deflate any idle ObjectMonitor that is associated with an object.
    • 'free_head_p' and 'free_tail_p' track the list of deflated ObjectMonitors.
    • 'deflated_count' is the number of deflated ObjectMonitors on the 'free_head_p' list.

Since we're using the more complicated mark-cur_mid_in_use-and-mid-as-we-go protocol and also the mark-next-next-as-we-go protocol, there is a mind numbing amount of detail:

    • L1[14]: Handle the initial setup if we are not resuming after a safepoint:
      • L12 marks the 'list_p' head (if it is not empty):
        • 'mid' is 'list_p's head and its next field is marked.
        • 'next' is the unmarked next field from 'mid'.
    • L15-L23: Handle the initial setup if we are resuming after a safepoint:
      • L17: mark next field in 'cur_mid_in_use' and update 'mid'
      • L18-L21: If 'mid' == NULL, then we've resumed context at the end of the list so we're done.
      • L23: mark next field in 'mid' and update 'next'
    • L25-L65: We walk each 'mid' in the list and determine if it can be deflated:
      • L2[67]: if next != NULL, thenmark next field in 'next' and update 'next_next'
      • L29-L30: if 'mid' is associated with an object, 'mid' is old, and can be deflated:
        • L31: if we can't cmpxchg 'list_p' to the 'next' ObjectMonitor*:
          Note: This cmpxchg only works if 'mid' is 'list_p's list head and no-harm-no-foul if 'mid' is not 'list_p's list head. This is faster than doing a load-acquire of 'list_p', checking the value and then calling cmpxchg.
          • L32: make a marked copy of 'mid'
          • L33: make a marked copy of 'next'
          • L34: we cmpxchg cur_mid_in_use's next field from 'marked_mid' to 'marked_next'.
            Note: We use cmpxchg here instead of release-store so that we can sanity check the result; see the real code.
        • L36 → L38: we've successfully extracted 'mid' from 'list_p's list so we increment 'deflated_count', decrement the counter referred to by 'count_p', set 'mid's next field to NULL and we're done.
          Note: 'mid' is the current tail in the 'free_head_p' list so we have to NULL terminate it (which also unmarks it).
        • L39: advance 'mid' to 'next'.
          Note: 'mid' keeps non-NULL 'next's marked next field.
        • L40: advance 'next' to 'next_next'.
      • L41-L57: 'mid' can't be deflated so we have to carefully advance the list pointers:
        • L4[23]: if cur_mid_in_use != NULL, then unmark next field in 'cur_mid_in_use'.
        • L45: advance 'cur_mid_in_use' to 'mid'.
          Note: The next field in 'mid' is still marked and 'cur_mid_in_use' keeps that.
        • L46: advance 'mid' to 'next'.
          Note: The next field in a non-NULL 'next' is still marked and 'mid' keeps that.
        • L47: advance 'next' to 'next_next'.
        • L48-L56: Handle a safepoint if one has started and it is safe to do so.
      • L59-L63: we reached the end of the list:
        • L6[01]: if cur_mid_in_use != NULL, then unmark next field in 'cur_mid_in_use'.
        • L63: break out of the loop because we are done
    • L66: not pausing for a safepoint so clear saved state.
    • L67: all done so return 'deflated_count'.

...