Mon, 22 Sep 2008 09:56:49 -0400
6742641: G1: NullPointerException during GCOld
Summary: An update buffer is not processed correctly, which causes roots into the collection set not to be scanned and, hence, for the heap to be corrupted. The cause is that an object is accessed after it has been explicitly deleted, which causes a race.
Reviewed-by: jcoomes, ysr
1 /*
2 * Copyright 2001-2007 Sun Microsystems, Inc. All Rights Reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
20 * CA 95054 USA or visit www.sun.com if you need additional information or
21 * have any questions.
22 *
23 */
25 # include "incls/_precompiled.incl"
26 # include "incls/_dirtyCardQueue.cpp.incl"
28 bool DirtyCardQueue::apply_closure(CardTableEntryClosure* cl,
29 bool consume,
30 size_t worker_i) {
31 bool res = true;
32 if (_buf != NULL) {
33 res = apply_closure_to_buffer(cl, _buf, _index, _sz,
34 consume,
35 (int) worker_i);
36 if (res && consume) _index = _sz;
37 }
38 return res;
39 }
41 bool DirtyCardQueue::apply_closure_to_buffer(CardTableEntryClosure* cl,
42 void** buf,
43 size_t index, size_t sz,
44 bool consume,
45 int worker_i) {
46 if (cl == NULL) return true;
47 for (size_t i = index; i < sz; i += oopSize) {
48 int ind = byte_index_to_index((int)i);
49 jbyte* card_ptr = (jbyte*)buf[ind];
50 if (card_ptr != NULL) {
51 // Set the entry to null, so we don't do it again (via the test
52 // above) if we reconsider this buffer.
53 if (consume) buf[ind] = NULL;
54 if (!cl->do_card_ptr(card_ptr, worker_i)) return false;
55 }
56 }
57 return true;
58 }
60 #ifdef _MSC_VER // the use of 'this' below gets a warning, make it go away
61 #pragma warning( disable:4355 ) // 'this' : used in base member initializer list
62 #endif // _MSC_VER
64 DirtyCardQueueSet::DirtyCardQueueSet() :
65 PtrQueueSet(true /*notify_when_complete*/),
66 _closure(NULL),
67 _shared_dirty_card_queue(this, true /*perm*/),
68 _free_ids(NULL),
69 _processed_buffers_mut(0), _processed_buffers_rs_thread(0)
70 {
71 _all_active = true;
72 }
74 size_t DirtyCardQueueSet::num_par_ids() {
75 return MAX2(ParallelGCThreads, (size_t)2);
76 }
79 void DirtyCardQueueSet::initialize(Monitor* cbl_mon, Mutex* fl_lock,
80 int max_completed_queue,
81 Mutex* lock) {
82 PtrQueueSet::initialize(cbl_mon, fl_lock, max_completed_queue);
83 set_buffer_size(DCQBarrierQueueBufferSize);
84 set_process_completed_threshold(DCQBarrierProcessCompletedThreshold);
86 _shared_dirty_card_queue.set_lock(lock);
87 _free_ids = new FreeIdSet((int) num_par_ids(), _cbl_mon);
88 bool b = _free_ids->claim_perm_id(0);
89 guarantee(b, "Must reserve id zero for concurrent refinement thread.");
90 }
92 void DirtyCardQueueSet::handle_zero_index_for_thread(JavaThread* t) {
93 t->dirty_card_queue().handle_zero_index();
94 }
96 void DirtyCardQueueSet::set_closure(CardTableEntryClosure* closure) {
97 _closure = closure;
98 }
100 void DirtyCardQueueSet::iterate_closure_all_threads(bool consume,
101 size_t worker_i) {
102 assert(SafepointSynchronize::is_at_safepoint(), "Must be at safepoint.");
103 for(JavaThread* t = Threads::first(); t; t = t->next()) {
104 bool b = t->dirty_card_queue().apply_closure(_closure, consume);
105 guarantee(b, "Should not be interrupted.");
106 }
107 bool b = shared_dirty_card_queue()->apply_closure(_closure,
108 consume,
109 worker_i);
110 guarantee(b, "Should not be interrupted.");
111 }
113 bool DirtyCardQueueSet::mut_process_buffer(void** buf) {
115 // Used to determine if we had already claimed a par_id
116 // before entering this method.
117 bool already_claimed = false;
119 // We grab the current JavaThread.
120 JavaThread* thread = JavaThread::current();
122 // We get the the number of any par_id that this thread
123 // might have already claimed.
124 int worker_i = thread->get_claimed_par_id();
126 // If worker_i is not -1 then the thread has already claimed
127 // a par_id. We make note of it using the already_claimed value
128 if (worker_i != -1) {
129 already_claimed = true;
130 } else {
132 // Otherwise we need to claim a par id
133 worker_i = _free_ids->claim_par_id();
135 // And store the par_id value in the thread
136 thread->set_claimed_par_id(worker_i);
137 }
139 bool b = false;
140 if (worker_i != -1) {
141 b = DirtyCardQueue::apply_closure_to_buffer(_closure, buf, 0,
142 _sz, true, worker_i);
143 if (b) Atomic::inc(&_processed_buffers_mut);
145 // If we had not claimed an id before entering the method
146 // then we must release the id.
147 if (!already_claimed) {
149 // we release the id
150 _free_ids->release_par_id(worker_i);
152 // and set the claimed_id in the thread to -1
153 thread->set_claimed_par_id(-1);
154 }
155 }
156 return b;
157 }
159 DirtyCardQueueSet::CompletedBufferNode*
160 DirtyCardQueueSet::get_completed_buffer_lock(int stop_at) {
161 CompletedBufferNode* nd = NULL;
162 MutexLockerEx x(_cbl_mon, Mutex::_no_safepoint_check_flag);
164 if ((int)_n_completed_buffers <= stop_at) {
165 _process_completed = false;
166 return NULL;
167 }
169 if (_completed_buffers_head != NULL) {
170 nd = _completed_buffers_head;
171 _completed_buffers_head = nd->next;
172 if (_completed_buffers_head == NULL)
173 _completed_buffers_tail = NULL;
174 _n_completed_buffers--;
175 }
176 debug_only(assert_completed_buffer_list_len_correct_locked());
177 return nd;
178 }
180 // We only do this in contexts where there is no concurrent enqueueing.
181 DirtyCardQueueSet::CompletedBufferNode*
182 DirtyCardQueueSet::get_completed_buffer_CAS() {
183 CompletedBufferNode* nd = _completed_buffers_head;
185 while (nd != NULL) {
186 CompletedBufferNode* next = nd->next;
187 CompletedBufferNode* result =
188 (CompletedBufferNode*)Atomic::cmpxchg_ptr(next,
189 &_completed_buffers_head,
190 nd);
191 if (result == nd) {
192 return result;
193 } else {
194 nd = _completed_buffers_head;
195 }
196 }
197 assert(_completed_buffers_head == NULL, "Loop post");
198 _completed_buffers_tail = NULL;
199 return NULL;
200 }
202 bool DirtyCardQueueSet::
203 apply_closure_to_completed_buffer_helper(int worker_i,
204 CompletedBufferNode* nd) {
205 if (nd != NULL) {
206 bool b =
207 DirtyCardQueue::apply_closure_to_buffer(_closure, nd->buf,
208 nd->index, _sz,
209 true, worker_i);
210 void** buf = nd->buf;
211 size_t index = nd->index;
212 delete nd;
213 if (b) {
214 deallocate_buffer(buf);
215 return true; // In normal case, go on to next buffer.
216 } else {
217 enqueue_complete_buffer(buf, index, true);
218 return false;
219 }
220 } else {
221 return false;
222 }
223 }
225 bool DirtyCardQueueSet::apply_closure_to_completed_buffer(int worker_i,
226 int stop_at,
227 bool with_CAS)
228 {
229 CompletedBufferNode* nd = NULL;
230 if (with_CAS) {
231 guarantee(stop_at == 0, "Precondition");
232 nd = get_completed_buffer_CAS();
233 } else {
234 nd = get_completed_buffer_lock(stop_at);
235 }
236 bool res = apply_closure_to_completed_buffer_helper(worker_i, nd);
237 if (res) _processed_buffers_rs_thread++;
238 return res;
239 }
241 void DirtyCardQueueSet::apply_closure_to_all_completed_buffers() {
242 CompletedBufferNode* nd = _completed_buffers_head;
243 while (nd != NULL) {
244 bool b =
245 DirtyCardQueue::apply_closure_to_buffer(_closure, nd->buf, 0, _sz,
246 false);
247 guarantee(b, "Should not stop early.");
248 nd = nd->next;
249 }
250 }
252 void DirtyCardQueueSet::abandon_logs() {
253 assert(SafepointSynchronize::is_at_safepoint(), "Must be at safepoint.");
254 CompletedBufferNode* buffers_to_delete = NULL;
255 {
256 MutexLockerEx x(_cbl_mon, Mutex::_no_safepoint_check_flag);
257 while (_completed_buffers_head != NULL) {
258 CompletedBufferNode* nd = _completed_buffers_head;
259 _completed_buffers_head = nd->next;
260 nd->next = buffers_to_delete;
261 buffers_to_delete = nd;
262 }
263 _n_completed_buffers = 0;
264 _completed_buffers_tail = NULL;
265 debug_only(assert_completed_buffer_list_len_correct_locked());
266 }
267 while (buffers_to_delete != NULL) {
268 CompletedBufferNode* nd = buffers_to_delete;
269 buffers_to_delete = nd->next;
270 deallocate_buffer(nd->buf);
271 delete nd;
272 }
273 // Since abandon is done only at safepoints, we can safely manipulate
274 // these queues.
275 for (JavaThread* t = Threads::first(); t; t = t->next()) {
276 t->dirty_card_queue().reset();
277 }
278 shared_dirty_card_queue()->reset();
279 }
282 void DirtyCardQueueSet::concatenate_logs() {
283 // Iterate over all the threads, if we find a partial log add it to
284 // the global list of logs. Temporarily turn off the limit on the number
285 // of outstanding buffers.
286 int save_max_completed_queue = _max_completed_queue;
287 _max_completed_queue = max_jint;
288 assert(SafepointSynchronize::is_at_safepoint(), "Must be at safepoint.");
289 for (JavaThread* t = Threads::first(); t; t = t->next()) {
290 DirtyCardQueue& dcq = t->dirty_card_queue();
291 if (dcq.size() != 0) {
292 void **buf = t->dirty_card_queue().get_buf();
293 // We must NULL out the unused entries, then enqueue.
294 for (size_t i = 0; i < t->dirty_card_queue().get_index(); i += oopSize) {
295 buf[PtrQueue::byte_index_to_index((int)i)] = NULL;
296 }
297 enqueue_complete_buffer(dcq.get_buf(), dcq.get_index());
298 dcq.reinitialize();
299 }
300 }
301 if (_shared_dirty_card_queue.size() != 0) {
302 enqueue_complete_buffer(_shared_dirty_card_queue.get_buf(),
303 _shared_dirty_card_queue.get_index());
304 _shared_dirty_card_queue.reinitialize();
305 }
306 // Restore the completed buffer queue limit.
307 _max_completed_queue = save_max_completed_queue;
308 }