Thu, 05 Jun 2008 15:57:56 -0700
6711316: Open source the Garbage-First garbage collector
Summary: First mercurial integration of the code for the Garbage-First garbage collector.
Reviewed-by: apetrusenko, iveresov, jmasa, sgoldman, tonyp, ysr
ysr@777 | 1 | /* |
ysr@777 | 2 | * Copyright 2001-2007 Sun Microsystems, Inc. All Rights Reserved. |
ysr@777 | 3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
ysr@777 | 4 | * |
ysr@777 | 5 | * This code is free software; you can redistribute it and/or modify it |
ysr@777 | 6 | * under the terms of the GNU General Public License version 2 only, as |
ysr@777 | 7 | * published by the Free Software Foundation. |
ysr@777 | 8 | * |
ysr@777 | 9 | * This code is distributed in the hope that it will be useful, but WITHOUT |
ysr@777 | 10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
ysr@777 | 11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
ysr@777 | 12 | * version 2 for more details (a copy is included in the LICENSE file that |
ysr@777 | 13 | * accompanied this code). |
ysr@777 | 14 | * |
ysr@777 | 15 | * You should have received a copy of the GNU General Public License version |
ysr@777 | 16 | * 2 along with this work; if not, write to the Free Software Foundation, |
ysr@777 | 17 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
ysr@777 | 18 | * |
ysr@777 | 19 | * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, |
ysr@777 | 20 | * CA 95054 USA or visit www.sun.com if you need additional information or |
ysr@777 | 21 | * have any questions. |
ysr@777 | 22 | * |
ysr@777 | 23 | */ |
ysr@777 | 24 | |
ysr@777 | 25 | # include "incls/_precompiled.incl" |
ysr@777 | 26 | # include "incls/_ptrQueue.cpp.incl" |
ysr@777 | 27 | |
ysr@777 | 28 | PtrQueue::PtrQueue(PtrQueueSet* qset_, bool perm) : |
ysr@777 | 29 | _qset(qset_), _buf(NULL), _index(0), _active(false), |
ysr@777 | 30 | _perm(perm), _lock(NULL) |
ysr@777 | 31 | {} |
ysr@777 | 32 | |
ysr@777 | 33 | PtrQueue::~PtrQueue() { |
ysr@777 | 34 | if (!_perm && _buf != NULL) { |
ysr@777 | 35 | if (_index == _sz) { |
ysr@777 | 36 | // No work to do. |
ysr@777 | 37 | qset()->deallocate_buffer(_buf); |
ysr@777 | 38 | } else { |
ysr@777 | 39 | // We must NULL out the unused entries, then enqueue. |
ysr@777 | 40 | for (size_t i = 0; i < _index; i += oopSize) { |
ysr@777 | 41 | _buf[byte_index_to_index((int)i)] = NULL; |
ysr@777 | 42 | } |
ysr@777 | 43 | qset()->enqueue_complete_buffer(_buf); |
ysr@777 | 44 | _buf = NULL; |
ysr@777 | 45 | } |
ysr@777 | 46 | } |
ysr@777 | 47 | } |
ysr@777 | 48 | |
ysr@777 | 49 | |
ysr@777 | 50 | static int byte_index_to_index(int ind) { |
ysr@777 | 51 | assert((ind % oopSize) == 0, "Invariant."); |
ysr@777 | 52 | return ind / oopSize; |
ysr@777 | 53 | } |
ysr@777 | 54 | |
ysr@777 | 55 | static int index_to_byte_index(int byte_ind) { |
ysr@777 | 56 | return byte_ind * oopSize; |
ysr@777 | 57 | } |
ysr@777 | 58 | |
ysr@777 | 59 | void PtrQueue::enqueue_known_active(void* ptr) { |
ysr@777 | 60 | assert(0 <= _index && _index <= _sz, "Invariant."); |
ysr@777 | 61 | assert(_index == 0 || _buf != NULL, "invariant"); |
ysr@777 | 62 | |
ysr@777 | 63 | while (_index == 0) { |
ysr@777 | 64 | handle_zero_index(); |
ysr@777 | 65 | } |
ysr@777 | 66 | assert(_index > 0, "postcondition"); |
ysr@777 | 67 | |
ysr@777 | 68 | _index -= oopSize; |
ysr@777 | 69 | _buf[byte_index_to_index((int)_index)] = ptr; |
ysr@777 | 70 | assert(0 <= _index && _index <= _sz, "Invariant."); |
ysr@777 | 71 | } |
ysr@777 | 72 | |
ysr@777 | 73 | void PtrQueue::locking_enqueue_completed_buffer(void** buf) { |
ysr@777 | 74 | assert(_lock->owned_by_self(), "Required."); |
ysr@777 | 75 | _lock->unlock(); |
ysr@777 | 76 | qset()->enqueue_complete_buffer(buf); |
ysr@777 | 77 | // We must relock only because the caller will unlock, for the normal |
ysr@777 | 78 | // case. |
ysr@777 | 79 | _lock->lock_without_safepoint_check(); |
ysr@777 | 80 | } |
ysr@777 | 81 | |
ysr@777 | 82 | |
ysr@777 | 83 | PtrQueueSet::PtrQueueSet(bool notify_when_complete) : |
ysr@777 | 84 | _max_completed_queue(0), |
ysr@777 | 85 | _cbl_mon(NULL), _fl_lock(NULL), |
ysr@777 | 86 | _notify_when_complete(notify_when_complete), |
ysr@777 | 87 | _sz(0), |
ysr@777 | 88 | _completed_buffers_head(NULL), |
ysr@777 | 89 | _completed_buffers_tail(NULL), |
ysr@777 | 90 | _n_completed_buffers(0), |
ysr@777 | 91 | _process_completed_threshold(0), _process_completed(false), |
ysr@777 | 92 | _buf_free_list(NULL), _buf_free_list_sz(0) |
ysr@777 | 93 | {} |
ysr@777 | 94 | |
ysr@777 | 95 | void** PtrQueueSet::allocate_buffer() { |
ysr@777 | 96 | assert(_sz > 0, "Didn't set a buffer size."); |
ysr@777 | 97 | MutexLockerEx x(_fl_lock, Mutex::_no_safepoint_check_flag); |
ysr@777 | 98 | if (_buf_free_list != NULL) { |
ysr@777 | 99 | void** res = _buf_free_list; |
ysr@777 | 100 | _buf_free_list = (void**)_buf_free_list[0]; |
ysr@777 | 101 | _buf_free_list_sz--; |
ysr@777 | 102 | // Just override the next pointer with NULL, just in case we scan this part |
ysr@777 | 103 | // of the buffer. |
ysr@777 | 104 | res[0] = NULL; |
ysr@777 | 105 | return res; |
ysr@777 | 106 | } else { |
ysr@777 | 107 | return NEW_C_HEAP_ARRAY(void*, _sz); |
ysr@777 | 108 | } |
ysr@777 | 109 | } |
ysr@777 | 110 | |
ysr@777 | 111 | void PtrQueueSet::deallocate_buffer(void** buf) { |
ysr@777 | 112 | assert(_sz > 0, "Didn't set a buffer size."); |
ysr@777 | 113 | MutexLockerEx x(_fl_lock, Mutex::_no_safepoint_check_flag); |
ysr@777 | 114 | buf[0] = (void*)_buf_free_list; |
ysr@777 | 115 | _buf_free_list = buf; |
ysr@777 | 116 | _buf_free_list_sz++; |
ysr@777 | 117 | } |
ysr@777 | 118 | |
ysr@777 | 119 | void PtrQueueSet::reduce_free_list() { |
ysr@777 | 120 | // For now we'll adopt the strategy of deleting half. |
ysr@777 | 121 | MutexLockerEx x(_fl_lock, Mutex::_no_safepoint_check_flag); |
ysr@777 | 122 | size_t n = _buf_free_list_sz / 2; |
ysr@777 | 123 | while (n > 0) { |
ysr@777 | 124 | assert(_buf_free_list != NULL, "_buf_free_list_sz must be wrong."); |
ysr@777 | 125 | void** head = _buf_free_list; |
ysr@777 | 126 | _buf_free_list = (void**)_buf_free_list[0]; |
ysr@777 | 127 | FREE_C_HEAP_ARRAY(void*,head); |
ysr@777 | 128 | n--; |
ysr@777 | 129 | } |
ysr@777 | 130 | } |
ysr@777 | 131 | |
ysr@777 | 132 | void PtrQueueSet::enqueue_complete_buffer(void** buf, size_t index, bool ignore_max_completed) { |
ysr@777 | 133 | // I use explicit locking here because there's a bailout in the middle. |
ysr@777 | 134 | _cbl_mon->lock_without_safepoint_check(); |
ysr@777 | 135 | |
ysr@777 | 136 | Thread* thread = Thread::current(); |
ysr@777 | 137 | assert( ignore_max_completed || |
ysr@777 | 138 | thread->is_Java_thread() || |
ysr@777 | 139 | SafepointSynchronize::is_at_safepoint(), |
ysr@777 | 140 | "invariant" ); |
ysr@777 | 141 | ignore_max_completed = ignore_max_completed || !thread->is_Java_thread(); |
ysr@777 | 142 | |
ysr@777 | 143 | if (!ignore_max_completed && _max_completed_queue > 0 && |
ysr@777 | 144 | _n_completed_buffers >= (size_t) _max_completed_queue) { |
ysr@777 | 145 | _cbl_mon->unlock(); |
ysr@777 | 146 | bool b = mut_process_buffer(buf); |
ysr@777 | 147 | if (b) { |
ysr@777 | 148 | deallocate_buffer(buf); |
ysr@777 | 149 | return; |
ysr@777 | 150 | } |
ysr@777 | 151 | |
ysr@777 | 152 | // Otherwise, go ahead and enqueue the buffer. Must reaquire the lock. |
ysr@777 | 153 | _cbl_mon->lock_without_safepoint_check(); |
ysr@777 | 154 | } |
ysr@777 | 155 | |
ysr@777 | 156 | // Here we still hold the _cbl_mon. |
ysr@777 | 157 | CompletedBufferNode* cbn = new CompletedBufferNode; |
ysr@777 | 158 | cbn->buf = buf; |
ysr@777 | 159 | cbn->next = NULL; |
ysr@777 | 160 | cbn->index = index; |
ysr@777 | 161 | if (_completed_buffers_tail == NULL) { |
ysr@777 | 162 | assert(_completed_buffers_head == NULL, "Well-formedness"); |
ysr@777 | 163 | _completed_buffers_head = cbn; |
ysr@777 | 164 | _completed_buffers_tail = cbn; |
ysr@777 | 165 | } else { |
ysr@777 | 166 | _completed_buffers_tail->next = cbn; |
ysr@777 | 167 | _completed_buffers_tail = cbn; |
ysr@777 | 168 | } |
ysr@777 | 169 | _n_completed_buffers++; |
ysr@777 | 170 | |
ysr@777 | 171 | if (!_process_completed && |
ysr@777 | 172 | _n_completed_buffers == _process_completed_threshold) { |
ysr@777 | 173 | _process_completed = true; |
ysr@777 | 174 | if (_notify_when_complete) |
ysr@777 | 175 | _cbl_mon->notify_all(); |
ysr@777 | 176 | } |
ysr@777 | 177 | debug_only(assert_completed_buffer_list_len_correct_locked()); |
ysr@777 | 178 | _cbl_mon->unlock(); |
ysr@777 | 179 | } |
ysr@777 | 180 | |
ysr@777 | 181 | int PtrQueueSet::completed_buffers_list_length() { |
ysr@777 | 182 | int n = 0; |
ysr@777 | 183 | CompletedBufferNode* cbn = _completed_buffers_head; |
ysr@777 | 184 | while (cbn != NULL) { |
ysr@777 | 185 | n++; |
ysr@777 | 186 | cbn = cbn->next; |
ysr@777 | 187 | } |
ysr@777 | 188 | return n; |
ysr@777 | 189 | } |
ysr@777 | 190 | |
ysr@777 | 191 | void PtrQueueSet::assert_completed_buffer_list_len_correct() { |
ysr@777 | 192 | MutexLockerEx x(_cbl_mon, Mutex::_no_safepoint_check_flag); |
ysr@777 | 193 | assert_completed_buffer_list_len_correct_locked(); |
ysr@777 | 194 | } |
ysr@777 | 195 | |
ysr@777 | 196 | void PtrQueueSet::assert_completed_buffer_list_len_correct_locked() { |
ysr@777 | 197 | guarantee((size_t)completed_buffers_list_length() == _n_completed_buffers, |
ysr@777 | 198 | "Completed buffer length is wrong."); |
ysr@777 | 199 | } |
ysr@777 | 200 | |
ysr@777 | 201 | void PtrQueueSet::set_buffer_size(size_t sz) { |
ysr@777 | 202 | assert(_sz == 0 && sz > 0, "Should be called only once."); |
ysr@777 | 203 | _sz = sz * oopSize; |
ysr@777 | 204 | } |
ysr@777 | 205 | |
ysr@777 | 206 | void PtrQueueSet::set_process_completed_threshold(size_t sz) { |
ysr@777 | 207 | _process_completed_threshold = sz; |
ysr@777 | 208 | } |