comparison src/share/vm/gc_implementation/g1/heapRegionRemSet.cpp @ 1259:9eee977dd1a9

6802453: G1: hr()->is_in_reserved(from),"Precondition." Summary: The operations of re-using a RSet component and expanding the same RSet component were not mutually exlusive, and this could lead to RSets getting corrupted and entries being dropped. Reviewed-by: iveresov, johnc
author tonyp
date Mon, 08 Feb 2010 14:23:01 -0500
parents 2c79770d1f6e
children 0414c1049f15
comparison
equal deleted inserted replaced
1258:38836cf1d8d2 1259:9eee977dd1a9
256 256
257 enum SomePrivateConstants { 257 enum SomePrivateConstants {
258 ReserveParTableExpansion = 1 258 ReserveParTableExpansion = 1
259 }; 259 };
260 260
261 void par_expand() {
262 int n = HeapRegionRemSet::num_par_rem_sets()-1;
263 if (n <= 0) return;
264 if (_par_tables == NULL) {
265 PerRegionTable* res =
266 (PerRegionTable*)
267 Atomic::cmpxchg_ptr((PerRegionTable*)ReserveParTableExpansion,
268 &_par_tables, NULL);
269 if (res != NULL) return;
270 // Otherwise, we reserved the right to do the expansion.
271
272 PerRegionTable** ptables = NEW_C_HEAP_ARRAY(PerRegionTable*, n);
273 for (int i = 0; i < n; i++) {
274 PerRegionTable* ptable = PerRegionTable::alloc(hr());
275 ptables[i] = ptable;
276 }
277 // Here we do not need an atomic.
278 _par_tables = ptables;
279 #if COUNT_PAR_EXPANDS
280 print_par_expand();
281 #endif
282 // We must put this table on the expanded list.
283 PosParPRT* exp_head = _par_expanded_list;
284 while (true) {
285 set_next_par_expanded(exp_head);
286 PosParPRT* res =
287 (PosParPRT*)
288 Atomic::cmpxchg_ptr(this, &_par_expanded_list, exp_head);
289 if (res == exp_head) return;
290 // Otherwise.
291 exp_head = res;
292 }
293 ShouldNotReachHere();
294 }
295 }
296
297 void par_contract() { 261 void par_contract() {
298 assert(_par_tables != NULL, "Precondition."); 262 assert(_par_tables != NULL, "Precondition.");
299 int n = HeapRegionRemSet::num_par_rem_sets()-1; 263 int n = HeapRegionRemSet::num_par_rem_sets()-1;
300 for (int i = 0; i < n; i++) { 264 for (int i = 0; i < n; i++) {
301 _par_tables[i]->union_bitmap_into(bm()); 265 _par_tables[i]->union_bitmap_into(bm());
389 353
390 PosParPRT* next() const { return _next; } 354 PosParPRT* next() const { return _next; }
391 void set_next(PosParPRT* nxt) { _next = nxt; } 355 void set_next(PosParPRT* nxt) { _next = nxt; }
392 PosParPRT** next_addr() { return &_next; } 356 PosParPRT** next_addr() { return &_next; }
393 357
358 bool should_expand(int tid) {
359 return par_tables() == NULL && tid > 0 && hr()->is_gc_alloc_region();
360 }
361
362 void par_expand() {
363 int n = HeapRegionRemSet::num_par_rem_sets()-1;
364 if (n <= 0) return;
365 if (_par_tables == NULL) {
366 PerRegionTable* res =
367 (PerRegionTable*)
368 Atomic::cmpxchg_ptr((PerRegionTable*)ReserveParTableExpansion,
369 &_par_tables, NULL);
370 if (res != NULL) return;
371 // Otherwise, we reserved the right to do the expansion.
372
373 PerRegionTable** ptables = NEW_C_HEAP_ARRAY(PerRegionTable*, n);
374 for (int i = 0; i < n; i++) {
375 PerRegionTable* ptable = PerRegionTable::alloc(hr());
376 ptables[i] = ptable;
377 }
378 // Here we do not need an atomic.
379 _par_tables = ptables;
380 #if COUNT_PAR_EXPANDS
381 print_par_expand();
382 #endif
383 // We must put this table on the expanded list.
384 PosParPRT* exp_head = _par_expanded_list;
385 while (true) {
386 set_next_par_expanded(exp_head);
387 PosParPRT* res =
388 (PosParPRT*)
389 Atomic::cmpxchg_ptr(this, &_par_expanded_list, exp_head);
390 if (res == exp_head) return;
391 // Otherwise.
392 exp_head = res;
393 }
394 ShouldNotReachHere();
395 }
396 }
397
394 void add_reference(OopOrNarrowOopStar from, int tid) { 398 void add_reference(OopOrNarrowOopStar from, int tid) {
395 // Expand if necessary. 399 // Expand if necessary.
396 PerRegionTable** pt = par_tables(); 400 PerRegionTable** pt = par_tables();
397 if (par_tables() == NULL && tid > 0 && hr()->is_gc_alloc_region()) {
398 par_expand();
399 pt = par_tables();
400 }
401 if (pt != NULL) { 401 if (pt != NULL) {
402 // We always have to assume that mods to table 0 are in parallel, 402 // We always have to assume that mods to table 0 are in parallel,
403 // because of the claiming scheme in parallel expansion. A thread 403 // because of the claiming scheme in parallel expansion. A thread
404 // with tid != 0 that finds the table to be NULL, but doesn't succeed 404 // with tid != 0 that finds the table to be NULL, but doesn't succeed
405 // in claiming the right of expanding it, will end up in the else 405 // in claiming the right of expanding it, will end up in the else
694 // Note that we can't assert "prt->hr() == from_hr", because of the 694 // Note that we can't assert "prt->hr() == from_hr", because of the
695 // possibility of concurrent reuse. But see head comment of 695 // possibility of concurrent reuse. But see head comment of
696 // OtherRegionsTable for why this is OK. 696 // OtherRegionsTable for why this is OK.
697 assert(prt != NULL, "Inv"); 697 assert(prt != NULL, "Inv");
698 698
699 prt->add_reference(from, tid); 699 if (prt->should_expand(tid)) {
700 MutexLockerEx x(&_m, Mutex::_no_safepoint_check_flag);
701 HeapRegion* prt_hr = prt->hr();
702 if (prt_hr == from_hr) {
703 // Make sure the table still corresponds to the same region
704 prt->par_expand();
705 prt->add_reference(from, tid);
706 }
707 // else: The table has been concurrently coarsened, evicted, and
708 // the table data structure re-used for another table. So, we
709 // don't need to add the reference any more given that the table
710 // has been coarsened and the whole region will be scanned anyway.
711 } else {
712 prt->add_reference(from, tid);
713 }
700 if (G1RecordHRRSOops) { 714 if (G1RecordHRRSOops) {
701 HeapRegionRemSet::record(hr(), from); 715 HeapRegionRemSet::record(hr(), from);
702 #if HRRS_VERBOSE 716 #if HRRS_VERBOSE
703 gclog_or_tty->print("Added card " PTR_FORMAT " to region " 717 gclog_or_tty->print("Added card " PTR_FORMAT " to region "
704 "[" PTR_FORMAT "...) for ref " PTR_FORMAT ".\n", 718 "[" PTR_FORMAT "...) for ref " PTR_FORMAT ".\n",