changeset 60849:9623140d2685

8242038: G1: Lazily initialize RSHashTables Reviewed-by: kbarrett, sjohanss, tschatzl
author redestad
date Thu, 09 Apr 2020 13:04:10 +0200
parents 193e4179def8
children 7992ff451fec
files src/hotspot/share/gc/g1/sparsePRT.cpp src/hotspot/share/gc/g1/sparsePRT.hpp
diffstat 2 files changed, 51 insertions(+), 20 deletions(-) [+]
line wrap: on
line diff
--- a/src/hotspot/share/gc/g1/sparsePRT.cpp	Wed Apr 08 22:58:42 2020 -0700
+++ b/src/hotspot/share/gc/g1/sparsePRT.cpp	Thu Apr 09 13:04:10 2020 +0200
@@ -85,6 +85,21 @@
 
 float RSHashTable::TableOccupancyFactor = 0.5f;
 
+// The empty table can't hold any entries and is effectively immutable
+// This means it can be used as an initial sentinel value
+static int empty_buckets[] = { RSHashTable::NullEntry };
+RSHashTable RSHashTable::empty_table;
+
+RSHashTable::RSHashTable() :
+  _num_entries(0),
+  _capacity(0),
+  _capacity_mask(0),
+  _occupied_entries(0),
+  _entries(NULL),
+  _buckets(empty_buckets),
+  _free_region(0),
+  _free_list(NullEntry) { }
+
 RSHashTable::RSHashTable(size_t capacity) :
   _num_entries((capacity * TableOccupancyFactor) + 1),
   _capacity(capacity),
@@ -99,14 +114,19 @@
 }
 
 RSHashTable::~RSHashTable() {
-  FREE_C_HEAP_ARRAY(SparsePRTEntry, _entries);
-  FREE_C_HEAP_ARRAY(int, _buckets);
+  // Nothing to free for empty RSHashTable
+  if (_buckets != empty_buckets) {
+    assert(_entries != NULL, "invariant");
+    FREE_C_HEAP_ARRAY(SparsePRTEntry, _entries);
+    FREE_C_HEAP_ARRAY(int, _buckets);
+  }
 }
 
 void RSHashTable::clear() {
+  assert(_buckets != empty_buckets, "Shouldn't call this for the empty_table");
   _occupied_entries = 0;
-  guarantee(_entries != NULL, "INV");
-  guarantee(_buckets != NULL, "INV");
+  guarantee(_entries != NULL, "invariant");
+  guarantee(_buckets != NULL, "invariant");
 
   guarantee(_capacity <= ((size_t)1 << (sizeof(int)*BitsPerByte-1)) - 1,
                 "_capacity too large");
@@ -119,6 +139,7 @@
 }
 
 SparsePRT::AddCardResult RSHashTable::add_card(RegionIdx_t region_ind, CardIdx_t card_index) {
+  assert(this != &empty_table, "can't add a card to the empty table");
   SparsePRTEntry* e = entry_for_region_ind_create(region_ind);
   assert(e != NULL && e->r_ind() == region_ind,
          "Postcondition of call above.");
@@ -207,7 +228,7 @@
 
 bool RSHashTableBucketIter::has_next(SparsePRTEntry*& entry) {
   while (_bl_ind == RSHashTable::NullEntry)  {
-    if (_tbl_ind == (int)_rsht->capacity() - 1) {
+    if (_tbl_ind + 1 >= _rsht->capacity()) {
       return false;
     }
     _tbl_ind++;
@@ -231,12 +252,14 @@
 // ----------------------------------------------------------------------
 
 SparsePRT::SparsePRT() :
-  _table(new RSHashTable(InitialCapacity)) {
+  _table(&RSHashTable::empty_table) {
 }
 
 
 SparsePRT::~SparsePRT() {
-  delete _table;
+  if (_table != &RSHashTable::empty_table) {
+    delete _table;
+  }
 }
 
 
@@ -262,23 +285,27 @@
 }
 
 void SparsePRT::clear() {
-  // If the entry table is not at initial capacity, just create a new one.
-  if (_table->capacity() != InitialCapacity) {
+  // If the entry table not at initial capacity, just reset to the empty table.
+  if (_table->capacity() == InitialCapacity) {
+    _table->clear();
+  } else if (_table != &RSHashTable::empty_table) {
     delete _table;
-    _table = new RSHashTable(InitialCapacity);
-  } else {
-    _table->clear();
+    _table = &RSHashTable::empty_table;
   }
 }
 
 void SparsePRT::expand() {
   RSHashTable* last = _table;
-  _table = new RSHashTable(last->capacity() * 2);
-  for (size_t i = 0; i < last->num_entries(); i++) {
-    SparsePRTEntry* e = last->entry((int)i);
-    if (e->valid_entry()) {
-      _table->add_entry(e);
+  if (last != &RSHashTable::empty_table) {
+    _table = new RSHashTable(last->capacity() * 2);
+    for (size_t i = 0; i < last->num_entries(); i++) {
+      SparsePRTEntry* e = last->entry((int)i);
+      if (e->valid_entry()) {
+        _table->add_entry(e);
+      }
     }
+    delete last;
+  } else {
+    _table = new RSHashTable(InitialCapacity);
   }
-  delete last;
 }
--- a/src/hotspot/share/gc/g1/sparsePRT.hpp	Wed Apr 08 22:58:42 2020 -0700
+++ b/src/hotspot/share/gc/g1/sparsePRT.hpp	Thu Apr 09 13:04:10 2020 +0200
@@ -173,11 +173,15 @@
   // deleted from any bucket lists.
   void free_entry(int fi);
 
+  // For the empty sentinel created at static initialization time
+  RSHashTable();
+
 public:
   RSHashTable(size_t capacity);
   ~RSHashTable();
 
   static const int NullEntry = -1;
+  static RSHashTable empty_table;
 
   bool should_expand() const { return _occupied_entries == _num_entries; }
 
@@ -215,8 +219,8 @@
 
 // This is embedded in HRRS iterator.
 class RSHashTableBucketIter {
-  int _tbl_ind;         // [-1, 0.._rsht->_capacity)
-  int _bl_ind;          // [-1, 0.._rsht->_capacity)
+  uint _tbl_ind;        // [0.._rsht->_capacity)
+  int  _bl_ind;         // [-1, 0.._rsht->_capacity)
 
   RSHashTable* _rsht;