提交 671d00ce 编写于 作者: M mgerdin

8056084: Refactor Hashtable to allow implementations without rehashing support

Reviewed-by: gziemski, jmasa, brutisso, coleenp, tschatzl
上级 8dd4a007
...@@ -205,7 +205,7 @@ Symbol* SymbolTable::lookup(int index, const char* name, ...@@ -205,7 +205,7 @@ Symbol* SymbolTable::lookup(int index, const char* name,
} }
} }
// If the bucket size is too deep check if this hash code is insufficient. // 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); _needs_rehashing = check_rehash_table(count);
} }
return NULL; return NULL;
...@@ -656,7 +656,7 @@ oop StringTable::lookup(int index, jchar* name, ...@@ -656,7 +656,7 @@ oop StringTable::lookup(int index, jchar* name,
} }
} }
// If the bucket size is too deep check if this hash code is insufficient. // 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); _needs_rehashing = check_rehash_table(count);
} }
return NULL; return NULL;
......
...@@ -74,7 +74,7 @@ class TempNewSymbol : public StackObj { ...@@ -74,7 +74,7 @@ class TempNewSymbol : public StackObj {
operator Symbol*() { return _temp; } operator Symbol*() { return _temp; }
}; };
class SymbolTable : public Hashtable<Symbol*, mtSymbol> { class SymbolTable : public RehashableHashtable<Symbol*, mtSymbol> {
friend class VMStructs; friend class VMStructs;
friend class ClassFileParser; friend class ClassFileParser;
...@@ -110,10 +110,10 @@ private: ...@@ -110,10 +110,10 @@ private:
Symbol* lookup(int index, const char* name, int len, unsigned int hash); Symbol* lookup(int index, const char* name, int len, unsigned int hash);
SymbolTable() 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) 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) {} number_of_entries) {}
// Arena for permanent symbols (null class loader) that are never unloaded // Arena for permanent symbols (null class loader) that are never unloaded
...@@ -252,7 +252,7 @@ public: ...@@ -252,7 +252,7 @@ public:
static int parallel_claimed_index() { return _parallel_claimed_idx; } static int parallel_claimed_index() { return _parallel_claimed_idx; }
}; };
class StringTable : public Hashtable<oop, mtSymbol> { class StringTable : public RehashableHashtable<oop, mtSymbol> {
friend class VMStructs; friend class VMStructs;
private: private:
...@@ -278,11 +278,11 @@ private: ...@@ -278,11 +278,11 @@ private:
// in the range [start_idx, end_idx). // 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); 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>)) {} sizeof (HashtableEntry<oop, mtSymbol>)) {}
StringTable(HashtableBucket<mtSymbol>* t, int number_of_entries) 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) {} number_of_entries) {}
public: public:
// The string table // The string table
......
...@@ -36,21 +36,22 @@ ...@@ -36,21 +36,22 @@
#include "utilities/numberSeq.hpp" #include "utilities/numberSeq.hpp"
// This is a generic hashtable, designed to be used for the symbol // This hashtable is implemented as an open hash table with a fixed number of buckets.
// 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.
template <MEMFLAGS F> BasicHashtableEntry<F>* BasicHashtable<F>::new_entry(unsigned int hashValue) { template <MEMFLAGS F> BasicHashtableEntry<F>* BasicHashtable<F>::new_entry_free_list() {
BasicHashtableEntry<F>* entry; BasicHashtableEntry<F>* entry = NULL;
if (_free_list != NULL) {
if (_free_list) {
entry = _free_list; entry = _free_list;
_free_list = _free_list->next(); _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) { if (_first_free_entry + _entry_size >= _end_block) {
int block_size = MIN2(512, MAX2((int)_table_size / 2, (int)_number_of_entries)); int block_size = MIN2(512, MAX2((int)_table_size / 2, (int)_number_of_entries));
int len = _entry_size * block_size; int len = _entry_size * block_size;
...@@ -83,9 +84,9 @@ template <class T, MEMFLAGS F> HashtableEntry<T, F>* Hashtable<T, F>::new_entry( ...@@ -83,9 +84,9 @@ template <class T, MEMFLAGS F> HashtableEntry<T, F>* Hashtable<T, F>::new_entry(
// This is somewhat an arbitrary heuristic but if one bucket gets to // This is somewhat an arbitrary heuristic but if one bucket gets to
// rehash_count which is currently 100, there's probably something wrong. // rehash_count which is currently 100, there's probably something wrong.
template <MEMFLAGS F> bool BasicHashtable<F>::check_rehash_table(int count) { template <class T, MEMFLAGS F> bool RehashableHashtable<T, F>::check_rehash_table(int count) {
assert(table_size() != 0, "underflow"); assert(this->table_size() != 0, "underflow");
if (count > (((double)number_of_entries()/(double)table_size())*rehash_multiple)) { 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 // Set a flag for the next safepoint, which should be at some guaranteed
// safepoint interval. // safepoint interval.
return true; return true;
...@@ -93,13 +94,13 @@ template <MEMFLAGS F> bool BasicHashtable<F>::check_rehash_table(int count) { ...@@ -93,13 +94,13 @@ template <MEMFLAGS F> bool BasicHashtable<F>::check_rehash_table(int count) {
return false; 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 // 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 // with the existing elements. This can be used to change the hash code
// and could in the future change the size of the table. // 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. // Initialize the global seed for hashing.
_seed = AltHashing::compute_seed(); _seed = AltHashing::compute_seed();
...@@ -109,7 +110,7 @@ template <class T, MEMFLAGS F> void Hashtable<T, F>::move_to(Hashtable<T, F>* ne ...@@ -109,7 +110,7 @@ template <class T, MEMFLAGS F> void Hashtable<T, F>::move_to(Hashtable<T, F>* ne
// Iterate through the table and create a new entry for the new table // Iterate through the table and create a new entry for the new table
for (int i = 0; i < new_table->table_size(); ++i) { 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(); HashtableEntry<T, F>* next = p->next();
T string = p->literal(); T string = p->literal();
// Use alternate hashing algorithm on the symbol in the first table // Use alternate hashing algorithm on the symbol in the first table
...@@ -238,11 +239,11 @@ template <class T, MEMFLAGS F> void Hashtable<T, F>::reverse(void* boundary) { ...@@ -238,11 +239,11 @@ template <class T, MEMFLAGS F> void Hashtable<T, F>::reverse(void* boundary) {
} }
} }
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; 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, // 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, // and the String.value array is shared by several Strings. However, starting from JDK8,
// the String.value array is not shared anymore. // the String.value array is not shared anymore.
...@@ -255,12 +256,12 @@ template <class T, MEMFLAGS F> int Hashtable<T, F>::literal_size(oop oop) { ...@@ -255,12 +256,12 @@ template <class T, MEMFLAGS F> int Hashtable<T, F>::literal_size(oop oop) {
// Note: if you create a new subclass of Hashtable<MyNewType, F>, you will need to // 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) // 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; NumberSeq summary;
int literal_bytes = 0; int literal_bytes = 0;
for (int i = 0; i < this->table_size(); ++i) { for (int i = 0; i < this->table_size(); ++i) {
int count = 0; int count = 0;
for (HashtableEntry<T, F>* e = bucket(i); for (HashtableEntry<T, F>* e = this->bucket(i);
e != NULL; e = e->next()) { e != NULL; e = e->next()) {
count++; count++;
literal_bytes += literal_size(e->literal()); literal_bytes += literal_size(e->literal());
...@@ -270,7 +271,7 @@ template <class T, MEMFLAGS F> void Hashtable<T, F>::dump_table(outputStream* st ...@@ -270,7 +271,7 @@ template <class T, MEMFLAGS F> void Hashtable<T, F>::dump_table(outputStream* st
double num_buckets = summary.num(); double num_buckets = summary.num();
double num_entries = summary.sum(); 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 entry_bytes = (int)num_entries * sizeof(HashtableEntry<T, F>);
int total_bytes = literal_bytes + bucket_bytes + entry_bytes; int total_bytes = literal_bytes + bucket_bytes + entry_bytes;
...@@ -353,11 +354,14 @@ template <MEMFLAGS F> void BasicHashtable<F>::verify_lookup_length(double load) ...@@ -353,11 +354,14 @@ template <MEMFLAGS F> void BasicHashtable<F>::verify_lookup_length(double load)
#endif #endif
// Explicitly instantiate these types // Explicitly instantiate these types
template class Hashtable<ConstantPool*, mtClass>; template class Hashtable<ConstantPool*, mtClass>;
template class RehashableHashtable<Symbol*, mtSymbol>;
template class RehashableHashtable<oopDesc*, mtSymbol>;
template class Hashtable<Symbol*, mtSymbol>; template class Hashtable<Symbol*, mtSymbol>;
template class Hashtable<Klass*, mtClass>; template class Hashtable<Klass*, mtClass>;
template class Hashtable<oop, mtClass>; template class Hashtable<oop, mtClass>;
#if defined(SOLARIS) || defined(CHECK_UNHANDLED_OOPS) #if defined(SOLARIS) || defined(CHECK_UNHANDLED_OOPS)
template class Hashtable<oop, mtSymbol>; template class Hashtable<oop, mtSymbol>;
template class RehashableHashtable<oop, mtSymbol>;
#endif // SOLARIS || CHECK_UNHANDLED_OOPS #endif // SOLARIS || CHECK_UNHANDLED_OOPS
template class Hashtable<oopDesc*, mtSymbol>; template class Hashtable<oopDesc*, mtSymbol>;
template class Hashtable<Symbol*, mtClass>; template class Hashtable<Symbol*, mtClass>;
......
...@@ -178,11 +178,6 @@ protected: ...@@ -178,11 +178,6 @@ protected:
void verify_lookup_length(double load); void verify_lookup_length(double load);
#endif #endif
enum {
rehash_count = 100,
rehash_multiple = 60
};
void initialize(int table_size, int entry_size, int number_of_entries); void initialize(int table_size, int entry_size, int number_of_entries);
// Accessor // Accessor
...@@ -194,12 +189,12 @@ protected: ...@@ -194,12 +189,12 @@ protected:
// The following method is not MT-safe and must be done under lock. // The following method is not MT-safe and must be done under lock.
BasicHashtableEntry<F>** bucket_addr(int i) { return _buckets[i].entry_addr(); } 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 // Table entry management
BasicHashtableEntry<F>* new_entry(unsigned int hashValue); 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 // Used when moving the entry to another table
// Clean up links, but do not add to free_list // Clean up links, but do not add to free_list
void unlink_entry(BasicHashtableEntry<F>* entry) { void unlink_entry(BasicHashtableEntry<F>* entry) {
...@@ -277,8 +272,30 @@ protected: ...@@ -277,8 +272,30 @@ protected:
return (HashtableEntry<T, F>**)BasicHashtable<F>::bucket_addr(i); 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. // 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 bool use_alternate_hashcode() { return _seed != 0; }
static juint seed() { return _seed; } static juint seed() { return _seed; }
...@@ -292,7 +309,6 @@ protected: ...@@ -292,7 +309,6 @@ protected:
static int literal_size(ConstantPool *cp) {Unimplemented(); return 0;} static int literal_size(ConstantPool *cp) {Unimplemented(); return 0;}
static int literal_size(Klass *k) {Unimplemented(); return 0;} static int literal_size(Klass *k) {Unimplemented(); return 0;}
public:
void dump_table(outputStream* st, const char *table_name); void dump_table(outputStream* st, const char *table_name);
private: private:
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册