# HG changeset patch # User mgerdin # Date 1409310481 -7200 # Node ID 152cf4afc11f0648fbad47c74aab5fcce9d70675 # Parent 50d3433155d92f9c32c35349fe4b609ed18f35c3 8056084: Refactor Hashtable to allow implementations without rehashing support Reviewed-by: gziemski, jmasa, brutisso, coleenp, tschatzl diff -r 50d3433155d9 -r 152cf4afc11f src/share/vm/classfile/symbolTable.cpp --- a/src/share/vm/classfile/symbolTable.cpp Tue Sep 23 17:24:34 2014 -0700 +++ b/src/share/vm/classfile/symbolTable.cpp Fri Aug 29 13:08:01 2014 +0200 @@ -205,7 +205,7 @@ } } // If the bucket size is too deep check if this hash code is insufficient. - if (count >= BasicHashtable::rehash_count && !needs_rehashing()) { + if (count >= rehash_count && !needs_rehashing()) { _needs_rehashing = check_rehash_table(count); } return NULL; @@ -656,7 +656,7 @@ } } // If the bucket size is too deep check if this hash code is insufficient. - if (count >= BasicHashtable::rehash_count && !needs_rehashing()) { + if (count >= rehash_count && !needs_rehashing()) { _needs_rehashing = check_rehash_table(count); } return NULL; diff -r 50d3433155d9 -r 152cf4afc11f src/share/vm/classfile/symbolTable.hpp --- a/src/share/vm/classfile/symbolTable.hpp Tue Sep 23 17:24:34 2014 -0700 +++ b/src/share/vm/classfile/symbolTable.hpp Fri Aug 29 13:08:01 2014 +0200 @@ -74,7 +74,7 @@ operator Symbol*() { return _temp; } }; -class SymbolTable : public Hashtable { +class SymbolTable : public RehashableHashtable { friend class VMStructs; friend class ClassFileParser; @@ -110,10 +110,10 @@ Symbol* lookup(int index, const char* name, int len, unsigned int hash); SymbolTable() - : Hashtable(SymbolTableSize, sizeof (HashtableEntry)) {} + : RehashableHashtable(SymbolTableSize, sizeof (HashtableEntry)) {} SymbolTable(HashtableBucket* t, int number_of_entries) - : Hashtable(SymbolTableSize, sizeof (HashtableEntry), t, + : RehashableHashtable(SymbolTableSize, sizeof (HashtableEntry), t, number_of_entries) {} // Arena for permanent symbols (null class loader) that are never unloaded @@ -252,7 +252,7 @@ static int parallel_claimed_index() { return _parallel_claimed_idx; } }; -class StringTable : public Hashtable { +class StringTable : public RehashableHashtable { friend class VMStructs; private: @@ -278,11 +278,11 @@ // in the range [start_idx, end_idx). static void buckets_unlink_or_oops_do(BoolObjectClosure* is_alive, OopClosure* f, int start_idx, int end_idx, int* processed, int* removed); - StringTable() : Hashtable((int)StringTableSize, + StringTable() : RehashableHashtable((int)StringTableSize, sizeof (HashtableEntry)) {} StringTable(HashtableBucket* t, int number_of_entries) - : Hashtable((int)StringTableSize, sizeof (HashtableEntry), t, + : RehashableHashtable((int)StringTableSize, sizeof (HashtableEntry), t, number_of_entries) {} public: // The string table diff -r 50d3433155d9 -r 152cf4afc11f src/share/vm/utilities/hashtable.cpp --- a/src/share/vm/utilities/hashtable.cpp Tue Sep 23 17:24:34 2014 -0700 +++ b/src/share/vm/utilities/hashtable.cpp Fri Aug 29 13:08:01 2014 +0200 @@ -36,21 +36,22 @@ #include "utilities/numberSeq.hpp" -// This is a generic hashtable, designed to be used for the symbol -// and string tables. -// -// It is implemented as an open hash table with a fixed number of buckets. -// -// %note: -// - HashtableEntrys are allocated in blocks to reduce the space overhead. +// This hashtable is implemented as an open hash table with a fixed number of buckets. -template BasicHashtableEntry* BasicHashtable::new_entry(unsigned int hashValue) { - BasicHashtableEntry* entry; - - if (_free_list) { +template BasicHashtableEntry* BasicHashtable::new_entry_free_list() { + BasicHashtableEntry* entry = NULL; + if (_free_list != NULL) { entry = _free_list; _free_list = _free_list->next(); - } else { + } + return entry; +} + +// HashtableEntrys are allocated in blocks to reduce the space overhead. +template BasicHashtableEntry* BasicHashtable::new_entry(unsigned int hashValue) { + BasicHashtableEntry* entry = new_entry_free_list(); + + if (entry == NULL) { if (_first_free_entry + _entry_size >= _end_block) { int block_size = MIN2(512, MAX2((int)_table_size / 2, (int)_number_of_entries)); int len = _entry_size * block_size; @@ -83,9 +84,9 @@ // This is somewhat an arbitrary heuristic but if one bucket gets to // rehash_count which is currently 100, there's probably something wrong. -template bool BasicHashtable::check_rehash_table(int count) { - assert(table_size() != 0, "underflow"); - if (count > (((double)number_of_entries()/(double)table_size())*rehash_multiple)) { +template bool RehashableHashtable::check_rehash_table(int count) { + assert(this->table_size() != 0, "underflow"); + if (count > (((double)this->number_of_entries()/(double)this->table_size())*rehash_multiple)) { // Set a flag for the next safepoint, which should be at some guaranteed // safepoint interval. return true; @@ -93,13 +94,13 @@ return false; } -template juint Hashtable::_seed = 0; +template juint RehashableHashtable::_seed = 0; // Create a new table and using alternate hash code, populate the new table // with the existing elements. This can be used to change the hash code // and could in the future change the size of the table. -template void Hashtable::move_to(Hashtable* new_table) { +template void RehashableHashtable::move_to(RehashableHashtable* new_table) { // Initialize the global seed for hashing. _seed = AltHashing::compute_seed(); @@ -109,7 +110,7 @@ // Iterate through the table and create a new entry for the new table for (int i = 0; i < new_table->table_size(); ++i) { - for (HashtableEntry* p = bucket(i); p != NULL; ) { + for (HashtableEntry* p = this->bucket(i); p != NULL; ) { HashtableEntry* next = p->next(); T string = p->literal(); // Use alternate hashing algorithm on the symbol in the first table @@ -238,11 +239,11 @@ } } -template int Hashtable::literal_size(Symbol *symbol) { +template int RehashableHashtable::literal_size(Symbol *symbol) { return symbol->size() * HeapWordSize; } -template int Hashtable::literal_size(oop oop) { +template int RehashableHashtable::literal_size(oop oop) { // NOTE: this would over-count if (pre-JDK8) java_lang_Class::has_offset_field() is true, // and the String.value array is shared by several Strings. However, starting from JDK8, // the String.value array is not shared anymore. @@ -255,12 +256,12 @@ // Note: if you create a new subclass of Hashtable, you will need to // add a new function Hashtable::literal_size(MyNewType lit) -template void Hashtable::dump_table(outputStream* st, const char *table_name) { +template void RehashableHashtable::dump_table(outputStream* st, const char *table_name) { NumberSeq summary; int literal_bytes = 0; for (int i = 0; i < this->table_size(); ++i) { int count = 0; - for (HashtableEntry* e = bucket(i); + for (HashtableEntry* e = this->bucket(i); e != NULL; e = e->next()) { count++; literal_bytes += literal_size(e->literal()); @@ -270,7 +271,7 @@ double num_buckets = summary.num(); double num_entries = summary.sum(); - int bucket_bytes = (int)num_buckets * sizeof(bucket(0)); + int bucket_bytes = (int)num_buckets * sizeof(HashtableBucket); int entry_bytes = (int)num_entries * sizeof(HashtableEntry); int total_bytes = literal_bytes + bucket_bytes + entry_bytes; @@ -353,11 +354,14 @@ #endif // Explicitly instantiate these types template class Hashtable; +template class RehashableHashtable; +template class RehashableHashtable; template class Hashtable; template class Hashtable; template class Hashtable; #if defined(SOLARIS) || defined(CHECK_UNHANDLED_OOPS) template class Hashtable; +template class RehashableHashtable; #endif // SOLARIS || CHECK_UNHANDLED_OOPS template class Hashtable; template class Hashtable; diff -r 50d3433155d9 -r 152cf4afc11f src/share/vm/utilities/hashtable.hpp --- a/src/share/vm/utilities/hashtable.hpp Tue Sep 23 17:24:34 2014 -0700 +++ b/src/share/vm/utilities/hashtable.hpp Fri Aug 29 13:08:01 2014 +0200 @@ -178,11 +178,6 @@ void verify_lookup_length(double load); #endif - enum { - rehash_count = 100, - rehash_multiple = 60 - }; - void initialize(int table_size, int entry_size, int number_of_entries); // Accessor @@ -194,12 +189,12 @@ // The following method is not MT-safe and must be done under lock. BasicHashtableEntry** bucket_addr(int i) { return _buckets[i].entry_addr(); } + // Attempt to get an entry from the free list + BasicHashtableEntry* new_entry_free_list(); + // Table entry management BasicHashtableEntry* new_entry(unsigned int hashValue); - // Check that the table is unbalanced - bool check_rehash_table(int count); - // Used when moving the entry to another table // Clean up links, but do not add to free_list void unlink_entry(BasicHashtableEntry* entry) { @@ -277,8 +272,30 @@ return (HashtableEntry**)BasicHashtable::bucket_addr(i); } +}; + +template class RehashableHashtable : public Hashtable { + protected: + + enum { + rehash_count = 100, + rehash_multiple = 60 + }; + + // Check that the table is unbalanced + bool check_rehash_table(int count); + + public: + RehashableHashtable(int table_size, int entry_size) + : Hashtable(table_size, entry_size) { } + + RehashableHashtable(int table_size, int entry_size, + HashtableBucket* buckets, int number_of_entries) + : Hashtable(table_size, entry_size, buckets, number_of_entries) { } + + // Function to move these elements into the new table. - void move_to(Hashtable* new_table); + void move_to(RehashableHashtable* new_table); static bool use_alternate_hashcode() { return _seed != 0; } static juint seed() { return _seed; } @@ -292,7 +309,6 @@ static int literal_size(ConstantPool *cp) {Unimplemented(); return 0;} static int literal_size(Klass *k) {Unimplemented(); return 0;} -public: void dump_table(outputStream* st, const char *table_name); private: