8071913: Filter out entries to free/uncommitted regions during iteration
authortschatzl
Wed, 31 Oct 2018 13:43:57 +0100
changeset 52345 418fb8bb5151
parent 52344 55711b181dfc
child 52346 08041b0d7c08
8071913: Filter out entries to free/uncommitted regions during iteration Reviewed-by: sjohanss, kbarrett
src/hotspot/share/gc/g1/g1CollectedHeap.hpp
src/hotspot/share/gc/g1/g1CollectedHeap.inline.hpp
src/hotspot/share/gc/g1/g1RemSet.cpp
src/hotspot/share/gc/g1/heapRegionManager.hpp
src/hotspot/share/gc/g1/heapRegionManager.inline.hpp
src/hotspot/share/gc/g1/heapRegionRemSet.cpp
src/hotspot/share/gc/g1/heapRegionRemSet.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 <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