Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: Add deflate_monitor_list().

...

    • 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 'marked_mid'.
            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.

The last line of the code block (L22) prepends 'm' to self's free list.

...

    • prepend_list_to_g_free_list(free_list, free_tail, free_count);
    • prepend_list_to_g_om_in_use_list(in_use_list, in_use_tail, in_use_count);

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

ObjectSynchronizer::deflate_monitor_list() is responsible for deflating idle ObjectMonitors at a safepoint. This function can use the simpler mark-mid-as-we-go protocol since there can be no parallel list deletions due to the safepoint:

    L01:  int ObjectSynchronizer::deflate_monitor_list(ObjectMonitor* volatile * list_p,
    L02:                                               int volatile * count_p,
    L03:                                               ObjectMonitor** free_head_p,
    L04:                                               ObjectMonitor** free_tail_p) {
    L05:    ObjectMonitor* cur_mid_in_use = NULL;
    L06:    ObjectMonitor* mid = NULL;
    L07:    ObjectMonitor* next = NULL;
    L08:    int deflated_count = 0;
    L09:    if (!mark_list_head(list_p, &mid, &next)) {
    L10:      return 0;  // The list is empty so nothing to deflate.
    L11:    }
    L12:    while (true) {
    L13:      oop obj = (oop) mid->object();
    L14:      if (obj != NULL && deflate_monitor(mid, obj, free_head_p, free_tail_p)) {
    L15:        if (Atomic::cmpxchg(next, list_p, mid) != mid) {
    L16:          Atomic::cmpxchg(next, &cur_mid_in_use->_next_om, mid);
    L17:        }
    L18:        deflated_count++;
    L19:        Atomic::dec(count_p);
    L20:        set_next(mid, NULL);
    L21:        mid = next;
    L22:      } else {
    L23:        set_next(mid, next);  // unmark next field
    L24:        cur_mid_in_use = mid;
    L25:        mid = next;
    L26:      }
    L27:      if (mid == NULL) {
    L28:        break;  // Reached end of the list so nothing more to deflate.
    L29:      }
    L30:      next = mark_next_loop(mid);
    L31:    }
    L32:    return deflated_count;
    L33:  }

The above is not an exact copy of the code block from deflate_monitor_list(), 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 simpler mark-mid-as-we-go protocol, there are not too many details:

    • 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'.

Housekeeping Parts of the Algorithm

...