# HG changeset patch # User tschatzl # Date 1540989837 -3600 # Node ID 418fb8bb5151248d6d4ebb6abfd27a2dcccef1d9 # Parent 55711b181dfcd6b7cbf1d9c2fd56ba1ee2df705c 8071913: Filter out entries to free/uncommitted regions during iteration Reviewed-by: sjohanss, kbarrett diff -r 55711b181dfc -r 418fb8bb5151 src/hotspot/share/gc/g1/g1CollectedHeap.hpp --- a/src/hotspot/share/gc/g1/g1CollectedHeap.hpp Wed Oct 31 07:06:54 2018 -0400 +++ b/src/hotspot/share/gc/g1/g1CollectedHeap.hpp Wed Oct 31 13:43:57 2018 +0100 @@ -1120,6 +1120,7 @@ // Return the region with the given index. It assumes the index is valid. inline HeapRegion* region_at(uint index) const; + inline HeapRegion* region_at_or_null(uint index) const; // Return the next region (by index) that is part of the same // humongous object that hr is part of. @@ -1157,6 +1158,11 @@ template inline HeapRegion* heap_region_containing(const T addr) const; + // Returns the HeapRegion that contains addr, or NULL if that is an uncommitted + // region. addr must not be NULL. + template + inline HeapRegion* heap_region_containing_or_null(const T addr) const; + // A CollectedHeap is divided into a dense sequence of "blocks"; that is, // each address in the (reserved) heap is a member of exactly // one block. The defining characteristic of a block is that it is diff -r 55711b181dfc -r 418fb8bb5151 src/hotspot/share/gc/g1/g1CollectedHeap.inline.hpp --- a/src/hotspot/share/gc/g1/g1CollectedHeap.inline.hpp Wed Oct 31 07:06:54 2018 -0400 +++ b/src/hotspot/share/gc/g1/g1CollectedHeap.inline.hpp Wed Oct 31 13:43:57 2018 +0100 @@ -60,6 +60,9 @@ // Return the region with the given index. It assumes the index is valid. inline HeapRegion* G1CollectedHeap::region_at(uint index) const { return _hrm.at(index); } +// Return the region with the given index, or NULL if unmapped. It assumes the index is valid. +inline HeapRegion* G1CollectedHeap::region_at_or_null(uint index) const { return _hrm.at_or_null(index); } + inline HeapRegion* G1CollectedHeap::next_region_in_humongous(HeapRegion* hr) const { return _hrm.next_region_in_humongous(hr); } @@ -84,6 +87,16 @@ return _hrm.addr_to_region((HeapWord*) addr); } +template +inline HeapRegion* G1CollectedHeap::heap_region_containing_or_null(const T addr) const { + assert(addr != NULL, "invariant"); + assert(is_in_g1_reserved((const void*) addr), + "Address " PTR_FORMAT " is outside of the heap ranging from [" PTR_FORMAT " to " PTR_FORMAT ")", + p2i((void*)addr), p2i(g1_reserved().start()), p2i(g1_reserved().end())); + uint const region_idx = addr_to_region(addr); + return region_at_or_null(region_idx); +} + inline void G1CollectedHeap::old_set_add(HeapRegion* hr) { _old_set.add(hr); } diff -r 55711b181dfc -r 418fb8bb5151 src/hotspot/share/gc/g1/g1RemSet.cpp --- a/src/hotspot/share/gc/g1/g1RemSet.cpp Wed Oct 31 07:06:54 2018 -0400 +++ b/src/hotspot/share/gc/g1/g1RemSet.cpp Wed Oct 31 13:43:57 2018 +0100 @@ -133,10 +133,10 @@ virtual bool do_heap_region(HeapRegion* r) { uint hrm_index = r->hrm_index(); - if (!r->in_collection_set() && r->is_old_or_humongous_or_archive()) { + if (!r->in_collection_set() && r->is_old_or_humongous_or_archive() && !r->is_empty()) { _scan_top[hrm_index] = r->top(); } else { - _scan_top[hrm_index] = r->bottom(); + _scan_top[hrm_index] = NULL; } return false; } @@ -191,6 +191,7 @@ void reset() { for (uint i = 0; i < _max_regions; i++) { _iter_states[i] = Unclaimed; + _scan_top[i] = NULL; } G1ResetScanTopClosure cl(_scan_top); @@ -350,6 +351,10 @@ _scan_state->add_dirty_region(region_idx); } + if (r->rem_set()->cardset_is_empty()) { + return; + } + // We claim cards in blocks so as to reduce the contention. size_t const block_size = G1RSetScanBlockSize; @@ -367,18 +372,21 @@ } _cards_claimed++; - // If the card is dirty, then G1 will scan it during Update RS. - if (_ct->is_card_claimed(card_index) || _ct->is_card_dirty(card_index)) { + HeapWord* const card_start = _g1h->bot()->address_for_index_raw(card_index); + uint const region_idx_for_card = _g1h->addr_to_region(card_start); + +#ifdef ASSERT + HeapRegion* hr = _g1h->region_at_or_null(region_idx_for_card); + assert(hr == NULL || hr->is_in_reserved(card_start), + "Card start " PTR_FORMAT " to scan outside of region %u", p2i(card_start), _g1h->region_at(region_idx_for_card)->hrm_index()); +#endif + HeapWord* const top = _scan_state->scan_top(region_idx_for_card); + if (card_start >= top) { continue; } - HeapWord* const card_start = _g1h->bot()->address_for_index(card_index); - uint const region_idx_for_card = _g1h->addr_to_region(card_start); - - assert(_g1h->region_at(region_idx_for_card)->is_in_reserved(card_start), - "Card start " PTR_FORMAT " to scan outside of region %u", p2i(card_start), _g1h->region_at(region_idx_for_card)->hrm_index()); - HeapWord* const top = _scan_state->scan_top(region_idx_for_card); - if (card_start >= top) { + // If the card is dirty, then G1 will scan it during Update RS. + if (_ct->is_card_claimed(card_index) || _ct->is_card_dirty(card_index)) { continue; } @@ -545,6 +553,16 @@ uint worker_i) { assert(!_g1h->is_gc_active(), "Only call concurrently"); + // Construct the region representing the card. + HeapWord* start = _ct->addr_for(card_ptr); + // And find the region containing it. + HeapRegion* r = _g1h->heap_region_containing_or_null(start); + + // If this is a (stale) card into an uncommitted region, exit. + if (r == NULL) { + return; + } + check_card_ptr(card_ptr, _ct); // If the card is no longer dirty, nothing to do. @@ -552,11 +570,6 @@ return; } - // Construct the region representing the card. - HeapWord* start = _ct->addr_for(card_ptr); - // And find the region containing it. - HeapRegion* r = _g1h->heap_region_containing(start); - // This check is needed for some uncommon cases where we should // ignore the card. // @@ -679,6 +692,18 @@ G1ScanObjsDuringUpdateRSClosure* update_rs_cl) { assert(_g1h->is_gc_active(), "Only call during GC"); + // Construct the region representing the card. + HeapWord* card_start = _ct->addr_for(card_ptr); + // And find the region containing it. + uint const card_region_idx = _g1h->addr_to_region(card_start); + + HeapWord* scan_limit = _scan_state->scan_top(card_region_idx); + if (scan_limit == NULL) { + // This is a card into an uncommitted region. We need to bail out early as we + // should not access the corresponding card table entry. + return false; + } + check_card_ptr(card_ptr, _ct); // If the card is no longer dirty, nothing to do. This covers cards that were already @@ -691,13 +716,7 @@ // number of potential duplicate scans (multiple threads may enqueue the same card twice). *card_ptr = G1CardTable::clean_card_val() | G1CardTable::claimed_card_val(); - // Construct the region representing the card. - HeapWord* card_start = _ct->addr_for(card_ptr); - // And find the region containing it. - uint const card_region_idx = _g1h->addr_to_region(card_start); - _scan_state->add_dirty_region(card_region_idx); - HeapWord* scan_limit = _scan_state->scan_top(card_region_idx); if (scan_limit <= card_start) { // If the card starts above the area in the region containing objects to scan, skip it. return false; diff -r 55711b181dfc -r 418fb8bb5151 src/hotspot/share/gc/g1/heapRegionManager.hpp --- a/src/hotspot/share/gc/g1/heapRegionManager.hpp Wed Oct 31 07:06:54 2018 -0400 +++ b/src/hotspot/share/gc/g1/heapRegionManager.hpp Wed Oct 31 13:43:57 2018 +0100 @@ -123,10 +123,7 @@ public: bool is_free(HeapRegion* hr) const; #endif - // Returns whether the given region is available for allocation. - bool is_available(uint region) const; - - public: +public: // Empty constructor, we'll initialize it with the initialize() method. HeapRegionManager(); @@ -147,6 +144,13 @@ // is valid. inline HeapRegion* at(uint index) const; + // Return the HeapRegion at the given index, NULL if the index + // is for an unavailable region. + inline HeapRegion* at_or_null(uint index) const; + + // Returns whether the given region is available for allocation. + bool is_available(uint region) const; + // Return the next region (by index) that is part of the same // humongous object that hr is part of. inline HeapRegion* next_region_in_humongous(HeapRegion* hr) const; diff -r 55711b181dfc -r 418fb8bb5151 src/hotspot/share/gc/g1/heapRegionManager.inline.hpp --- a/src/hotspot/share/gc/g1/heapRegionManager.inline.hpp Wed Oct 31 07:06:54 2018 -0400 +++ b/src/hotspot/share/gc/g1/heapRegionManager.inline.hpp Wed Oct 31 13:43:57 2018 +0100 @@ -47,6 +47,16 @@ return hr; } +inline HeapRegion* HeapRegionManager::at_or_null(uint index) const { + if (!is_available(index)) { + return NULL; + } + HeapRegion* hr = _regions.get_by_index(index); + assert(hr != NULL, "All available regions must have a HeapRegion but index %u has not.", index); + assert(hr->hrm_index() == index, "sanity"); + return hr; +} + inline HeapRegion* HeapRegionManager::next_region_in_humongous(HeapRegion* hr) const { uint index = hr->hrm_index(); assert(is_available(index), "pre-condition"); diff -r 55711b181dfc -r 418fb8bb5151 src/hotspot/share/gc/g1/heapRegionRemSet.cpp --- a/src/hotspot/share/gc/g1/heapRegionRemSet.cpp Wed Oct 31 07:06:54 2018 -0400 +++ b/src/hotspot/share/gc/g1/heapRegionRemSet.cpp Wed Oct 31 13:43:57 2018 +0100 @@ -751,7 +751,7 @@ _coarse_cur_region_cur_card = 0; HeapWord* r_bot = _g1h->region_at((uint) _coarse_cur_region_index)->bottom(); - _cur_region_card_offset = _bot->index_for(r_bot); + _cur_region_card_offset = _bot->index_for_raw(r_bot); } else { return false; } @@ -792,7 +792,7 @@ _fine_cur_prt = prt; HeapWord* r_bot = _fine_cur_prt->hr()->bottom(); - _cur_region_card_offset = _bot->index_for(r_bot); + _cur_region_card_offset = _bot->index_for_raw(r_bot); // The bitmap scan for the PRT always scans from _cur_region_cur_card + 1. // To avoid special-casing this start case, and not miss the first bitmap diff -r 55711b181dfc -r 418fb8bb5151 src/hotspot/share/gc/g1/heapRegionRemSet.hpp --- a/src/hotspot/share/gc/g1/heapRegionRemSet.hpp Wed Oct 31 07:06:54 2018 -0400 +++ b/src/hotspot/share/gc/g1/heapRegionRemSet.hpp Wed Oct 31 13:43:57 2018 +0100 @@ -187,8 +187,12 @@ static void setup_remset_size(); + bool cardset_is_empty() const { + return _other_regions.is_empty(); + } + bool is_empty() const { - return (strong_code_roots_list_length() == 0) && _other_regions.is_empty(); + return (strong_code_roots_list_length() == 0) && cardset_is_empty(); } bool occupancy_less_or_equal_than(size_t occ) const { @@ -353,7 +357,7 @@ }; class HeapRegionRemSetIterator : public StackObj { - private: +private: // The region RSet over which we are iterating. HeapRegionRemSet* _hrrs; @@ -401,7 +405,7 @@ // The Sparse remembered set iterator. SparsePRTIter _sparse_iter; - public: +public: HeapRegionRemSetIterator(HeapRegionRemSet* hrrs); // If there remains one or more cards to be yielded, returns true and