Fri, 29 Aug 2014 13:08:01 +0200
8056084: Refactor Hashtable to allow implementations without rehashing support
Reviewed-by: gziemski, jmasa, brutisso, coleenp, tschatzl
1.1 --- a/src/share/vm/classfile/symbolTable.cpp Tue Sep 23 17:24:34 2014 -0700 1.2 +++ b/src/share/vm/classfile/symbolTable.cpp Fri Aug 29 13:08:01 2014 +0200 1.3 @@ -205,7 +205,7 @@ 1.4 } 1.5 } 1.6 // If the bucket size is too deep check if this hash code is insufficient. 1.7 - if (count >= BasicHashtable<mtSymbol>::rehash_count && !needs_rehashing()) { 1.8 + if (count >= rehash_count && !needs_rehashing()) { 1.9 _needs_rehashing = check_rehash_table(count); 1.10 } 1.11 return NULL; 1.12 @@ -656,7 +656,7 @@ 1.13 } 1.14 } 1.15 // If the bucket size is too deep check if this hash code is insufficient. 1.16 - if (count >= BasicHashtable<mtSymbol>::rehash_count && !needs_rehashing()) { 1.17 + if (count >= rehash_count && !needs_rehashing()) { 1.18 _needs_rehashing = check_rehash_table(count); 1.19 } 1.20 return NULL;
2.1 --- a/src/share/vm/classfile/symbolTable.hpp Tue Sep 23 17:24:34 2014 -0700 2.2 +++ b/src/share/vm/classfile/symbolTable.hpp Fri Aug 29 13:08:01 2014 +0200 2.3 @@ -74,7 +74,7 @@ 2.4 operator Symbol*() { return _temp; } 2.5 }; 2.6 2.7 -class SymbolTable : public Hashtable<Symbol*, mtSymbol> { 2.8 +class SymbolTable : public RehashableHashtable<Symbol*, mtSymbol> { 2.9 friend class VMStructs; 2.10 friend class ClassFileParser; 2.11 2.12 @@ -110,10 +110,10 @@ 2.13 Symbol* lookup(int index, const char* name, int len, unsigned int hash); 2.14 2.15 SymbolTable() 2.16 - : Hashtable<Symbol*, mtSymbol>(SymbolTableSize, sizeof (HashtableEntry<Symbol*, mtSymbol>)) {} 2.17 + : RehashableHashtable<Symbol*, mtSymbol>(SymbolTableSize, sizeof (HashtableEntry<Symbol*, mtSymbol>)) {} 2.18 2.19 SymbolTable(HashtableBucket<mtSymbol>* t, int number_of_entries) 2.20 - : Hashtable<Symbol*, mtSymbol>(SymbolTableSize, sizeof (HashtableEntry<Symbol*, mtSymbol>), t, 2.21 + : RehashableHashtable<Symbol*, mtSymbol>(SymbolTableSize, sizeof (HashtableEntry<Symbol*, mtSymbol>), t, 2.22 number_of_entries) {} 2.23 2.24 // Arena for permanent symbols (null class loader) that are never unloaded 2.25 @@ -252,7 +252,7 @@ 2.26 static int parallel_claimed_index() { return _parallel_claimed_idx; } 2.27 }; 2.28 2.29 -class StringTable : public Hashtable<oop, mtSymbol> { 2.30 +class StringTable : public RehashableHashtable<oop, mtSymbol> { 2.31 friend class VMStructs; 2.32 2.33 private: 2.34 @@ -278,11 +278,11 @@ 2.35 // in the range [start_idx, end_idx). 2.36 static void buckets_unlink_or_oops_do(BoolObjectClosure* is_alive, OopClosure* f, int start_idx, int end_idx, int* processed, int* removed); 2.37 2.38 - StringTable() : Hashtable<oop, mtSymbol>((int)StringTableSize, 2.39 + StringTable() : RehashableHashtable<oop, mtSymbol>((int)StringTableSize, 2.40 sizeof (HashtableEntry<oop, mtSymbol>)) {} 2.41 2.42 StringTable(HashtableBucket<mtSymbol>* t, int number_of_entries) 2.43 - : Hashtable<oop, mtSymbol>((int)StringTableSize, sizeof (HashtableEntry<oop, mtSymbol>), t, 2.44 + : RehashableHashtable<oop, mtSymbol>((int)StringTableSize, sizeof (HashtableEntry<oop, mtSymbol>), t, 2.45 number_of_entries) {} 2.46 public: 2.47 // The string table
3.1 --- a/src/share/vm/utilities/hashtable.cpp Tue Sep 23 17:24:34 2014 -0700 3.2 +++ b/src/share/vm/utilities/hashtable.cpp Fri Aug 29 13:08:01 2014 +0200 3.3 @@ -36,21 +36,22 @@ 3.4 #include "utilities/numberSeq.hpp" 3.5 3.6 3.7 -// This is a generic hashtable, designed to be used for the symbol 3.8 -// and string tables. 3.9 -// 3.10 -// It is implemented as an open hash table with a fixed number of buckets. 3.11 -// 3.12 -// %note: 3.13 -// - HashtableEntrys are allocated in blocks to reduce the space overhead. 3.14 +// This hashtable is implemented as an open hash table with a fixed number of buckets. 3.15 3.16 -template <MEMFLAGS F> BasicHashtableEntry<F>* BasicHashtable<F>::new_entry(unsigned int hashValue) { 3.17 - BasicHashtableEntry<F>* entry; 3.18 - 3.19 - if (_free_list) { 3.20 +template <MEMFLAGS F> BasicHashtableEntry<F>* BasicHashtable<F>::new_entry_free_list() { 3.21 + BasicHashtableEntry<F>* entry = NULL; 3.22 + if (_free_list != NULL) { 3.23 entry = _free_list; 3.24 _free_list = _free_list->next(); 3.25 - } else { 3.26 + } 3.27 + return entry; 3.28 +} 3.29 + 3.30 +// HashtableEntrys are allocated in blocks to reduce the space overhead. 3.31 +template <MEMFLAGS F> BasicHashtableEntry<F>* BasicHashtable<F>::new_entry(unsigned int hashValue) { 3.32 + BasicHashtableEntry<F>* entry = new_entry_free_list(); 3.33 + 3.34 + if (entry == NULL) { 3.35 if (_first_free_entry + _entry_size >= _end_block) { 3.36 int block_size = MIN2(512, MAX2((int)_table_size / 2, (int)_number_of_entries)); 3.37 int len = _entry_size * block_size; 3.38 @@ -83,9 +84,9 @@ 3.39 // This is somewhat an arbitrary heuristic but if one bucket gets to 3.40 // rehash_count which is currently 100, there's probably something wrong. 3.41 3.42 -template <MEMFLAGS F> bool BasicHashtable<F>::check_rehash_table(int count) { 3.43 - assert(table_size() != 0, "underflow"); 3.44 - if (count > (((double)number_of_entries()/(double)table_size())*rehash_multiple)) { 3.45 +template <class T, MEMFLAGS F> bool RehashableHashtable<T, F>::check_rehash_table(int count) { 3.46 + assert(this->table_size() != 0, "underflow"); 3.47 + if (count > (((double)this->number_of_entries()/(double)this->table_size())*rehash_multiple)) { 3.48 // Set a flag for the next safepoint, which should be at some guaranteed 3.49 // safepoint interval. 3.50 return true; 3.51 @@ -93,13 +94,13 @@ 3.52 return false; 3.53 } 3.54 3.55 -template <class T, MEMFLAGS F> juint Hashtable<T, F>::_seed = 0; 3.56 +template <class T, MEMFLAGS F> juint RehashableHashtable<T, F>::_seed = 0; 3.57 3.58 // Create a new table and using alternate hash code, populate the new table 3.59 // with the existing elements. This can be used to change the hash code 3.60 // and could in the future change the size of the table. 3.61 3.62 -template <class T, MEMFLAGS F> void Hashtable<T, F>::move_to(Hashtable<T, F>* new_table) { 3.63 +template <class T, MEMFLAGS F> void RehashableHashtable<T, F>::move_to(RehashableHashtable<T, F>* new_table) { 3.64 3.65 // Initialize the global seed for hashing. 3.66 _seed = AltHashing::compute_seed(); 3.67 @@ -109,7 +110,7 @@ 3.68 3.69 // Iterate through the table and create a new entry for the new table 3.70 for (int i = 0; i < new_table->table_size(); ++i) { 3.71 - for (HashtableEntry<T, F>* p = bucket(i); p != NULL; ) { 3.72 + for (HashtableEntry<T, F>* p = this->bucket(i); p != NULL; ) { 3.73 HashtableEntry<T, F>* next = p->next(); 3.74 T string = p->literal(); 3.75 // Use alternate hashing algorithm on the symbol in the first table 3.76 @@ -238,11 +239,11 @@ 3.77 } 3.78 } 3.79 3.80 -template <class T, MEMFLAGS F> int Hashtable<T, F>::literal_size(Symbol *symbol) { 3.81 +template <class T, MEMFLAGS F> int RehashableHashtable<T, F>::literal_size(Symbol *symbol) { 3.82 return symbol->size() * HeapWordSize; 3.83 } 3.84 3.85 -template <class T, MEMFLAGS F> int Hashtable<T, F>::literal_size(oop oop) { 3.86 +template <class T, MEMFLAGS F> int RehashableHashtable<T, F>::literal_size(oop oop) { 3.87 // NOTE: this would over-count if (pre-JDK8) java_lang_Class::has_offset_field() is true, 3.88 // and the String.value array is shared by several Strings. However, starting from JDK8, 3.89 // the String.value array is not shared anymore. 3.90 @@ -255,12 +256,12 @@ 3.91 // Note: if you create a new subclass of Hashtable<MyNewType, F>, you will need to 3.92 // add a new function Hashtable<T, F>::literal_size(MyNewType lit) 3.93 3.94 -template <class T, MEMFLAGS F> void Hashtable<T, F>::dump_table(outputStream* st, const char *table_name) { 3.95 +template <class T, MEMFLAGS F> void RehashableHashtable<T, F>::dump_table(outputStream* st, const char *table_name) { 3.96 NumberSeq summary; 3.97 int literal_bytes = 0; 3.98 for (int i = 0; i < this->table_size(); ++i) { 3.99 int count = 0; 3.100 - for (HashtableEntry<T, F>* e = bucket(i); 3.101 + for (HashtableEntry<T, F>* e = this->bucket(i); 3.102 e != NULL; e = e->next()) { 3.103 count++; 3.104 literal_bytes += literal_size(e->literal()); 3.105 @@ -270,7 +271,7 @@ 3.106 double num_buckets = summary.num(); 3.107 double num_entries = summary.sum(); 3.108 3.109 - int bucket_bytes = (int)num_buckets * sizeof(bucket(0)); 3.110 + int bucket_bytes = (int)num_buckets * sizeof(HashtableBucket<F>); 3.111 int entry_bytes = (int)num_entries * sizeof(HashtableEntry<T, F>); 3.112 int total_bytes = literal_bytes + bucket_bytes + entry_bytes; 3.113 3.114 @@ -353,11 +354,14 @@ 3.115 #endif 3.116 // Explicitly instantiate these types 3.117 template class Hashtable<ConstantPool*, mtClass>; 3.118 +template class RehashableHashtable<Symbol*, mtSymbol>; 3.119 +template class RehashableHashtable<oopDesc*, mtSymbol>; 3.120 template class Hashtable<Symbol*, mtSymbol>; 3.121 template class Hashtable<Klass*, mtClass>; 3.122 template class Hashtable<oop, mtClass>; 3.123 #if defined(SOLARIS) || defined(CHECK_UNHANDLED_OOPS) 3.124 template class Hashtable<oop, mtSymbol>; 3.125 +template class RehashableHashtable<oop, mtSymbol>; 3.126 #endif // SOLARIS || CHECK_UNHANDLED_OOPS 3.127 template class Hashtable<oopDesc*, mtSymbol>; 3.128 template class Hashtable<Symbol*, mtClass>;
4.1 --- a/src/share/vm/utilities/hashtable.hpp Tue Sep 23 17:24:34 2014 -0700 4.2 +++ b/src/share/vm/utilities/hashtable.hpp Fri Aug 29 13:08:01 2014 +0200 4.3 @@ -178,11 +178,6 @@ 4.4 void verify_lookup_length(double load); 4.5 #endif 4.6 4.7 - enum { 4.8 - rehash_count = 100, 4.9 - rehash_multiple = 60 4.10 - }; 4.11 - 4.12 void initialize(int table_size, int entry_size, int number_of_entries); 4.13 4.14 // Accessor 4.15 @@ -194,12 +189,12 @@ 4.16 // The following method is not MT-safe and must be done under lock. 4.17 BasicHashtableEntry<F>** bucket_addr(int i) { return _buckets[i].entry_addr(); } 4.18 4.19 + // Attempt to get an entry from the free list 4.20 + BasicHashtableEntry<F>* new_entry_free_list(); 4.21 + 4.22 // Table entry management 4.23 BasicHashtableEntry<F>* new_entry(unsigned int hashValue); 4.24 4.25 - // Check that the table is unbalanced 4.26 - bool check_rehash_table(int count); 4.27 - 4.28 // Used when moving the entry to another table 4.29 // Clean up links, but do not add to free_list 4.30 void unlink_entry(BasicHashtableEntry<F>* entry) { 4.31 @@ -277,8 +272,30 @@ 4.32 return (HashtableEntry<T, F>**)BasicHashtable<F>::bucket_addr(i); 4.33 } 4.34 4.35 +}; 4.36 + 4.37 +template <class T, MEMFLAGS F> class RehashableHashtable : public Hashtable<T, F> { 4.38 + protected: 4.39 + 4.40 + enum { 4.41 + rehash_count = 100, 4.42 + rehash_multiple = 60 4.43 + }; 4.44 + 4.45 + // Check that the table is unbalanced 4.46 + bool check_rehash_table(int count); 4.47 + 4.48 + public: 4.49 + RehashableHashtable(int table_size, int entry_size) 4.50 + : Hashtable<T, F>(table_size, entry_size) { } 4.51 + 4.52 + RehashableHashtable(int table_size, int entry_size, 4.53 + HashtableBucket<F>* buckets, int number_of_entries) 4.54 + : Hashtable<T, F>(table_size, entry_size, buckets, number_of_entries) { } 4.55 + 4.56 + 4.57 // Function to move these elements into the new table. 4.58 - void move_to(Hashtable<T, F>* new_table); 4.59 + void move_to(RehashableHashtable<T, F>* new_table); 4.60 static bool use_alternate_hashcode() { return _seed != 0; } 4.61 static juint seed() { return _seed; } 4.62 4.63 @@ -292,7 +309,6 @@ 4.64 static int literal_size(ConstantPool *cp) {Unimplemented(); return 0;} 4.65 static int literal_size(Klass *k) {Unimplemented(); return 0;} 4.66 4.67 -public: 4.68 void dump_table(outputStream* st, const char *table_name); 4.69 4.70 private: