8242038: G1: Lazily initialize RSHashTables

Reviewed-by: kbarrett, sjohanss, tschatzl
This commit is contained in:
Claes Redestad 2020-04-09 13:04:10 +02:00
parent 7c351405c4
commit cdfe841d3d
2 changed files with 51 additions and 20 deletions

View File

@ -85,6 +85,21 @@ void SparsePRTEntry::copy_cards(SparsePRTEntry* e) const {
float RSHashTable::TableOccupancyFactor = 0.5f; 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) : RSHashTable::RSHashTable(size_t capacity) :
_num_entries((capacity * TableOccupancyFactor) + 1), _num_entries((capacity * TableOccupancyFactor) + 1),
_capacity(capacity), _capacity(capacity),
@ -99,14 +114,19 @@ RSHashTable::RSHashTable(size_t capacity) :
} }
RSHashTable::~RSHashTable() { RSHashTable::~RSHashTable() {
FREE_C_HEAP_ARRAY(SparsePRTEntry, _entries); // Nothing to free for empty RSHashTable
FREE_C_HEAP_ARRAY(int, _buckets); if (_buckets != empty_buckets) {
assert(_entries != NULL, "invariant");
FREE_C_HEAP_ARRAY(SparsePRTEntry, _entries);
FREE_C_HEAP_ARRAY(int, _buckets);
}
} }
void RSHashTable::clear() { void RSHashTable::clear() {
assert(_buckets != empty_buckets, "Shouldn't call this for the empty_table");
_occupied_entries = 0; _occupied_entries = 0;
guarantee(_entries != NULL, "INV"); guarantee(_entries != NULL, "invariant");
guarantee(_buckets != NULL, "INV"); guarantee(_buckets != NULL, "invariant");
guarantee(_capacity <= ((size_t)1 << (sizeof(int)*BitsPerByte-1)) - 1, guarantee(_capacity <= ((size_t)1 << (sizeof(int)*BitsPerByte-1)) - 1,
"_capacity too large"); "_capacity too large");
@ -119,6 +139,7 @@ void RSHashTable::clear() {
} }
SparsePRT::AddCardResult RSHashTable::add_card(RegionIdx_t region_ind, CardIdx_t card_index) { 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); SparsePRTEntry* e = entry_for_region_ind_create(region_ind);
assert(e != NULL && e->r_ind() == region_ind, assert(e != NULL && e->r_ind() == region_ind,
"Postcondition of call above."); "Postcondition of call above.");
@ -207,7 +228,7 @@ void RSHashTable::add_entry(SparsePRTEntry* e) {
bool RSHashTableBucketIter::has_next(SparsePRTEntry*& entry) { bool RSHashTableBucketIter::has_next(SparsePRTEntry*& entry) {
while (_bl_ind == RSHashTable::NullEntry) { while (_bl_ind == RSHashTable::NullEntry) {
if (_tbl_ind == (int)_rsht->capacity() - 1) { if (_tbl_ind + 1 >= _rsht->capacity()) {
return false; return false;
} }
_tbl_ind++; _tbl_ind++;
@ -231,12 +252,14 @@ size_t RSHashTable::mem_size() const {
// ---------------------------------------------------------------------- // ----------------------------------------------------------------------
SparsePRT::SparsePRT() : SparsePRT::SparsePRT() :
_table(new RSHashTable(InitialCapacity)) { _table(&RSHashTable::empty_table) {
} }
SparsePRT::~SparsePRT() { SparsePRT::~SparsePRT() {
delete _table; if (_table != &RSHashTable::empty_table) {
delete _table;
}
} }
@ -262,23 +285,27 @@ bool SparsePRT::delete_entry(RegionIdx_t region_id) {
} }
void SparsePRT::clear() { void SparsePRT::clear() {
// If the entry table is not at initial capacity, just create a new one. // If the entry table not at initial capacity, just reset to the empty table.
if (_table->capacity() != InitialCapacity) { if (_table->capacity() == InitialCapacity) {
delete _table;
_table = new RSHashTable(InitialCapacity);
} else {
_table->clear(); _table->clear();
} else if (_table != &RSHashTable::empty_table) {
delete _table;
_table = &RSHashTable::empty_table;
} }
} }
void SparsePRT::expand() { void SparsePRT::expand() {
RSHashTable* last = _table; RSHashTable* last = _table;
_table = new RSHashTable(last->capacity() * 2); if (last != &RSHashTable::empty_table) {
for (size_t i = 0; i < last->num_entries(); i++) { _table = new RSHashTable(last->capacity() * 2);
SparsePRTEntry* e = last->entry((int)i); for (size_t i = 0; i < last->num_entries(); i++) {
if (e->valid_entry()) { SparsePRTEntry* e = last->entry((int)i);
_table->add_entry(e); if (e->valid_entry()) {
_table->add_entry(e);
}
} }
delete last;
} else {
_table = new RSHashTable(InitialCapacity);
} }
delete last;
} }

View File

@ -173,11 +173,15 @@ class RSHashTable : public CHeapObj<mtGC> {
// deleted from any bucket lists. // deleted from any bucket lists.
void free_entry(int fi); void free_entry(int fi);
// For the empty sentinel created at static initialization time
RSHashTable();
public: public:
RSHashTable(size_t capacity); RSHashTable(size_t capacity);
~RSHashTable(); ~RSHashTable();
static const int NullEntry = -1; static const int NullEntry = -1;
static RSHashTable empty_table;
bool should_expand() const { return _occupied_entries == _num_entries; } bool should_expand() const { return _occupied_entries == _num_entries; }
@ -215,8 +219,8 @@ public:
// This is embedded in HRRS iterator. // This is embedded in HRRS iterator.
class RSHashTableBucketIter { class RSHashTableBucketIter {
int _tbl_ind; // [-1, 0.._rsht->_capacity) uint _tbl_ind; // [0.._rsht->_capacity)
int _bl_ind; // [-1, 0.._rsht->_capacity) int _bl_ind; // [-1, 0.._rsht->_capacity)
RSHashTable* _rsht; RSHashTable* _rsht;