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