src/share/vm/gc_implementation/g1/heapRegionSeq.cpp

Print this page
rev 4204 : 7163191: G1: introduce a "heap spanning table" abstraction
Summary: Add a heap spanning table and employ it for the heap region sequence table.
Reviewed-by:
rev 4205 : imported patch bengt-and-thomas-comments

*** 69,153 **** } } // Public ! void HeapRegionSeq::initialize(HeapWord* bottom, HeapWord* end, ! uint max_length) { ! assert((uintptr_t) bottom % HeapRegion::GrainBytes == 0, ! "bottom should be heap region aligned"); ! assert((uintptr_t) end % HeapRegion::GrainBytes == 0, ! "end should be heap region aligned"); ! ! _length = 0; ! _heap_bottom = bottom; ! _heap_end = end; ! _region_shift = HeapRegion::LogOfHRGrainBytes; ! _next_search_index = 0; ! _allocated_length = 0; ! _max_length = max_length; ! ! _regions = NEW_C_HEAP_ARRAY(HeapRegion*, max_length, mtGC); ! memset(_regions, 0, (size_t) max_length * sizeof(HeapRegion*)); ! _regions_biased = _regions - ((uintx) bottom >> _region_shift); ! ! assert(&_regions[0] == &_regions_biased[addr_to_index_biased(bottom)], ! "bottom should be included in the region with index 0"); ! } ! ! MemRegion HeapRegionSeq::expand_by(HeapWord* old_end, ! HeapWord* new_end, ! FreeRegionList* list) { ! assert(old_end < new_end, "don't call it otherwise"); G1CollectedHeap* g1h = G1CollectedHeap::heap(); ! HeapWord* next_bottom = old_end; ! assert(_heap_bottom <= next_bottom, "invariant"); ! while (next_bottom < new_end) { ! assert(next_bottom < _heap_end, "invariant"); uint index = length(); - assert(index < _max_length, "otherwise we cannot expand further"); if (index == 0) { ! // We have not allocated any regions so far ! assert(next_bottom == _heap_bottom, "invariant"); } else { ! // next_bottom should match the end of the last/previous region ! assert(next_bottom == at(index - 1)->end(), "invariant"); } ! if (index == _allocated_length) { ! // We have to allocate a new HeapRegion. ! HeapRegion* new_hr = g1h->new_heap_region(index, next_bottom); ! if (new_hr == NULL) { ! // allocation failed, we bail out and return what we have done so far ! return MemRegion(old_end, next_bottom); ! } ! assert(_regions[index] == NULL, "invariant"); ! _regions[index] = new_hr; ! increment_length(&_allocated_length); ! } ! // Have to increment the length first, otherwise we will get an ! // assert failure at(index) below. ! increment_length(&_length); ! HeapRegion* hr = at(index); list->add_as_tail(hr); ! next_bottom = hr->end(); } ! assert(next_bottom == new_end, "post-condition"); ! return MemRegion(old_end, next_bottom); } uint HeapRegionSeq::free_suffix() { uint res = 0; uint index = length(); while (index > 0) { index -= 1; ! if (!at(index)->is_empty()) { ! break; ! } res += 1; } return res; } --- 69,133 ---- } } // Public ! MemRegion HeapRegionSeq::expand_to(HeapWord* new_end, FreeRegionList* list) { ! assert(_heap_end < new_end && new_end <= _max_heap_end, ! err_msg("new_end: "PTR_FORMAT" heap end: "PTR_FORMAT" " ! "max heap end: "PTR_FORMAT, new_end, _heap_end, _max_heap_end)); G1CollectedHeap* g1h = G1CollectedHeap::heap(); ! uint new_length = length_for(new_end); uint index = length(); + HeapWord* next_hr_bottom = _heap_end; + while (index < new_length) { + assert(length_for(next_hr_bottom) == index, + err_msg("invariant, length_for: "PTR_FORMAT" %u index: %u", + next_hr_bottom, length_for(next_hr_bottom), index)); if (index == 0) { ! // We have not allocated any regions so far. ! assert(next_hr_bottom == _heap_bottom, "invariant"); } else { ! // The previous region should exist. ! assert(_regions[index - 1] != NULL, "invariant"); ! // next_hr_bottom should match the end of the previous region. ! assert(next_hr_bottom == _regions[index - 1]->end(), "invariant"); } ! HeapRegion* hr; ! if (index < _length_high_watermark) { ! // This region should have been previously allocated. ! assert(_regions[index] != NULL, err_msg("invariant, index: %u", index)); ! ! hr = _regions[index]; ! } else { ! // We have to allocate a new region. ! assert(_regions[index] == NULL, err_msg("invariant, index: %u", index)); ! ! hr = g1h->new_heap_region(index, next_hr_bottom); ! // If allocation fails, bail out and return what we have done so far. ! if (hr == NULL) break; ! _regions[index] = hr; ! } list->add_as_tail(hr); ! index += 1; ! next_hr_bottom = hr->end(); } ! ! HeapWord* prev_heap_end = update_heap_end(next_hr_bottom); ! return MemRegion(prev_heap_end, next_hr_bottom); } uint HeapRegionSeq::free_suffix() { uint res = 0; uint index = length(); while (index > 0) { index -= 1; ! if (!at(index)->is_empty()) break; res += 1; } return res; }
*** 199,275 **** return; } } } ! MemRegion HeapRegionSeq::shrink_by(size_t shrink_bytes, uint* num_regions_deleted) { // Reset this in case it's currently pointing into the regions that // we just removed. _next_search_index = 0; ! assert(shrink_bytes % os::vm_page_size() == 0, "unaligned"); ! assert(shrink_bytes % HeapRegion::GrainBytes == 0, "unaligned"); ! assert(length() > 0, "the region sequence should not be empty"); ! assert(length() <= _allocated_length, "invariant"); ! assert(_allocated_length > 0, "we should have at least one region committed"); ! ! // around the loop, i will be the next region to be removed ! uint i = length() - 1; ! assert(i > 0, "we should never remove all regions"); ! // [last_start, end) is the MemRegion that covers the regions we will remove. ! HeapWord* end = at(i)->end(); ! HeapWord* last_start = end; ! *num_regions_deleted = 0; ! while (shrink_bytes > 0) { ! HeapRegion* cur = at(i); // We should leave the humongous regions where they are. ! if (cur->isHumongous()) break; // We should stop shrinking if we come across a non-empty region. ! if (!cur->is_empty()) break; ! i -= 1; ! *num_regions_deleted += 1; ! shrink_bytes -= cur->capacity(); ! last_start = cur->bottom(); ! decrement_length(&_length); ! // We will reclaim the HeapRegion. _allocated_length should be ! // covering this index. So, even though we removed the region from ! // the active set by decreasing _length, we still have it ! // available in the future if we need to re-use it. ! assert(i > 0, "we should never remove all regions"); ! assert(length() > 0, "we should never remove all regions"); } ! return MemRegion(last_start, end); } #ifndef PRODUCT void HeapRegionSeq::verify_optional() { ! guarantee(_length <= _allocated_length, ! err_msg("invariant: _length: %u _allocated_length: %u", ! _length, _allocated_length)); ! guarantee(_allocated_length <= _max_length, ! err_msg("invariant: _allocated_length: %u _max_length: %u", ! _allocated_length, _max_length)); guarantee(_next_search_index <= _length, err_msg("invariant: _next_search_index: %u _length: %u", _next_search_index, _length)); HeapWord* prev_end = _heap_bottom; ! for (uint i = 0; i < _allocated_length; i += 1) { HeapRegion* hr = _regions[i]; guarantee(hr != NULL, err_msg("invariant: i: %u", i)); guarantee(hr->bottom() == prev_end, err_msg("invariant i: %u "HR_FORMAT" prev_end: "PTR_FORMAT, i, HR_FORMAT_PARAMS(hr), prev_end)); guarantee(hr->hrs_index() == i, err_msg("invariant: i: %u hrs_index(): %u", i, hr->hrs_index())); if (i < _length) { // Asserts will fire if i is >= _length HeapWord* addr = hr->bottom(); ! guarantee(addr_to_region(addr) == hr, "sanity"); ! guarantee(addr_to_region_unsafe(addr) == hr, "sanity"); } else { guarantee(hr->is_empty(), "sanity"); guarantee(!hr->isHumongous(), "sanity"); // using assert instead of guarantee here since containing_set() // is only available in non-product builds. --- 179,250 ---- return; } } } ! MemRegion HeapRegionSeq::shrink_to(HeapWord* new_end, uint* num_regions_deleted) { + assert(_heap_bottom < new_end && new_end <= _heap_end, + err_msg("new_end: "PTR_FORMAT" heap bottom: "PTR_FORMAT" " + "heap end: "PTR_FORMAT, new_end, _heap_bottom, _heap_end)); + // Reset this in case it's currently pointing into the regions that // we just removed. _next_search_index = 0; ! uint new_length = length_for(new_end); ! uint index = length(); ! HeapWord* last_hr_bottom = _heap_end; ! while (index > new_length) { ! assert(length_for(last_hr_bottom) == index, ! err_msg("invariant, length_for: "PTR_FORMAT" %u index: %u", ! last_hr_bottom, length_for(last_hr_bottom), index)); ! ! HeapRegion* hr = at(index - 1); // We should leave the humongous regions where they are. ! if (hr->isHumongous()) break; // We should stop shrinking if we come across a non-empty region. ! if (!hr->is_empty()) break; ! ! index -= 1; ! last_hr_bottom = hr->bottom(); ! } ! ! *num_regions_deleted = length() - index; ! if (new_end == _heap_end) { ! assert(*num_regions_deleted == 0, "invariant"); ! } else { ! assert(*num_regions_deleted > 0, "invariant"); } ! ! HeapWord* prev_heap_end = update_heap_end(last_hr_bottom); ! return MemRegion(last_hr_bottom, prev_heap_end); } #ifndef PRODUCT void HeapRegionSeq::verify_optional() { ! G1HeapSpanningTable<HeapRegion*>::verify_optional(); ! guarantee(_next_search_index <= _length, err_msg("invariant: _next_search_index: %u _length: %u", _next_search_index, _length)); HeapWord* prev_end = _heap_bottom; ! for (uint i = 0; i < _length_high_watermark; i += 1) { HeapRegion* hr = _regions[i]; guarantee(hr != NULL, err_msg("invariant: i: %u", i)); guarantee(hr->bottom() == prev_end, err_msg("invariant i: %u "HR_FORMAT" prev_end: "PTR_FORMAT, i, HR_FORMAT_PARAMS(hr), prev_end)); guarantee(hr->hrs_index() == i, err_msg("invariant: i: %u hrs_index(): %u", i, hr->hrs_index())); if (i < _length) { // Asserts will fire if i is >= _length HeapWord* addr = hr->bottom(); ! guarantee(at(addr) == hr, "sanity"); ! guarantee(at_unsafe(addr) == hr, "sanity"); } else { guarantee(hr->is_empty(), "sanity"); guarantee(!hr->isHumongous(), "sanity"); // using assert instead of guarantee here since containing_set() // is only available in non-product builds.
*** 279,288 **** prev_end = hr->orig_end(); } else { prev_end = hr->end(); } } ! for (uint i = _allocated_length; i < _max_length; i += 1) { guarantee(_regions[i] == NULL, err_msg("invariant i: %u", i)); } } #endif // PRODUCT --- 254,270 ---- prev_end = hr->orig_end(); } else { prev_end = hr->end(); } } ! for (uint i = _length_high_watermark; i < _max_length; i += 1) { guarantee(_regions[i] == NULL, err_msg("invariant i: %u", i)); } } #endif // PRODUCT + + void HeapRegionSeq::initialize(HeapWord* bottom, HeapWord* max_end) { + initialize_base(bottom, max_end, HeapRegion::LogOfHRGrainBytes); + _next_search_index = 0; + _regions = create_new_array(); + _regions_biased = get_biased_array(_regions); + }