Tue, 10 Jun 2008 07:26:42 -0700
6688799: Second fix for Guarantee failure "Unexpected dirty card found"
Summary: Expand cardtable without committing over existing regions.
Reviewed-by: apetrusenko
src/share/vm/memory/cardTableModRefBS.cpp | file | annotate | diff | comparison | revisions |
1.1 --- a/src/share/vm/memory/cardTableModRefBS.cpp Mon Jun 09 07:18:59 2008 -0700 1.2 +++ b/src/share/vm/memory/cardTableModRefBS.cpp Tue Jun 10 07:26:42 2008 -0700 1.3 @@ -196,6 +196,8 @@ 1.4 assert(_whole_heap.contains(new_region), 1.5 "attempt to cover area not in reserved area"); 1.6 debug_only(verify_guard();) 1.7 + // collided is true if the expansion would push into another committed region 1.8 + debug_only(bool collided = false;) 1.9 int const ind = find_covering_region_by_base(new_region.start()); 1.10 MemRegion const old_region = _covered[ind]; 1.11 assert(old_region.start() == new_region.start(), "just checking"); 1.12 @@ -211,12 +213,36 @@ 1.13 } 1.14 // Align the end up to a page size (starts are already aligned). 1.15 jbyte* const new_end = byte_after(new_region.last()); 1.16 - HeapWord* const new_end_aligned = 1.17 + HeapWord* new_end_aligned = 1.18 (HeapWord*) align_size_up((uintptr_t)new_end, _page_size); 1.19 assert(new_end_aligned >= (HeapWord*) new_end, 1.20 "align up, but less"); 1.21 + int ri = 0; 1.22 + for (ri = 0; ri < _cur_covered_regions; ri++) { 1.23 + if (ri != ind) { 1.24 + if (_committed[ri].contains(new_end_aligned)) { 1.25 + assert((new_end_aligned >= _committed[ri].start()) && 1.26 + (_committed[ri].start() > _committed[ind].start()), 1.27 + "New end of committed region is inconsistent"); 1.28 + new_end_aligned = _committed[ri].start(); 1.29 + assert(new_end_aligned > _committed[ind].start(), 1.30 + "New end of committed region is before start"); 1.31 + debug_only(collided = true;) 1.32 + // Should only collide with 1 region 1.33 + break; 1.34 + } 1.35 + } 1.36 + } 1.37 +#ifdef ASSERT 1.38 + for (++ri; ri < _cur_covered_regions; ri++) { 1.39 + assert(!_committed[ri].contains(new_end_aligned), 1.40 + "New end of committed region is in a second committed region"); 1.41 + } 1.42 +#endif 1.43 // The guard page is always committed and should not be committed over. 1.44 - HeapWord* const new_end_for_commit = MIN2(new_end_aligned, _guard_region.start()); 1.45 + HeapWord* const new_end_for_commit = MIN2(new_end_aligned, 1.46 + _guard_region.start()); 1.47 + 1.48 if (new_end_for_commit > cur_committed.end()) { 1.49 // Must commit new pages. 1.50 MemRegion const new_committed = 1.51 @@ -239,9 +265,11 @@ 1.52 if (!uncommit_region.is_empty()) { 1.53 if (!os::uncommit_memory((char*)uncommit_region.start(), 1.54 uncommit_region.byte_size())) { 1.55 - // Do better than this for Merlin 1.56 - vm_exit_out_of_memory(uncommit_region.byte_size(), 1.57 - "card table contraction"); 1.58 + assert(false, "Card table contraction failed"); 1.59 + // The call failed so don't change the end of the 1.60 + // committed region. This is better than taking the 1.61 + // VM down. 1.62 + new_end_aligned = _committed[ind].end(); 1.63 } 1.64 } 1.65 } 1.66 @@ -257,8 +285,25 @@ 1.67 } 1.68 assert(index_for(new_region.last()) < (int) _guard_index, 1.69 "The guard card will be overwritten"); 1.70 - jbyte* const end = byte_after(new_region.last()); 1.71 + // This line commented out cleans the newly expanded region and 1.72 + // not the aligned up expanded region. 1.73 + // jbyte* const end = byte_after(new_region.last()); 1.74 + jbyte* const end = (jbyte*) new_end_for_commit; 1.75 + assert((end >= byte_after(new_region.last())) || collided, 1.76 + "Expect to be beyond new region unless impacting another region"); 1.77 // do nothing if we resized downward. 1.78 +#ifdef ASSERT 1.79 + for (int ri = 0; ri < _cur_covered_regions; ri++) { 1.80 + if (ri != ind) { 1.81 + // The end of the new committed region should not 1.82 + // be in any existing region unless it matches 1.83 + // the start of the next region. 1.84 + assert(!_committed[ri].contains(end) || 1.85 + (_committed[ri].start() == (HeapWord*) end), 1.86 + "Overlapping committed regions"); 1.87 + } 1.88 + } 1.89 +#endif 1.90 if (entry < end) { 1.91 memset(entry, clean_card, pointer_delta(end, entry, sizeof(jbyte))); 1.92 }