1/*
2 * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 *
23 */
24
25#ifndef SHARE_UTILITIES_HASHTABLE_HPP
26#define SHARE_UTILITIES_HASHTABLE_HPP
27
28#include "memory/allocation.hpp"
29#include "oops/oop.hpp"
30#include "oops/symbol.hpp"
31#include "runtime/handles.hpp"
32#include "utilities/growableArray.hpp"
33#include "utilities/tableStatistics.hpp"
34
35// This is a generic hashtable, designed to be used for the symbol
36// and string tables.
37//
38// It is implemented as an open hash table with a fixed number of buckets.
39//
40// %note:
41// - TableEntrys are allocated in blocks to reduce the space overhead.
42
43
44
45template <MEMFLAGS F> class BasicHashtableEntry : public CHeapObj<F> {
46 friend class VMStructs;
47private:
48 unsigned int _hash; // 32-bit hash for item
49
50 // Link to next element in the linked list for this bucket. EXCEPT
51 // bit 0 set indicates that this entry is shared and must not be
52 // unlinked from the table. Bit 0 is set during the dumping of the
53 // archive. Since shared entries are immutable, _next fields in the
54 // shared entries will not change. New entries will always be
55 // unshared and since pointers are align, bit 0 will always remain 0
56 // with no extra effort.
57 BasicHashtableEntry<F>* _next;
58
59 // Windows IA64 compiler requires subclasses to be able to access these
60protected:
61 // Entry objects should not be created, they should be taken from the
62 // free list with BasicHashtable.new_entry().
63 BasicHashtableEntry() { ShouldNotReachHere(); }
64 // Entry objects should not be destroyed. They should be placed on
65 // the free list instead with BasicHashtable.free_entry().
66 ~BasicHashtableEntry() { ShouldNotReachHere(); }
67
68public:
69
70 unsigned int hash() const { return _hash; }
71 void set_hash(unsigned int hash) { _hash = hash; }
72 unsigned int* hash_addr() { return &_hash; }
73
74 static BasicHashtableEntry<F>* make_ptr(BasicHashtableEntry<F>* p) {
75 return (BasicHashtableEntry*)((intptr_t)p & -2);
76 }
77
78 BasicHashtableEntry<F>* next() const {
79 return make_ptr(_next);
80 }
81
82 void set_next(BasicHashtableEntry<F>* next) {
83 _next = next;
84 }
85
86 BasicHashtableEntry<F>** next_addr() {
87 return &_next;
88 }
89
90 bool is_shared() const {
91 return ((intptr_t)_next & 1) != 0;
92 }
93
94 void set_shared() {
95 _next = (BasicHashtableEntry<F>*)((intptr_t)_next | 1);
96 }
97};
98
99
100
101template <class T, MEMFLAGS F> class HashtableEntry : public BasicHashtableEntry<F> {
102 friend class VMStructs;
103private:
104 T _literal; // ref to item in table.
105
106public:
107 // Literal
108 T literal() const { return _literal; }
109 T* literal_addr() { return &_literal; }
110 void set_literal(T s) { _literal = s; }
111
112 HashtableEntry* next() const {
113 return (HashtableEntry*)BasicHashtableEntry<F>::next();
114 }
115 HashtableEntry** next_addr() {
116 return (HashtableEntry**)BasicHashtableEntry<F>::next_addr();
117 }
118};
119
120
121
122template <MEMFLAGS F> class HashtableBucket : public CHeapObj<F> {
123 friend class VMStructs;
124private:
125 // Instance variable
126 BasicHashtableEntry<F>* _entry;
127
128public:
129 // Accessing
130 void clear() { _entry = NULL; }
131
132 // The following methods use order access methods to avoid race
133 // conditions in multiprocessor systems.
134 BasicHashtableEntry<F>* get_entry() const;
135 void set_entry(BasicHashtableEntry<F>* l);
136
137 // The following method is not MT-safe and must be done under lock.
138 BasicHashtableEntry<F>** entry_addr() { return &_entry; }
139
140};
141
142
143template <MEMFLAGS F> class BasicHashtable : public CHeapObj<F> {
144 friend class VMStructs;
145
146public:
147 BasicHashtable(int table_size, int entry_size);
148 BasicHashtable(int table_size, int entry_size,
149 HashtableBucket<F>* buckets, int number_of_entries);
150 ~BasicHashtable();
151
152 // Bucket handling
153 int hash_to_index(unsigned int full_hash) const {
154 int h = full_hash % _table_size;
155 assert(h >= 0 && h < _table_size, "Illegal hash value");
156 return h;
157 }
158
159private:
160 // Instance variables
161 int _table_size;
162 HashtableBucket<F>* _buckets;
163 BasicHashtableEntry<F>* volatile _free_list;
164 char* _first_free_entry;
165 char* _end_block;
166 int _entry_size;
167 volatile int _number_of_entries;
168 GrowableArray<char*>* _entry_blocks;
169
170protected:
171
172 TableRateStatistics _stats_rate;
173
174 void initialize(int table_size, int entry_size, int number_of_entries);
175
176 // Accessor
177 int entry_size() const { return _entry_size; }
178
179 // The following method is MT-safe and may be used with caution.
180 BasicHashtableEntry<F>* bucket(int i) const;
181
182 // The following method is not MT-safe and must be done under lock.
183 BasicHashtableEntry<F>** bucket_addr(int i) { return _buckets[i].entry_addr(); }
184
185 // Attempt to get an entry from the free list
186 BasicHashtableEntry<F>* new_entry_free_list();
187
188 // Table entry management
189 BasicHashtableEntry<F>* new_entry(unsigned int hashValue);
190
191 // Used when moving the entry to another table
192 // Clean up links, but do not add to free_list
193 void unlink_entry(BasicHashtableEntry<F>* entry) {
194 entry->set_next(NULL);
195 --_number_of_entries;
196 }
197
198 // Move over freelist and free block for allocation
199 void copy_freelist(BasicHashtable* src) {
200 _free_list = src->_free_list;
201 src->_free_list = NULL;
202 _first_free_entry = src->_first_free_entry;
203 src->_first_free_entry = NULL;
204 _end_block = src->_end_block;
205 src->_end_block = NULL;
206 }
207
208 // Free the buckets in this hashtable
209 void free_buckets();
210public:
211 int table_size() const { return _table_size; }
212 void set_entry(int index, BasicHashtableEntry<F>* entry);
213
214 void add_entry(int index, BasicHashtableEntry<F>* entry);
215
216 void free_entry(BasicHashtableEntry<F>* entry);
217
218 int number_of_entries() const { return _number_of_entries; }
219
220 bool resize(int new_size);
221
222 // Grow the number of buckets if the average entries per bucket is over the load_factor
223 bool maybe_grow(int max_size, int load_factor = 8);
224
225 template <class T> void verify_table(const char* table_name) PRODUCT_RETURN;
226};
227
228
229template <class T, MEMFLAGS F> class Hashtable : public BasicHashtable<F> {
230 friend class VMStructs;
231
232public:
233 Hashtable(int table_size, int entry_size)
234 : BasicHashtable<F>(table_size, entry_size) { }
235
236 Hashtable(int table_size, int entry_size,
237 HashtableBucket<F>* buckets, int number_of_entries)
238 : BasicHashtable<F>(table_size, entry_size, buckets, number_of_entries) { }
239
240 // Debugging
241 void print() PRODUCT_RETURN;
242
243 unsigned int compute_hash(const Symbol* name) const {
244 return (unsigned int) name->identity_hash();
245 }
246
247 int index_for(const Symbol* name) const {
248 return this->hash_to_index(compute_hash(name));
249 }
250
251 TableStatistics statistics_calculate(T (*literal_load_barrier)(HashtableEntry<T, F>*) = NULL);
252 void print_table_statistics(outputStream* st, const char *table_name, T (*literal_load_barrier)(HashtableEntry<T, F>*) = NULL);
253
254 protected:
255
256 // Table entry management
257 HashtableEntry<T, F>* new_entry(unsigned int hashValue, T obj);
258 // Don't create and use freelist of HashtableEntry.
259 HashtableEntry<T, F>* allocate_new_entry(unsigned int hashValue, T obj);
260
261 // The following method is MT-safe and may be used with caution.
262 HashtableEntry<T, F>* bucket(int i) const {
263 return (HashtableEntry<T, F>*)BasicHashtable<F>::bucket(i);
264 }
265
266 // The following method is not MT-safe and must be done under lock.
267 HashtableEntry<T, F>** bucket_addr(int i) {
268 return (HashtableEntry<T, F>**)BasicHashtable<F>::bucket_addr(i);
269 }
270};
271
272// A subclass of BasicHashtable that allows you to do a simple K -> V mapping
273// without using tons of boilerplate code.
274template<
275 typename K, typename V, MEMFLAGS F,
276 unsigned (*HASH) (K const&) = primitive_hash<K>,
277 bool (*EQUALS)(K const&, K const&) = primitive_equals<K>
278 >
279class KVHashtable : public BasicHashtable<F> {
280 class KVHashtableEntry : public BasicHashtableEntry<F> {
281 public:
282 K _key;
283 V _value;
284 KVHashtableEntry* next() {
285 return (KVHashtableEntry*)BasicHashtableEntry<F>::next();
286 }
287 };
288
289protected:
290 KVHashtableEntry* bucket(int i) const {
291 return (KVHashtableEntry*)BasicHashtable<F>::bucket(i);
292 }
293
294 KVHashtableEntry* new_entry(unsigned int hashValue, K key, V value) {
295 KVHashtableEntry* entry = (KVHashtableEntry*)BasicHashtable<F>::new_entry(hashValue);
296 entry->_key = key;
297 entry->_value = value;
298 return entry;
299 }
300
301public:
302 KVHashtable(int table_size) : BasicHashtable<F>(table_size, sizeof(KVHashtableEntry)) {}
303
304 void add(K key, V value) {
305 unsigned int hash = HASH(key);
306 KVHashtableEntry* entry = new_entry(hash, key, value);
307 BasicHashtable<F>::add_entry(BasicHashtable<F>::hash_to_index(hash), entry);
308 }
309
310 V* lookup(K key) {
311 unsigned int hash = HASH(key);
312 int index = BasicHashtable<F>::hash_to_index(hash);
313 for (KVHashtableEntry* e = bucket(index); e != NULL; e = e->next()) {
314 if (e->hash() == hash && e->_key == key) {
315 return &(e->_value);
316 }
317 }
318 return NULL;
319 }
320};
321
322
323#endif // SHARE_UTILITIES_HASHTABLE_HPP
324