8056084: Refactor Hashtable to allow implementations without rehashing support

Fri, 29 Aug 2014 13:08:01 +0200

author
mgerdin
date
Fri, 29 Aug 2014 13:08:01 +0200
changeset 7207
152cf4afc11f
parent 7206
50d3433155d9
child 7208
7baf47cb97cb

8056084: Refactor Hashtable to allow implementations without rehashing support
Reviewed-by: gziemski, jmasa, brutisso, coleenp, tschatzl

src/share/vm/classfile/symbolTable.cpp file | annotate | diff | comparison | revisions
src/share/vm/classfile/symbolTable.hpp file | annotate | diff | comparison | revisions
src/share/vm/utilities/hashtable.cpp file | annotate | diff | comparison | revisions
src/share/vm/utilities/hashtable.hpp file | annotate | diff | comparison | revisions
     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:

mercurial