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