Mercurial > hg > truffle
annotate src/share/vm/gc_implementation/g1/dirtyCardQueue.cpp @ 1705:2d160770d2e5
6814437: G1: remove the _new_refs array
Summary: The per-worker _new_refs array is used to hold references that point into the collection set. It is populated during RSet updating and subsequently processed. In the event of an evacuation failure it processed again to recreate the RSets of regions in the collection set. Remove the per-worker _new_refs array by processing the references directly. Use a DirtyCardQueue to hold the cards containing the references so that the RSets of regions in the collection set can be recreated when handling an evacuation failure.
Reviewed-by: iveresov, jmasa, tonyp
author | johnc |
---|---|
date | Mon, 02 Aug 2010 12:51:43 -0700 |
parents | c18cbe5936b8 |
children | f95d63e2154a |
rev | line source |
---|---|
342 | 1 /* |
1705 | 2 * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved. |
342 | 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 * | |
1552
c18cbe5936b8
6941466: Oracle rebranding changes for Hotspot repositories
trims
parents:
1111
diff
changeset
|
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
c18cbe5936b8
6941466: Oracle rebranding changes for Hotspot repositories
trims
parents:
1111
diff
changeset
|
20 * or visit www.oracle.com if you need additional information or have any |
c18cbe5936b8
6941466: Oracle rebranding changes for Hotspot repositories
trims
parents:
1111
diff
changeset
|
21 * questions. |
342 | 22 * |
23 */ | |
24 | |
25 # include "incls/_precompiled.incl" | |
26 # include "incls/_dirtyCardQueue.cpp.incl" | |
27 | |
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 } | |
40 | |
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 } | |
59 | |
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 | |
63 | |
1111 | 64 DirtyCardQueueSet::DirtyCardQueueSet(bool notify_when_complete) : |
65 PtrQueueSet(notify_when_complete), | |
342 | 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 } | |
73 | |
795
215f81b4d9b3
6841831: G1: assert(contains_reference(from),"We just added it!") fires
iveresov
parents:
794
diff
changeset
|
74 // Determines how many mutator threads can process the buffers in parallel. |
342 | 75 size_t DirtyCardQueueSet::num_par_ids() { |
795
215f81b4d9b3
6841831: G1: assert(contains_reference(from),"We just added it!") fires
iveresov
parents:
794
diff
changeset
|
76 return os::processor_count(); |
342 | 77 } |
78 | |
79 void DirtyCardQueueSet::initialize(Monitor* cbl_mon, Mutex* fl_lock, | |
1111 | 80 int process_completed_threshold, |
342 | 81 int max_completed_queue, |
616
4f360ec815ba
6720309: G1: don't synchronously update RSet during evacuation pauses
iveresov
parents:
470
diff
changeset
|
82 Mutex* lock, PtrQueueSet* fl_owner) { |
1111 | 83 PtrQueueSet::initialize(cbl_mon, fl_lock, process_completed_threshold, |
84 max_completed_queue, fl_owner); | |
883
27f6a9b9c311
6864886: G1: rename -XX parameters related to update buffers
tonyp
parents:
795
diff
changeset
|
85 set_buffer_size(G1UpdateBufferSize); |
342 | 86 _shared_dirty_card_queue.set_lock(lock); |
87 _free_ids = new FreeIdSet((int) num_par_ids(), _cbl_mon); | |
88 } | |
89 | |
90 void DirtyCardQueueSet::handle_zero_index_for_thread(JavaThread* t) { | |
91 t->dirty_card_queue().handle_zero_index(); | |
92 } | |
93 | |
94 void DirtyCardQueueSet::set_closure(CardTableEntryClosure* closure) { | |
95 _closure = closure; | |
96 } | |
97 | |
98 void DirtyCardQueueSet::iterate_closure_all_threads(bool consume, | |
99 size_t worker_i) { | |
100 assert(SafepointSynchronize::is_at_safepoint(), "Must be at safepoint."); | |
101 for(JavaThread* t = Threads::first(); t; t = t->next()) { | |
102 bool b = t->dirty_card_queue().apply_closure(_closure, consume); | |
103 guarantee(b, "Should not be interrupted."); | |
104 } | |
105 bool b = shared_dirty_card_queue()->apply_closure(_closure, | |
106 consume, | |
107 worker_i); | |
108 guarantee(b, "Should not be interrupted."); | |
109 } | |
110 | |
111 bool DirtyCardQueueSet::mut_process_buffer(void** buf) { | |
112 | |
113 // Used to determine if we had already claimed a par_id | |
114 // before entering this method. | |
115 bool already_claimed = false; | |
116 | |
117 // We grab the current JavaThread. | |
118 JavaThread* thread = JavaThread::current(); | |
119 | |
120 // We get the the number of any par_id that this thread | |
121 // might have already claimed. | |
122 int worker_i = thread->get_claimed_par_id(); | |
123 | |
124 // If worker_i is not -1 then the thread has already claimed | |
125 // a par_id. We make note of it using the already_claimed value | |
126 if (worker_i != -1) { | |
127 already_claimed = true; | |
128 } else { | |
129 | |
130 // Otherwise we need to claim a par id | |
131 worker_i = _free_ids->claim_par_id(); | |
132 | |
133 // And store the par_id value in the thread | |
134 thread->set_claimed_par_id(worker_i); | |
135 } | |
136 | |
137 bool b = false; | |
138 if (worker_i != -1) { | |
139 b = DirtyCardQueue::apply_closure_to_buffer(_closure, buf, 0, | |
140 _sz, true, worker_i); | |
141 if (b) Atomic::inc(&_processed_buffers_mut); | |
142 | |
143 // If we had not claimed an id before entering the method | |
144 // then we must release the id. | |
145 if (!already_claimed) { | |
146 | |
147 // we release the id | |
148 _free_ids->release_par_id(worker_i); | |
149 | |
150 // and set the claimed_id in the thread to -1 | |
151 thread->set_claimed_par_id(-1); | |
152 } | |
153 } | |
154 return b; | |
155 } | |
156 | |
1111 | 157 |
158 BufferNode* | |
1090
fa357420e7d2
6899058: G1: Internal error in ptrQueue.cpp:201 in nightly tests
johnc
parents:
885
diff
changeset
|
159 DirtyCardQueueSet::get_completed_buffer(int stop_at) { |
1111 | 160 BufferNode* nd = NULL; |
342 | 161 MutexLockerEx x(_cbl_mon, Mutex::_no_safepoint_check_flag); |
162 | |
163 if ((int)_n_completed_buffers <= stop_at) { | |
164 _process_completed = false; | |
165 return NULL; | |
166 } | |
167 | |
168 if (_completed_buffers_head != NULL) { | |
169 nd = _completed_buffers_head; | |
1111 | 170 _completed_buffers_head = nd->next(); |
342 | 171 if (_completed_buffers_head == NULL) |
172 _completed_buffers_tail = NULL; | |
173 _n_completed_buffers--; | |
1111 | 174 assert(_n_completed_buffers >= 0, "Invariant"); |
342 | 175 } |
176 debug_only(assert_completed_buffer_list_len_correct_locked()); | |
177 return nd; | |
178 } | |
179 | |
180 bool DirtyCardQueueSet:: | |
1705 | 181 apply_closure_to_completed_buffer_helper(CardTableEntryClosure* cl, |
182 int worker_i, | |
1111 | 183 BufferNode* nd) { |
342 | 184 if (nd != NULL) { |
1111 | 185 void **buf = BufferNode::make_buffer_from_node(nd); |
186 size_t index = nd->index(); | |
342 | 187 bool b = |
1705 | 188 DirtyCardQueue::apply_closure_to_buffer(cl, buf, |
1111 | 189 index, _sz, |
342 | 190 true, worker_i); |
191 if (b) { | |
192 deallocate_buffer(buf); | |
193 return true; // In normal case, go on to next buffer. | |
194 } else { | |
1111 | 195 enqueue_complete_buffer(buf, index); |
342 | 196 return false; |
197 } | |
198 } else { | |
199 return false; | |
200 } | |
201 } | |
202 | |
1705 | 203 bool DirtyCardQueueSet::apply_closure_to_completed_buffer(CardTableEntryClosure* cl, |
204 int worker_i, | |
205 int stop_at, | |
206 bool during_pause) { | |
207 assert(!during_pause || stop_at == 0, "Should not leave any completed buffers during a pause"); | |
208 BufferNode* nd = get_completed_buffer(stop_at); | |
209 bool res = apply_closure_to_completed_buffer_helper(cl, worker_i, nd); | |
210 if (res) Atomic::inc(&_processed_buffers_rs_thread); | |
211 return res; | |
212 } | |
213 | |
342 | 214 bool DirtyCardQueueSet::apply_closure_to_completed_buffer(int worker_i, |
215 int stop_at, | |
1705 | 216 bool during_pause) { |
217 return apply_closure_to_completed_buffer(_closure, worker_i, | |
218 stop_at, during_pause); | |
342 | 219 } |
220 | |
221 void DirtyCardQueueSet::apply_closure_to_all_completed_buffers() { | |
1111 | 222 BufferNode* nd = _completed_buffers_head; |
342 | 223 while (nd != NULL) { |
224 bool b = | |
1111 | 225 DirtyCardQueue::apply_closure_to_buffer(_closure, |
226 BufferNode::make_buffer_from_node(nd), | |
227 0, _sz, false); | |
342 | 228 guarantee(b, "Should not stop early."); |
1111 | 229 nd = nd->next(); |
342 | 230 } |
231 } | |
232 | |
1705 | 233 // Deallocates any completed log buffers |
234 void DirtyCardQueueSet::clear() { | |
1111 | 235 BufferNode* buffers_to_delete = NULL; |
342 | 236 { |
237 MutexLockerEx x(_cbl_mon, Mutex::_no_safepoint_check_flag); | |
238 while (_completed_buffers_head != NULL) { | |
1111 | 239 BufferNode* nd = _completed_buffers_head; |
240 _completed_buffers_head = nd->next(); | |
241 nd->set_next(buffers_to_delete); | |
342 | 242 buffers_to_delete = nd; |
243 } | |
244 _n_completed_buffers = 0; | |
245 _completed_buffers_tail = NULL; | |
246 debug_only(assert_completed_buffer_list_len_correct_locked()); | |
247 } | |
248 while (buffers_to_delete != NULL) { | |
1111 | 249 BufferNode* nd = buffers_to_delete; |
250 buffers_to_delete = nd->next(); | |
251 deallocate_buffer(BufferNode::make_buffer_from_node(nd)); | |
342 | 252 } |
1705 | 253 |
254 } | |
255 | |
256 void DirtyCardQueueSet::abandon_logs() { | |
257 assert(SafepointSynchronize::is_at_safepoint(), "Must be at safepoint."); | |
258 clear(); | |
342 | 259 // Since abandon is done only at safepoints, we can safely manipulate |
260 // these queues. | |
261 for (JavaThread* t = Threads::first(); t; t = t->next()) { | |
262 t->dirty_card_queue().reset(); | |
263 } | |
264 shared_dirty_card_queue()->reset(); | |
265 } | |
266 | |
267 | |
268 void DirtyCardQueueSet::concatenate_logs() { | |
269 // Iterate over all the threads, if we find a partial log add it to | |
270 // the global list of logs. Temporarily turn off the limit on the number | |
271 // of outstanding buffers. | |
272 int save_max_completed_queue = _max_completed_queue; | |
273 _max_completed_queue = max_jint; | |
274 assert(SafepointSynchronize::is_at_safepoint(), "Must be at safepoint."); | |
275 for (JavaThread* t = Threads::first(); t; t = t->next()) { | |
276 DirtyCardQueue& dcq = t->dirty_card_queue(); | |
277 if (dcq.size() != 0) { | |
278 void **buf = t->dirty_card_queue().get_buf(); | |
279 // We must NULL out the unused entries, then enqueue. | |
280 for (size_t i = 0; i < t->dirty_card_queue().get_index(); i += oopSize) { | |
281 buf[PtrQueue::byte_index_to_index((int)i)] = NULL; | |
282 } | |
283 enqueue_complete_buffer(dcq.get_buf(), dcq.get_index()); | |
284 dcq.reinitialize(); | |
285 } | |
286 } | |
287 if (_shared_dirty_card_queue.size() != 0) { | |
288 enqueue_complete_buffer(_shared_dirty_card_queue.get_buf(), | |
289 _shared_dirty_card_queue.get_index()); | |
290 _shared_dirty_card_queue.reinitialize(); | |
291 } | |
292 // Restore the completed buffer queue limit. | |
293 _max_completed_queue = save_max_completed_queue; | |
294 } |