Path: blob/master/src/hotspot/share/jfr/utilities/jfrHashtable.hpp
41149 views
/*1* Copyright (c) 2016, 2020, 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_JFR_UTILITIES_JFRHASHTABLE_HPP25#define SHARE_JFR_UTILITIES_JFRHASHTABLE_HPP2627#include "jfr/utilities/jfrAllocation.hpp"28#include "runtime/atomic.hpp"29#include "services/memTracker.hpp"30#include "utilities/debug.hpp"31#include "utilities/macros.hpp"3233template <typename T>34class JfrBasicHashtableEntry : public JfrCHeapObj {35private:36typedef JfrBasicHashtableEntry<T> Entry;37Entry* _next;38T _literal; // ref to item in table.39uintptr_t _hash;4041public:42JfrBasicHashtableEntry(uintptr_t hash, const T& data) : _next(NULL), _literal(data), _hash(hash) {}43uintptr_t hash() const { return _hash; }44T literal() const { return _literal; }45T* literal_addr() { return &_literal; }46void set_literal(T s) { _literal = s; }47void set_next(Entry* next) { _next = next; }48Entry* next() const { return _next; }49Entry** next_addr() { return &_next; }50};5152template <typename T>53class JfrHashtableBucket : public CHeapObj<mtTracing> {54template <typename>55friend class JfrBasicHashtable;56private:57typedef JfrBasicHashtableEntry<T> TableEntry;58TableEntry* _entry;5960TableEntry* get_entry() const {61return (TableEntry*)Atomic::load_acquire(&_entry);62}63void set_entry(TableEntry* entry) { Atomic::release_store(&_entry, entry);}64TableEntry** entry_addr() { return &_entry; }65};6667template <typename T>68class JfrBasicHashtable : public CHeapObj<mtTracing> {69private:70typedef JfrHashtableBucket<T> Bucket;71typedef JfrBasicHashtableEntry<T> TableEntry;72Bucket* _buckets;73uintptr_t _table_size;74const size_t _entry_size;75size_t _number_of_entries;7677protected:78JfrBasicHashtable(uintptr_t table_size, size_t entry_size) :79_buckets(NULL), _table_size(table_size), _entry_size(entry_size), _number_of_entries(0) {80_buckets = NEW_C_HEAP_ARRAY2(Bucket, table_size, mtTracing, CURRENT_PC);81memset((void*)_buckets, 0, table_size * sizeof(Bucket));82}8384size_t hash_to_index(uintptr_t full_hash) const {85const uintptr_t h = full_hash % _table_size;86assert(h < _table_size, "Illegal hash value");87return (size_t)h;88}89size_t entry_size() const { return _entry_size; }90void unlink_entry(TableEntry* entry) {91entry->set_next(NULL);92--_number_of_entries;93}94void free_buckets() {95FREE_C_HEAP_ARRAY(Bucket, _buckets);96}97TableEntry* bucket(size_t i) { return _buckets[i].get_entry();}98TableEntry** bucket_addr(size_t i) { return _buckets[i].entry_addr(); }99uintptr_t table_size() const { return _table_size; }100size_t number_of_entries() const { return _number_of_entries; }101void add_entry(size_t index, TableEntry* entry) {102assert(entry != NULL, "invariant");103entry->set_next(bucket(index));104_buckets[index].set_entry(entry);105++_number_of_entries;106}107};108109template <typename IdType, typename Entry, typename T>110class AscendingId : public JfrCHeapObj {111private:112IdType _id;113public:114AscendingId() : _id(0) {}115// callbacks116void on_link(Entry* entry) {117assert(entry != NULL, "invariant");118assert(entry->id() == 0, "invariant");119entry->set_id(++_id);120}121bool on_equals(uintptr_t hash, const Entry* entry) {122assert(entry->hash() == hash, "invariant");123return true;124}125};126127// IdType must be scalar128template <typename T, typename IdType>129class JfrHashtableEntry : public JfrBasicHashtableEntry<T> {130public:131JfrHashtableEntry(uintptr_t hash, const T& data) : JfrBasicHashtableEntry<T>(hash, data), _id(0) {}132typedef IdType ID;133ID id() const { return _id; }134void set_id(ID id) const { _id = id; }135T& value() const { return *const_cast<JfrHashtableEntry*>(this)->literal_addr();}136const T* value_addr() const { return const_cast<JfrHashtableEntry*>(this)->literal_addr(); }137private:138mutable ID _id;139};140141template <typename T, typename IdType, template <typename, typename> class Entry,142typename Callback = AscendingId<IdType, Entry<T, IdType>, T> ,143size_t TABLE_SIZE = 1009>144class HashTableHost : public JfrBasicHashtable<T> {145public:146typedef Entry<T, IdType> HashEntry;147HashTableHost(size_t size = 0) : JfrBasicHashtable<T>(size == 0 ? TABLE_SIZE : size, sizeof(HashEntry)), _callback(new Callback()) {}148HashTableHost(Callback* cb, size_t size = 0) : JfrBasicHashtable<T>(size == 0 ? TABLE_SIZE : size, sizeof(HashEntry)), _callback(cb) {}149~HashTableHost() {150this->clear_entries();151this->free_buckets();152}153154// direct insert assumes non-existing entry155HashEntry& put(uintptr_t hash, const T& data);156157// lookup entry, will put if not found158HashEntry& lookup_put(uintptr_t hash, const T& data) {159HashEntry* entry = lookup_only(hash);160return entry == NULL ? put(hash, data) : *entry;161}162163HashEntry* lookup_only(uintptr_t hash);164165// id retrieval166IdType id(uintptr_t hash, const T& data) {167assert(data != NULL, "invariant");168const HashEntry& entry = lookup_put(hash, data);169assert(entry.id() > 0, "invariant");170return entry.id();171}172173template <typename Functor>174void iterate_value(Functor& f);175176template <typename Functor>177void iterate_entry(Functor& f);178179size_t cardinality() const { return this->number_of_entries(); }180bool has_entries() const { return this->cardinality() > 0; }181void clear_entries();182183// removal and deallocation184void free_entry(HashEntry* entry) {185assert(entry != NULL, "invariant");186JfrBasicHashtable<T>::unlink_entry(entry);187_callback->on_unlink(entry);188delete entry;189}190191private:192Callback* _callback;193size_t index_for(uintptr_t hash) { return this->hash_to_index(hash); }194HashEntry* new_entry(uintptr_t hash, const T& data);195void add_entry(size_t index, HashEntry* new_entry) {196assert(new_entry != NULL, "invariant");197_callback->on_link(new_entry);198assert(new_entry->id() > 0, "invariant");199JfrBasicHashtable<T>::add_entry(index, new_entry);200}201};202203template <typename T, typename IdType, template <typename, typename> class Entry, typename Callback, size_t TABLE_SIZE>204Entry<T, IdType>& HashTableHost<T, IdType, Entry, Callback, TABLE_SIZE>::put(uintptr_t hash, const T& data) {205assert(lookup_only(hash) == NULL, "use lookup_put()");206HashEntry* const entry = new_entry(hash, data);207add_entry(index_for(hash), entry);208return *entry;209}210211template <typename T, typename IdType, template <typename, typename> class Entry, typename Callback, size_t TABLE_SIZE>212Entry<T, IdType>* HashTableHost<T, IdType, Entry, Callback, TABLE_SIZE>::lookup_only(uintptr_t hash) {213HashEntry* entry = (HashEntry*)this->bucket(index_for(hash));214while (entry != NULL) {215if (entry->hash() == hash && _callback->on_equals(hash, entry)) {216return entry;217}218entry = (HashEntry*)entry->next();219}220return NULL;221}222223template <typename T, typename IdType, template <typename, typename> class Entry, typename Callback, size_t TABLE_SIZE>224template <typename Functor>225void HashTableHost<T, IdType, Entry, Callback, TABLE_SIZE>::iterate_value(Functor& f) {226for (size_t i = 0; i < this->table_size(); ++i) {227const HashEntry* entry = (const HashEntry*)this->bucket(i);228while (entry != NULL) {229if (!f(entry->value())) {230break;231}232entry = (HashEntry*)entry->next();233}234}235}236237template <typename T, typename IdType, template <typename, typename> class Entry, typename Callback, size_t TABLE_SIZE>238template <typename Functor>239void HashTableHost<T, IdType, Entry, Callback, TABLE_SIZE>::iterate_entry(Functor& f) {240for (size_t i = 0; i < this->table_size(); ++i) {241const HashEntry* entry = (const HashEntry*)this->bucket(i);242while (entry != NULL) {243if (!f(entry)) {244break;245}246entry = (const HashEntry*)entry->next();247}248}249}250251template <typename T, typename IdType, template <typename, typename> class Entry, typename Callback, size_t TABLE_SIZE>252void HashTableHost<T, IdType, Entry, Callback, TABLE_SIZE>::clear_entries() {253for (size_t i = 0; i < this->table_size(); ++i) {254HashEntry** bucket = (HashEntry**)this->bucket_addr(i);255HashEntry* entry = *bucket;256while (entry != NULL) {257HashEntry* entry_to_remove = entry;258entry = (HashEntry*)entry->next();259this->free_entry(entry_to_remove);260}261*bucket = NULL;262}263assert(this->number_of_entries() == 0, "should have removed all entries");264}265266template <typename T, typename IdType, template <typename, typename> class Entry, typename Callback, size_t TABLE_SIZE>267Entry<T, IdType>* HashTableHost<T, IdType, Entry, Callback, TABLE_SIZE>::new_entry(uintptr_t hash, const T& data) {268assert(sizeof(HashEntry) == this->entry_size(), "invariant");269HashEntry* const entry = new HashEntry(hash, data);270assert(entry != NULL, "invariant");271assert(0 == entry->id(), "invariant");272return entry;273}274275#endif // SHARE_JFR_UTILITIES_JFRHASHTABLE_HPP276277278