Easy hashtable for HotSpot

Ioi Lam ioi.lam at oracle.com
Tue Jan 31 20:01:29 UTC 2017


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