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