Path: blob/aarch64-shenandoah-jdk8u272-b10/hotspot/src/share/vm/jfr/utilities/jfrHashtable.hpp
38920 views
/*1* Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*22*/2324#ifndef SHARE_VM_JFR_UTILITIES_JFRHASHTABLE_HPP25#define SHARE_VM_JFR_UTILITIES_JFRHASHTABLE_HPP2627#include "memory/allocation.inline.hpp"28#include "runtime/orderAccess.hpp"29#include "utilities/debug.hpp"30#include "utilities/macros.hpp"3132template <typename T>33class JfrBasicHashtableEntry {34private:35typedef JfrBasicHashtableEntry<T> Entry;36Entry* _next;37T _literal; // ref to item in table.38uintptr_t _hash;3940public:41uintptr_t hash() const { return _hash; }42void set_hash(uintptr_t hash) { _hash = hash; }43T literal() const { return _literal; }44T* literal_addr() { return &_literal; }45void set_literal(T s) { _literal = s; }46void set_next(Entry* next) { _next = next; }47Entry* next() const { return _next; }48Entry** next_addr() { return &_next; }49};5051template <typename T>52class JfrHashtableBucket : public CHeapObj<mtTracing> {53template <typename>54friend class JfrBasicHashtable;55private:56typedef JfrBasicHashtableEntry<T> TableEntry;57TableEntry* _entry;5859TableEntry* get_entry() const {60return (TableEntry*)OrderAccess::load_ptr_acquire(&_entry);61}62void set_entry(TableEntry* entry) { OrderAccess::release_store_ptr(&_entry, entry);}63TableEntry** entry_addr() { return &_entry; }64};6566template <typename T>67class JfrBasicHashtable : public CHeapObj<mtTracing> {68private:69typedef JfrHashtableBucket<T> Bucket;70typedef JfrBasicHashtableEntry<T> TableEntry;71Bucket* _buckets;72uintptr_t _table_size;73const size_t _entry_size;74size_t _number_of_entries;7576protected:77JfrBasicHashtable(uintptr_t table_size, size_t entry_size) :78_buckets(NULL), _table_size(table_size), _entry_size(entry_size), _number_of_entries(0) {79_buckets = NEW_C_HEAP_ARRAY2(Bucket, table_size, mtTracing, CURRENT_PC);80memset((void*)_buckets, 0, table_size * sizeof(Bucket));81}8283size_t hash_to_index(uintptr_t full_hash) const {84const uintptr_t h = full_hash % _table_size;85assert(h >= 0 && h < _table_size, "Illegal hash value");86return (size_t)h;87}88size_t entry_size() const { return _entry_size; }89void unlink_entry(TableEntry* entry) {90entry->set_next(NULL);91--_number_of_entries;92}93void free_buckets() {94if (NULL != _buckets) {95FREE_C_HEAP_ARRAY(Bucket, _buckets, mtTracing);96_buckets = NULL;97}98}99TableEntry* bucket(size_t i) { return _buckets[i].get_entry();}100TableEntry** bucket_addr(size_t i) { return _buckets[i].entry_addr(); }101uintptr_t table_size() const { return _table_size; }102size_t number_of_entries() const { return _number_of_entries; }103void add_entry(size_t index, TableEntry* entry) {104assert(entry != NULL, "invariant");105entry->set_next(bucket(index));106_buckets[index].set_entry(entry);107++_number_of_entries;108}109};110111template <typename IdType, typename Entry, typename T>112class AscendingId : public CHeapObj<mtTracing> {113private:114IdType _id;115public:116AscendingId() : _id(0) {}117// callbacks118void assign_id(Entry* entry) {119assert(entry != NULL, "invariant");120assert(entry->id() == 0, "invariant");121entry->set_id(++_id);122}123bool equals(const T& data, uintptr_t hash, const Entry* entry) {124assert(entry->hash() == hash, "invariant");125return true;126}127};128129// IdType must be scalar130template <typename T, typename IdType>131class Entry : public JfrBasicHashtableEntry<T> {132public:133typedef IdType ID;134void init() { _id = 0; }135ID id() const { return _id; }136void set_id(ID id) { _id = id; }137void set_value(const T& value) { this->set_literal(value); }138T& value() const { return *const_cast<Entry*>(this)->literal_addr();}139const T* value_addr() const { return const_cast<Entry*>(this)->literal_addr(); }140141private:142ID _id;143};144145template <typename T, typename IdType, template <typename, typename> class Entry,146typename Callback = AscendingId<IdType, Entry<T, IdType>, T> ,147size_t TABLE_SIZE = 1009>148class HashTableHost : public JfrBasicHashtable<T> {149public:150typedef Entry<T, IdType> HashEntry;151HashTableHost() : _callback(new Callback()) {}152HashTableHost(Callback* cb) : JfrBasicHashtable<T>(TABLE_SIZE, sizeof(HashEntry)), _callback(cb) {}153~HashTableHost() {154this->clear_entries();155this->free_buckets();156}157158// direct insert assumes non-existing entry159HashEntry& put(const T& data, uintptr_t hash);160161// lookup entry, will put if not found162HashEntry& lookup_put(const T& data, uintptr_t hash) {163HashEntry* entry = lookup_only(data, hash);164return entry == NULL ? put(data, hash) : *entry;165}166167// read-only lookup168HashEntry* lookup_only(const T& query, uintptr_t hash);169170// id retrieval171IdType id(const T& data, uintptr_t hash) {172assert(data != NULL, "invariant");173const HashEntry& entry = lookup_put(data, hash);174assert(entry.id() > 0, "invariant");175return entry.id();176}177178template <typename Functor>179void iterate_value(Functor& f);180181template <typename Functor>182void iterate_entry(Functor& f);183184size_t cardinality() const { return this->number_of_entries(); }185bool has_entries() const { return this->cardinality() > 0; }186void clear_entries();187188// removal and deallocation189void free_entry(HashEntry* entry) {190assert(entry != NULL, "invariant");191JfrBasicHashtable<T>::unlink_entry(entry);192FREE_C_HEAP_ARRAY(char, entry, mtTracing);193}194195private:196Callback* _callback;197size_t index_for(uintptr_t hash) { return this->hash_to_index(hash); }198HashEntry* new_entry(const T& data, uintptr_t hash);199void add_entry(size_t index, HashEntry* new_entry) {200assert(new_entry != NULL, "invariant");201_callback->assign_id(new_entry);202assert(new_entry->id() > 0, "invariant");203JfrBasicHashtable<T>::add_entry(index, new_entry);204}205};206207template <typename T, typename IdType, template <typename, typename> class Entry, typename Callback, size_t TABLE_SIZE>208Entry<T, IdType>& HashTableHost<T, IdType, Entry, Callback, TABLE_SIZE>::put(const T& data, uintptr_t hash) {209assert(lookup_only(data, hash) == NULL, "use lookup_put()");210HashEntry* const entry = new_entry(data, hash);211add_entry(index_for(hash), entry);212return *entry;213}214215template <typename T, typename IdType, template <typename, typename> class Entry, typename Callback, size_t TABLE_SIZE>216Entry<T, IdType>* HashTableHost<T, IdType, Entry, Callback, TABLE_SIZE>::lookup_only(const T& query, uintptr_t hash) {217HashEntry* entry = (HashEntry*)this->bucket(index_for(hash));218while (entry != NULL) {219if (entry->hash() == hash && _callback->equals(query, hash, entry)) {220return entry;221}222entry = (HashEntry*)entry->next();223}224return NULL;225}226227template <typename T, typename IdType, template <typename, typename> class Entry, typename Callback, size_t TABLE_SIZE>228template <typename Functor>229void HashTableHost<T, IdType, Entry, Callback, TABLE_SIZE>::iterate_value(Functor& f) {230for (size_t i = 0; i < this->table_size(); ++i) {231const HashEntry* entry = (const HashEntry*)this->bucket(i);232while (entry != NULL) {233if (!f(entry->value())) {234break;235}236entry = (HashEntry*)entry->next();237}238}239}240241template <typename T, typename IdType, template <typename, typename> class Entry, typename Callback, size_t TABLE_SIZE>242template <typename Functor>243void HashTableHost<T, IdType, Entry, Callback, TABLE_SIZE>::iterate_entry(Functor& f) {244for (size_t i = 0; i < this->table_size(); ++i) {245const HashEntry* entry = (const HashEntry*)this->bucket(i);246while (entry != NULL) {247if (!f(entry)) {248break;249}250entry = (const HashEntry*)entry->next();251}252}253}254255template <typename T, typename IdType, template <typename, typename> class Entry, typename Callback, size_t TABLE_SIZE>256void HashTableHost<T, IdType, Entry, Callback, TABLE_SIZE>::clear_entries() {257for (size_t i = 0; i < this->table_size(); ++i) {258HashEntry** bucket = (HashEntry**)this->bucket_addr(i);259HashEntry* entry = *bucket;260while (entry != NULL) {261HashEntry* entry_to_remove = entry;262entry = (HashEntry*)entry->next();263this->free_entry(entry_to_remove);264}265*bucket = NULL;266}267assert(this->number_of_entries() == 0, "should have removed all entries");268}269270template <typename T, typename IdType, template <typename, typename> class Entry, typename Callback, size_t TABLE_SIZE>271Entry<T, IdType>* HashTableHost<T, IdType, Entry, Callback, TABLE_SIZE>::new_entry(const T& data, uintptr_t hash) {272assert(sizeof(HashEntry) == this->entry_size(), "invariant");273HashEntry* const entry = (HashEntry*) NEW_C_HEAP_ARRAY2(char, this->entry_size(), mtTracing, CURRENT_PC);274entry->init();275entry->set_hash(hash);276entry->set_value(data);277entry->set_next(NULL);278assert(0 == entry->id(), "invariant");279return entry;280}281282#endif // SHARE_VM_JFR_UTILITIES_JFRHASHTABLE_HPP283284285