Easy hashtable for HotSpot

Ioi Lam ioi.lam at oracle.com
Tue Jan 31 22:46:10 UTC 2017


Oh, I didn't know about ResourceHashtable. It looks much better than the 
old Hashtable. Perhaps we should just convert all the old Hashtable code 
to ResourceHashtable?

On 1/31/17 1:37 PM, Coleen Phillimore wrote:
>
> 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