Easy hashtable for HotSpot

Coleen Phillimore coleen.phillimore at oracle.com
Tue Jan 31 21:37:31 UTC 2017


There is also a ResourceHashTable, did you see that?   We don't need an 
*additional* hashtable, we just need a good one!
Coleen

On 1/31/17 3:01 PM, Ioi Lam wrote:
> I've always been frustrated by the HotSpot hashtable code. It looks 
> like every time you need to create a new table, you have to write a 
> whole bunch of boilerplate code like get() and add(). This is 
> especially bad if you just need a very simple mapping.
>
> So I've created an "Easy" hashtable, to reduce as much boilerplate 
> code as possible:
>
>
> template <class T, class Entry, MEMFLAGS F> class EasyHashtable
>    : public Hashtable<T, F>
> {
>   static unsigned int compute_hash(T key) {
>     return Entry::compute_hash(key);
>   }
>   int hash_to_index(unsigned int hash) {
>     return Hashtable<T, F>::hash_to_index(hash);
>   }
> public:
>   EasyHashtable(int table_size)
>     : Hashtable<T, F>(table_size, sizeof(Entry)) {}
>
>   // For iterating all the entries in the table
>   Entry* bucket(int index) {
>     return (Entry*)Hashtable<T, F>::bucket(index);
>   }
>
>   Entry* get(T literal) {
>     unsigned int hash = compute_hash(literal);
>     int index = hash_to_index(hash);
>     for (Entry* e = bucket(index); e != NULL; e = (Entry*)e->next()) {
>       if (e->literal() == literal) {
>         return e;
>       }
>     }
>     return NULL;
>   }
>
>   Entry* add(T literal) {
>     unsigned int hash = compute_hash(literal);
>     int index = hash_to_index(hash);
>     Entry* e = (Entry*)Hashtable<T, F>::new_entry(hash, literal);
>     Hashtable<T, F>::add_entry(index, e);
>     return e;
>   }
> };
>
>
> Here's an example (map Symbol* -> Klass*). You just need to provide 
> your own hash function.
>
>
> class SymToKlassEntry : public HashtableEntry<Symbol*, mtSymbol> {
>   Klass* _klass;
> public:
>   static unsigned int compute_hash(Symbol* sym) {
>     return (unsigned int) sym->identity_hash();
>   }
>   void init(Klass* k) {
>     _klass = k;
>   }
>   Klass* klass() {
>     return _klass;
>   }
> };
>
> void test() {
>     typedef EasyHashtable<Symbol*, SymToKlassEntry, mtSymbol> MyTable;
>     MyTable* table = new MyTable(1234);
>     Symbol* sym = SymbolTable::new_permanent_symbol("some symbol", 
> CHECK);
>     table->add(sym)->init((Klass*)0xbaadf00d);
>     Klass* klass = table->get(sym)->klass();
>
>     // Iterate all symbols
>     for (int i=0; i<table->table_size(); i++) {
>       for (SymToKlassEntry* entry = table->bucket(i);
>            entry;
>            entry = (SymToKlassEntry*)entry->next()) {
>         tty->print_cr("sym: %p => klass: %p", entry->literal(), 
> entry->klass());
>       }
>     }
>   }
> }
>
>
>
>
> Another common case would be to map an address to arbitrary data type. 
> (I needed this for fixing JDK-8072061)
>
>
> template <MEMFLAGS F> class AddressHashtableEntry
>   : public HashtableEntry<address, F> {
> public:
>   static unsigned int compute_hash(address obj) {
>     return (unsigned int)(uintptr_t(obj) >> BitsPerWord);
>   }
> };
>
> template <class Entry, MEMFLAGS F> class AddressHashtable
>   : public EasyHashtable<address, Entry, F> {
> public:
>   AddressHashtable(int table_size)
>     : EasyHashtable<address, Entry, F>(table_size) {}
>
>   Entry* get(address obj) {
>     assert(obj != NULL, "Caller should not pass in NULL");
>     return (Entry*)EasyHashtable<address, Entry, mtInternal>::get(obj);
>   }
>   Entry* add(address obj) {
>     assert(obj != NULL, "Caller should not pass in NULL");
>     return (Entry*)EasyHashtable<address, Entry, mtInternal>::add(obj);
>   }
> };
>
>
> Examples:
>
>
> class AddrToNumEntry :  public AddressHashtableEntry<mtInternal> {
>   int _val;
> public:
>   void init(int v) {
>     _val = v;
>   }
>   int val() {
>     return _val;
>   }
> };
>
> void test() {
>   // A table of known addresses
>   {
>     typedef AddressHashtableEntry<mtInternal> MyEntry;
>     typedef AddressHashtable<MyEntry, mtInternal> MyTable;
>     MyTable* table = new MyTable(1234);
>     table->add((address)0xdeadbeef);
>     tty->print_cr("exists? %d", (table->get((address)0xbaadf00d) != 
> NULL));
>     tty->print_cr("exists? %d", (table->get((address)0xdeadbeef) != 
> NULL));
>   }
>
>   // Map addresses to numbers
>   {
>     typedef AddressHashtable<AddrToNumEntry, mtInternal> MyTable;
>     MyTable* table = new MyTable(1234);
>     table->add((address)0xdeadbeef)->init(1);
>     table->add((address)0xbaadf00d)->init(2);
>     tty->print_cr("%d", table->get((address)0xdeadbeef)->val());
>   }
> }
>
>
> Any thoughts about this coding style?
>
> Thanks
> - Ioi
>
>



More information about the hotspot-dev mailing list