131 _bm.at_put_range(heapWordToOffset(mr.start()), |
131 _bm.at_put_range(heapWordToOffset(mr.start()), |
132 heapWordToOffset(mr.end()), false); |
132 heapWordToOffset(mr.end()), false); |
133 } |
133 } |
134 |
134 |
135 G1CMMarkStack::G1CMMarkStack() : |
135 G1CMMarkStack::G1CMMarkStack() : |
136 _reserved_space(), |
136 _max_chunk_capacity(0), |
137 _base(NULL), |
137 _base(NULL), |
138 _capacity(0), |
138 _chunk_capacity(0), |
139 _saved_index((size_t)AllBits), |
139 _out_of_memory(false), |
140 _should_expand(false) { |
140 _should_expand(false) { |
141 set_empty(); |
141 set_empty(); |
142 } |
142 } |
143 |
143 |
144 bool G1CMMarkStack::resize(size_t new_capacity) { |
144 bool G1CMMarkStack::resize(size_t new_capacity) { |
145 assert(is_empty(), "Only resize when stack is empty."); |
145 assert(is_empty(), "Only resize when stack is empty."); |
146 assert(new_capacity <= MarkStackSizeMax, |
146 assert(new_capacity <= _max_chunk_capacity, |
147 "Trying to resize stack to " SIZE_FORMAT " elements when the maximum is " SIZE_FORMAT, new_capacity, MarkStackSizeMax); |
147 "Trying to resize stack to " SIZE_FORMAT " chunks when the maximum is " SIZE_FORMAT, new_capacity, _max_chunk_capacity); |
148 |
148 |
149 size_t reservation_size = ReservedSpace::allocation_align_size_up(new_capacity * sizeof(oop)); |
149 OopChunk* new_base = MmapArrayAllocator<OopChunk, mtGC>::allocate_or_null(new_capacity); |
150 |
150 |
151 ReservedSpace rs(reservation_size); |
151 if (new_base == NULL) { |
152 if (!rs.is_reserved()) { |
152 log_warning(gc)("Failed to reserve memory for new overflow mark stack with " SIZE_FORMAT " chunks and size " SIZE_FORMAT "B.", new_capacity, new_capacity * sizeof(OopChunk)); |
153 log_warning(gc)("Failed to reserve memory for new overflow mark stack with " SIZE_FORMAT " elements and size " SIZE_FORMAT "B.", new_capacity, reservation_size); |
|
154 return false; |
153 return false; |
155 } |
154 } |
156 |
|
157 VirtualSpace vs; |
|
158 |
|
159 if (!vs.initialize(rs, rs.size())) { |
|
160 rs.release(); |
|
161 log_warning(gc)("Failed to commit memory for new overflow mark stack of size " SIZE_FORMAT "B.", rs.size()); |
|
162 return false; |
|
163 } |
|
164 |
|
165 assert(vs.committed_size() == rs.size(), "Failed to commit all of the mark stack."); |
|
166 |
|
167 // Release old mapping. |
155 // Release old mapping. |
168 _reserved_space.release(); |
156 if (_base != NULL) { |
169 |
157 MmapArrayAllocator<OopChunk, mtGC>::free(_base, _chunk_capacity); |
170 // Save new mapping for future unmapping. |
158 } |
171 _reserved_space = rs; |
159 |
172 |
160 _base = new_base; |
173 MemTracker::record_virtual_memory_type((address)_reserved_space.base(), mtGC); |
161 _chunk_capacity = new_capacity; |
174 |
|
175 _base = (oop*) vs.low(); |
|
176 _capacity = new_capacity; |
|
177 set_empty(); |
162 set_empty(); |
178 _should_expand = false; |
163 _should_expand = false; |
179 |
164 |
180 return true; |
165 return true; |
181 } |
166 } |
182 |
167 |
183 bool G1CMMarkStack::allocate(size_t capacity) { |
168 size_t G1CMMarkStack::capacity_alignment() { |
184 return resize(capacity); |
169 return (size_t)lcm(os::vm_allocation_granularity(), sizeof(OopChunk)) / sizeof(void*); |
|
170 } |
|
171 |
|
172 bool G1CMMarkStack::initialize(size_t initial_capacity, size_t max_capacity) { |
|
173 guarantee(_max_chunk_capacity == 0, "G1CMMarkStack already initialized."); |
|
174 |
|
175 size_t const OopChunkSizeInVoidStar = sizeof(OopChunk) / sizeof(void*); |
|
176 |
|
177 _max_chunk_capacity = (size_t)align_size_up(max_capacity, capacity_alignment()) / OopChunkSizeInVoidStar; |
|
178 size_t initial_chunk_capacity = (size_t)align_size_up(initial_capacity, capacity_alignment()) / OopChunkSizeInVoidStar; |
|
179 |
|
180 guarantee(initial_chunk_capacity <= _max_chunk_capacity, |
|
181 "Maximum chunk capacity " SIZE_FORMAT " smaller than initial capacity " SIZE_FORMAT, |
|
182 _max_chunk_capacity, |
|
183 initial_chunk_capacity); |
|
184 |
|
185 log_debug(gc)("Initialize mark stack with " SIZE_FORMAT " chunks, maximum " SIZE_FORMAT, |
|
186 initial_chunk_capacity, _max_chunk_capacity); |
|
187 |
|
188 return resize(initial_chunk_capacity); |
185 } |
189 } |
186 |
190 |
187 void G1CMMarkStack::expand() { |
191 void G1CMMarkStack::expand() { |
188 // Clear expansion flag |
192 // Clear expansion flag |
189 _should_expand = false; |
193 _should_expand = false; |
190 |
194 |
191 if (_capacity == MarkStackSizeMax) { |
195 if (_chunk_capacity == _max_chunk_capacity) { |
192 log_debug(gc)("Can not expand overflow mark stack further, already at maximum capacity of " SIZE_FORMAT " elements.", _capacity); |
196 log_debug(gc)("Can not expand overflow mark stack further, already at maximum capacity of " SIZE_FORMAT " chunks.", _chunk_capacity); |
193 return; |
197 return; |
194 } |
198 } |
195 size_t old_capacity = _capacity; |
199 size_t old_capacity = _chunk_capacity; |
196 // Double capacity if possible |
200 // Double capacity if possible |
197 size_t new_capacity = MIN2(old_capacity * 2, MarkStackSizeMax); |
201 size_t new_capacity = MIN2(old_capacity * 2, _max_chunk_capacity); |
198 |
202 |
199 if (resize(new_capacity)) { |
203 if (resize(new_capacity)) { |
200 log_debug(gc)("Expanded marking stack capacity from " SIZE_FORMAT " to " SIZE_FORMAT " elements", |
204 log_debug(gc)("Expanded mark stack capacity from " SIZE_FORMAT " to " SIZE_FORMAT " chunks", |
201 old_capacity, new_capacity); |
205 old_capacity, new_capacity); |
202 } else { |
206 } else { |
203 log_warning(gc)("Failed to expand marking stack capacity from " SIZE_FORMAT " to " SIZE_FORMAT " elements", |
207 log_warning(gc)("Failed to expand mark stack capacity from " SIZE_FORMAT " to " SIZE_FORMAT " chunks", |
204 old_capacity, new_capacity); |
208 old_capacity, new_capacity); |
205 } |
209 } |
206 } |
210 } |
207 |
211 |
208 G1CMMarkStack::~G1CMMarkStack() { |
212 G1CMMarkStack::~G1CMMarkStack() { |
209 if (_base != NULL) { |
213 if (_base != NULL) { |
210 _base = NULL; |
214 MmapArrayAllocator<OopChunk, mtGC>::free(_base, _chunk_capacity); |
211 _reserved_space.release(); |
215 } |
212 } |
216 } |
213 } |
217 |
214 |
218 void G1CMMarkStack::add_chunk_to_list(OopChunk* volatile* list, OopChunk* elem) { |
215 void G1CMMarkStack::par_push_arr(oop* buffer, size_t n) { |
219 elem->next = *list; |
216 MutexLockerEx x(ParGCRareEvent_lock, Mutex::_no_safepoint_check_flag); |
220 *list = elem; |
217 size_t start = _index; |
221 } |
218 size_t next_index = start + n; |
222 |
219 if (next_index > _capacity) { |
223 void G1CMMarkStack::add_chunk_to_chunk_list(OopChunk* elem) { |
220 _overflow = true; |
224 MutexLockerEx x(MarkStackChunkList_lock, Mutex::_no_safepoint_check_flag); |
221 return; |
225 add_chunk_to_list(&_chunk_list, elem); |
222 } |
226 _chunks_in_chunk_list++; |
223 // Otherwise. |
227 } |
224 _index = next_index; |
228 |
225 for (size_t i = 0; i < n; i++) { |
229 void G1CMMarkStack::add_chunk_to_free_list(OopChunk* elem) { |
226 size_t ind = start + i; |
230 MutexLockerEx x(MarkStackFreeList_lock, Mutex::_no_safepoint_check_flag); |
227 assert(ind < _capacity, "By overflow test above."); |
231 add_chunk_to_list(&_free_list, elem); |
228 _base[ind] = buffer[i]; |
232 } |
229 } |
233 |
230 } |
234 G1CMMarkStack::OopChunk* G1CMMarkStack::remove_chunk_from_list(OopChunk* volatile* list) { |
231 |
235 OopChunk* result = *list; |
232 bool G1CMMarkStack::par_pop_arr(oop* buffer, size_t max, size_t* n) { |
236 if (result != NULL) { |
233 MutexLockerEx x(ParGCRareEvent_lock, Mutex::_no_safepoint_check_flag); |
237 *list = (*list)->next; |
234 size_t index = _index; |
238 } |
235 if (index == 0) { |
239 return result; |
236 *n = 0; |
240 } |
|
241 |
|
242 G1CMMarkStack::OopChunk* G1CMMarkStack::remove_chunk_from_chunk_list() { |
|
243 MutexLockerEx x(MarkStackChunkList_lock, Mutex::_no_safepoint_check_flag); |
|
244 OopChunk* result = remove_chunk_from_list(&_chunk_list); |
|
245 if (result != NULL) { |
|
246 _chunks_in_chunk_list--; |
|
247 } |
|
248 return result; |
|
249 } |
|
250 |
|
251 G1CMMarkStack::OopChunk* G1CMMarkStack::remove_chunk_from_free_list() { |
|
252 MutexLockerEx x(MarkStackFreeList_lock, Mutex::_no_safepoint_check_flag); |
|
253 return remove_chunk_from_list(&_free_list); |
|
254 } |
|
255 |
|
256 G1CMMarkStack::OopChunk* G1CMMarkStack::allocate_new_chunk() { |
|
257 // This dirty read of _hwm is okay because we only ever increase the _hwm in parallel code. |
|
258 // Further this limits _hwm to a value of _chunk_capacity + #threads, avoiding |
|
259 // wraparound of _hwm. |
|
260 if (_hwm >= _chunk_capacity) { |
|
261 return NULL; |
|
262 } |
|
263 |
|
264 size_t cur_idx = Atomic::add(1, &_hwm) - 1; |
|
265 if (cur_idx >= _chunk_capacity) { |
|
266 return NULL; |
|
267 } |
|
268 |
|
269 OopChunk* result = ::new (&_base[cur_idx]) OopChunk; |
|
270 result->next = NULL; |
|
271 return result; |
|
272 } |
|
273 |
|
274 bool G1CMMarkStack::par_push_chunk(oop* ptr_arr) { |
|
275 // Get a new chunk. |
|
276 OopChunk* new_chunk = remove_chunk_from_free_list(); |
|
277 |
|
278 if (new_chunk == NULL) { |
|
279 // Did not get a chunk from the free list. Allocate from backing memory. |
|
280 new_chunk = allocate_new_chunk(); |
|
281 } |
|
282 |
|
283 if (new_chunk == NULL) { |
|
284 _out_of_memory = true; |
237 return false; |
285 return false; |
238 } else { |
286 } |
239 size_t k = MIN2(max, index); |
287 |
240 size_t new_ind = index - k; |
288 Copy::conjoint_oops_atomic(ptr_arr, new_chunk->data, OopsPerChunk); |
241 for (size_t j = 0; j < k; j++) { |
289 |
242 buffer[j] = _base[new_ind + j]; |
290 add_chunk_to_chunk_list(new_chunk); |
243 } |
291 |
244 _index = new_ind; |
292 return true; |
245 *n = k; |
293 } |
246 return true; |
294 |
247 } |
295 bool G1CMMarkStack::par_pop_chunk(oop* ptr_arr) { |
248 } |
296 OopChunk* cur = remove_chunk_from_chunk_list(); |
249 |
297 |
250 void G1CMMarkStack::note_start_of_gc() { |
298 if (cur == NULL) { |
251 assert(_saved_index == (size_t)AllBits, "note_start_of_gc()/end_of_gc() calls bracketed incorrectly"); |
299 return false; |
252 _saved_index = _index; |
300 } |
253 } |
301 |
254 |
302 Copy::conjoint_oops_atomic(cur->data, ptr_arr, OopsPerChunk); |
255 void G1CMMarkStack::note_end_of_gc() { |
303 |
256 guarantee(!stack_modified(), "Saved index " SIZE_FORMAT " must be the same as " SIZE_FORMAT, _saved_index, _index); |
304 add_chunk_to_free_list(cur); |
257 |
305 return true; |
258 _saved_index = (size_t)AllBits; |
306 } |
|
307 |
|
308 void G1CMMarkStack::set_empty() { |
|
309 _chunks_in_chunk_list = 0; |
|
310 _hwm = 0; |
|
311 clear_out_of_memory(); |
|
312 _chunk_list = NULL; |
|
313 _free_list = NULL; |
259 } |
314 } |
260 |
315 |
261 G1CMRootRegions::G1CMRootRegions() : |
316 G1CMRootRegions::G1CMRootRegions() : |
262 _cm(NULL), _scan_in_progress(false), |
317 _cm(NULL), _scan_in_progress(false), |
263 _should_abort(false), _claimed_survivor_index(0) { } |
318 _should_abort(false), _claimed_survivor_index(0) { } |
2341 _refs_reached_limit = _real_refs_reached_limit - |
2395 _refs_reached_limit = _real_refs_reached_limit - |
2342 3 * refs_reached_period / 4; |
2396 3 * refs_reached_period / 4; |
2343 } |
2397 } |
2344 |
2398 |
2345 void G1CMTask::move_entries_to_global_stack() { |
2399 void G1CMTask::move_entries_to_global_stack() { |
2346 // local array where we'll store the entries that will be popped |
2400 // Local array where we'll store the entries that will be popped |
2347 // from the local queue |
2401 // from the local queue. |
2348 oop buffer[global_stack_transfer_size]; |
2402 oop buffer[G1CMMarkStack::OopsPerChunk]; |
2349 |
2403 |
2350 int n = 0; |
2404 size_t n = 0; |
2351 oop obj; |
2405 oop obj; |
2352 while (n < global_stack_transfer_size && _task_queue->pop_local(obj)) { |
2406 while (n < G1CMMarkStack::OopsPerChunk && _task_queue->pop_local(obj)) { |
2353 buffer[n] = obj; |
2407 buffer[n] = obj; |
2354 ++n; |
2408 ++n; |
2355 } |
2409 } |
|
2410 if (n < G1CMMarkStack::OopsPerChunk) { |
|
2411 buffer[n] = NULL; |
|
2412 } |
2356 |
2413 |
2357 if (n > 0) { |
2414 if (n > 0) { |
2358 // we popped at least one entry from the local queue |
2415 if (!_cm->mark_stack_push(buffer)) { |
2359 |
|
2360 if (!_cm->mark_stack_push(buffer, n)) { |
|
2361 set_has_aborted(); |
2416 set_has_aborted(); |
2362 } |
2417 } |
2363 } |
2418 } |
2364 |
2419 |
2365 // this operation was quite expensive, so decrease the limits |
2420 // This operation was quite expensive, so decrease the limits. |
2366 decrease_limits(); |
2421 decrease_limits(); |
2367 } |
2422 } |
2368 |
2423 |
2369 void G1CMTask::get_entries_from_global_stack() { |
2424 bool G1CMTask::get_entries_from_global_stack() { |
2370 // local array where we'll store the entries that will be popped |
2425 // Local array where we'll store the entries that will be popped |
2371 // from the global stack. |
2426 // from the global stack. |
2372 oop buffer[global_stack_transfer_size]; |
2427 oop buffer[G1CMMarkStack::OopsPerChunk]; |
2373 size_t n; |
2428 |
2374 _cm->mark_stack_pop(buffer, global_stack_transfer_size, &n); |
2429 if (!_cm->mark_stack_pop(buffer)) { |
2375 assert(n <= global_stack_transfer_size, |
2430 return false; |
2376 "we should not pop more than the given limit"); |
2431 } |
2377 if (n > 0) { |
2432 |
2378 // yes, we did actually pop at least one entry |
2433 // We did actually pop at least one entry. |
2379 for (size_t i = 0; i < n; ++i) { |
2434 for (size_t i = 0; i < G1CMMarkStack::OopsPerChunk; ++i) { |
2380 bool success = _task_queue->push(buffer[i]); |
2435 oop elem = buffer[i]; |
2381 // We only call this when the local queue is empty or under a |
2436 if (elem == NULL) { |
2382 // given target limit. So, we do not expect this push to fail. |
2437 break; |
2383 assert(success, "invariant"); |
2438 } |
2384 } |
2439 bool success = _task_queue->push(elem); |
2385 } |
2440 // We only call this when the local queue is empty or under a |
2386 |
2441 // given target limit. So, we do not expect this push to fail. |
2387 // this operation was quite expensive, so decrease the limits |
2442 assert(success, "invariant"); |
|
2443 } |
|
2444 |
|
2445 // This operation was quite expensive, so decrease the limits |
2388 decrease_limits(); |
2446 decrease_limits(); |
|
2447 return true; |
2389 } |
2448 } |
2390 |
2449 |
2391 void G1CMTask::drain_local_queue(bool partially) { |
2450 void G1CMTask::drain_local_queue(bool partially) { |
2392 if (has_aborted()) return; |
2451 if (has_aborted()) return; |
2393 |
2452 |