8071913: Filter out entries to free/uncommitted regions during iteration
Reviewed-by: sjohanss, kbarrett
--- 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 <class T>
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 <class T>
+ 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
--- 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 <class T>
+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);
}
--- 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;
--- 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;
--- 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");
--- 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
--- 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