changeset 20493:152cf4afc11f

8056084: Refactor Hashtable to allow implementations without rehashing support Reviewed-by: gziemski, jmasa, brutisso, coleenp, tschatzl
author mgerdin
date Fri, 29 Aug 2014 13:08:01 +0200
parents 50d3433155d9
children 7baf47cb97cb
files src/share/vm/classfile/symbolTable.cpp src/share/vm/classfile/symbolTable.hpp src/share/vm/utilities/hashtable.cpp src/share/vm/utilities/hashtable.hpp
diffstat 4 files changed, 61 insertions(+), 41 deletions(-) [+]
line wrap: on
line diff
--- 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<mtSymbol>::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<mtSymbol>::rehash_count && !needs_rehashing()) {
+  if (count >= rehash_count && !needs_rehashing()) {
     _needs_rehashing = check_rehash_table(count);
   }
   return NULL;
--- 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<Symbol*, mtSymbol> {
+class SymbolTable : public RehashableHashtable<Symbol*, mtSymbol> {
   friend class VMStructs;
   friend class ClassFileParser;
 
@@ -110,10 +110,10 @@
   Symbol* lookup(int index, const char* name, int len, unsigned int hash);
 
   SymbolTable()
-    : Hashtable<Symbol*, mtSymbol>(SymbolTableSize, sizeof (HashtableEntry<Symbol*, mtSymbol>)) {}
+    : RehashableHashtable<Symbol*, mtSymbol>(SymbolTableSize, sizeof (HashtableEntry<Symbol*, mtSymbol>)) {}
 
   SymbolTable(HashtableBucket<mtSymbol>* t, int number_of_entries)
-    : Hashtable<Symbol*, mtSymbol>(SymbolTableSize, sizeof (HashtableEntry<Symbol*, mtSymbol>), t,
+    : RehashableHashtable<Symbol*, mtSymbol>(SymbolTableSize, sizeof (HashtableEntry<Symbol*, mtSymbol>), 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<oop, mtSymbol> {
+class StringTable : public RehashableHashtable<oop, mtSymbol> {
   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<oop, mtSymbol>((int)StringTableSize,
+  StringTable() : RehashableHashtable<oop, mtSymbol>((int)StringTableSize,
                               sizeof (HashtableEntry<oop, mtSymbol>)) {}
 
   StringTable(HashtableBucket<mtSymbol>* t, int number_of_entries)
-    : Hashtable<oop, mtSymbol>((int)StringTableSize, sizeof (HashtableEntry<oop, mtSymbol>), t,
+    : RehashableHashtable<oop, mtSymbol>((int)StringTableSize, sizeof (HashtableEntry<oop, mtSymbol>), t,
                      number_of_entries) {}
 public:
   // The string table
--- 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 <MEMFLAGS F> BasicHashtableEntry<F>* BasicHashtable<F>::new_entry(unsigned int hashValue) {
-  BasicHashtableEntry<F>* entry;
-
-  if (_free_list) {
+template <MEMFLAGS F> BasicHashtableEntry<F>* BasicHashtable<F>::new_entry_free_list() {
+  BasicHashtableEntry<F>* 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 <MEMFLAGS F> BasicHashtableEntry<F>* BasicHashtable<F>::new_entry(unsigned int hashValue) {
+  BasicHashtableEntry<F>* 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 <MEMFLAGS F> bool BasicHashtable<F>::check_rehash_table(int count) {
-  assert(table_size() != 0, "underflow");
-  if (count > (((double)number_of_entries()/(double)table_size())*rehash_multiple)) {
+template <class T, MEMFLAGS F> bool RehashableHashtable<T, F>::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 <class T, MEMFLAGS F> juint Hashtable<T, F>::_seed = 0;
+template <class T, MEMFLAGS F> juint RehashableHashtable<T, F>::_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 <class T, MEMFLAGS F> void Hashtable<T, F>::move_to(Hashtable<T, F>* new_table) {
+template <class T, MEMFLAGS F> void RehashableHashtable<T, F>::move_to(RehashableHashtable<T, F>* 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<T, F>* p = bucket(i); p != NULL; ) {
+    for (HashtableEntry<T, F>* p = this->bucket(i); p != NULL; ) {
       HashtableEntry<T, F>* next = p->next();
       T string = p->literal();
       // Use alternate hashing algorithm on the symbol in the first table
@@ -238,11 +239,11 @@
   }
 }
 
-template <class T, MEMFLAGS F> int Hashtable<T, F>::literal_size(Symbol *symbol) {
+template <class T, MEMFLAGS F> int RehashableHashtable<T, F>::literal_size(Symbol *symbol) {
   return symbol->size() * HeapWordSize;
 }
 
-template <class T, MEMFLAGS F> int Hashtable<T, F>::literal_size(oop oop) {
+template <class T, MEMFLAGS F> int RehashableHashtable<T, F>::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<MyNewType, F>, you will need to
 // add a new function Hashtable<T, F>::literal_size(MyNewType lit)
 
-template <class T, MEMFLAGS F> void Hashtable<T, F>::dump_table(outputStream* st, const char *table_name) {
+template <class T, MEMFLAGS F> void RehashableHashtable<T, F>::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<T, F>* e = bucket(i);
+    for (HashtableEntry<T, F>* 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<F>);
   int entry_bytes  = (int)num_entries * sizeof(HashtableEntry<T, F>);
   int total_bytes = literal_bytes +  bucket_bytes + entry_bytes;
 
@@ -353,11 +354,14 @@
 #endif
 // Explicitly instantiate these types
 template class Hashtable<ConstantPool*, mtClass>;
+template class RehashableHashtable<Symbol*, mtSymbol>;
+template class RehashableHashtable<oopDesc*, mtSymbol>;
 template class Hashtable<Symbol*, mtSymbol>;
 template class Hashtable<Klass*, mtClass>;
 template class Hashtable<oop, mtClass>;
 #if defined(SOLARIS) || defined(CHECK_UNHANDLED_OOPS)
 template class Hashtable<oop, mtSymbol>;
+template class RehashableHashtable<oop, mtSymbol>;
 #endif // SOLARIS || CHECK_UNHANDLED_OOPS
 template class Hashtable<oopDesc*, mtSymbol>;
 template class Hashtable<Symbol*, mtClass>;
--- 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<F>** bucket_addr(int i) { return _buckets[i].entry_addr(); }
 
+  // Attempt to get an entry from the free list
+  BasicHashtableEntry<F>* new_entry_free_list();
+
   // Table entry management
   BasicHashtableEntry<F>* 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<F>* entry) {
@@ -277,8 +272,30 @@
     return (HashtableEntry<T, F>**)BasicHashtable<F>::bucket_addr(i);
   }
 
+};
+
+template <class T, MEMFLAGS F> class RehashableHashtable : public Hashtable<T, F> {
+ 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<T, F>(table_size, entry_size) { }
+
+  RehashableHashtable(int table_size, int entry_size,
+                   HashtableBucket<F>* buckets, int number_of_entries)
+    : Hashtable<T, F>(table_size, entry_size, buckets, number_of_entries) { }
+
+
   // Function to move these elements into the new table.
-  void move_to(Hashtable<T, F>* new_table);
+  void move_to(RehashableHashtable<T, F>* 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: