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