bool SimpleCompactHashtable::exists(u4 value) { assert(!DumpSharedSpaces, "run-time only"); if (_entry_count == 0) { return false; } unsigned int hash = (unsigned int)value; int index = hash % _bucket_count; u4 bucket_info = _buckets[index]; u4 bucket_offset = BUCKET_OFFSET(bucket_info); int bucket_type = BUCKET_TYPE(bucket_info); u4* entry = _entries + bucket_offset; if (bucket_type == VALUE_ONLY_BUCKET_TYPE) { return (entry[0] == value); } else { u4*entry_max = _entries + BUCKET_OFFSET(_buckets[index + 1]); while (entry <entry_max) { if (entry[1] == value) { return true; } entry += 2; } return false; } }
// Write the compact table's entries juint* CompactHashtableWriter::dump_buckets(juint* compact_table, juint* p, NumberSeq* summary) { uintx base_address = 0; uintx max_delta = 0; int num_compact_buckets = 0; if (_type == CompactHashtable<Symbol*, char>::_symbol_table) { base_address = uintx(MetaspaceShared::shared_rs()->base()); max_delta = uintx(MetaspaceShared::shared_rs()->size()); assert(max_delta <= 0x7fffffff, "range check"); } else { assert((_type == CompactHashtable<oop, char>::_string_table), "unknown table"); assert(UseCompressedOops, "UseCompressedOops is required"); } assert(p != NULL, "sanity"); for (int index = 0; index < _num_buckets; index++) { juint count = 0; int bucket_size = _bucket_sizes[index]; int bucket_type = BUCKET_TYPE(compact_table[index]); if (bucket_size == 1) { assert(bucket_type == COMPACT_BUCKET_TYPE, "Bad bucket type"); num_compact_buckets ++; } for (Entry* tent = _buckets[index]; tent; tent = tent->next()) { if (bucket_type == REGULAR_BUCKET_TYPE) { *p++ = juint(tent->hash()); // write entry hash } if (_type == CompactHashtable<Symbol*, char>::_symbol_table) { uintx deltax = uintx(tent->value()) - base_address; assert(deltax < max_delta, "range check"); juint delta = juint(deltax); *p++ = delta; // write entry offset } else { *p++ = oopDesc::encode_heap_oop(tent->string()); } count ++; } assert(count == _bucket_sizes[index], "sanity"); } // Adjust the hashentry_bytes in CompactHashtableStats. Each compact // bucket saves 4-byte. _stats->hashentry_bytes -= num_compact_buckets * 4; return p; }
inline void SimpleCompactHashtable::iterate(const I& iterator) { assert(!DumpSharedSpaces, "run-time only"); for (u4 i = 0; i < _bucket_count; i++) { u4 bucket_info = _buckets[i]; u4 bucket_offset = BUCKET_OFFSET(bucket_info); int bucket_type = BUCKET_TYPE(bucket_info); u4* entry = _entries + bucket_offset; if (bucket_type == VALUE_ONLY_BUCKET_TYPE) { iterator.do_value(_base_address, entry[0]); } else { u4*entry_max = _entries + BUCKET_OFFSET(_buckets[i + 1]); while (entry < entry_max) { iterator.do_value(_base_address, entry[1]); entry += 2; } } } }
template <class T, class N> void CompactHashtable<T, N>::symbols_do(SymbolClosure *cl) { assert(!DumpSharedSpaces, "run-time only"); for (juint i = 0; i < _bucket_count; i ++) { juint bucket_info = _buckets[i]; juint bucket_offset = BUCKET_OFFSET(bucket_info); int bucket_type = BUCKET_TYPE(bucket_info); juint* bucket = _buckets + bucket_offset; juint* bucket_end = _buckets; Symbol* sym; if (bucket_type == COMPACT_BUCKET_TYPE) { sym = (Symbol*)((void*)(_base_address + bucket[0])); cl->do_symbol(&sym); } else { bucket_end += BUCKET_OFFSET(_buckets[i + 1]); while (bucket < bucket_end) { sym = (Symbol*)((void*)(_base_address + bucket[1])); cl->do_symbol(&sym); bucket += 2; } } } }
// Write the compact table's entries juint* CompactHashtableWriter::dump_buckets(juint* compact_table, juint* p, NumberSeq* summary) { uintx base_address = uintx(MetaspaceShared::shared_rs()->base()); uintx max_delta = uintx(MetaspaceShared::shared_rs()->size()); assert(max_delta <= 0x7fffffff, "range check"); int num_compact_buckets = 0; assert(p != NULL, "sanity"); for (int index = 0; index < _num_buckets; index++) { juint count = 0; int bucket_size = _bucket_sizes[index]; int bucket_type = BUCKET_TYPE(compact_table[index]); if (bucket_size == 1) { assert(bucket_type == COMPACT_BUCKET_TYPE, "Bad bucket type"); num_compact_buckets ++; } for (Entry* tent = _buckets[index]; tent; tent = tent->next()) { if (bucket_type == REGULAR_BUCKET_TYPE) { *p++ = juint(tent->hash()); // write symbol hash } uintx deltax = uintx(tent->value()) - base_address; assert(deltax < max_delta, "range check"); juint delta = juint(deltax); *p++ = delta; // write symbol offset count ++; } assert(count == _bucket_sizes[index], "sanity"); } // Adjust the hashentry_bytes in CompactHashtableStats. Each compact // bucket saves 4-byte. _stats->hashentry_bytes -= num_compact_buckets * 4; return p; }
template <class T, class N> void CompactHashtable<T, N>::oops_do(OopClosure* f) { assert(!DumpSharedSpaces, "run-time only"); assert(_type == _string_table || _bucket_count == 0, "sanity"); for (juint i = 0; i < _bucket_count; i ++) { juint bucket_info = _buckets[i]; juint bucket_offset = BUCKET_OFFSET(bucket_info); int bucket_type = BUCKET_TYPE(bucket_info); juint* bucket = _buckets + bucket_offset; juint* bucket_end = _buckets; narrowOop o; if (bucket_type == COMPACT_BUCKET_TYPE) { o = (narrowOop)bucket[0]; f->do_oop(&o); } else { bucket_end += BUCKET_OFFSET(_buckets[i + 1]); while (bucket < bucket_end) { o = (narrowOop)bucket[1]; f->do_oop(&o); bucket += 2; } } } }