src/share/vm/utilities/hashtable.hpp

Mon, 15 May 2017 12:20:15 +0200

author
tschatzl
date
Mon, 15 May 2017 12:20:15 +0200
changeset 8766
ce9a710b0f63
parent 7207
152cf4afc11f
child 8856
ac27a9c85bea
permissions
-rw-r--r--

8180048: Interned string and symbol table leak memory during parallel unlinking
Summary: Make appending found dead BasicHashtableEntrys to the free list atomic.
Reviewed-by: ehelin, shade

duke@435 1 /*
minqi@6351 2 * Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved.
duke@435 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
duke@435 4 *
duke@435 5 * This code is free software; you can redistribute it and/or modify it
duke@435 6 * under the terms of the GNU General Public License version 2 only, as
duke@435 7 * published by the Free Software Foundation.
duke@435 8 *
duke@435 9 * This code is distributed in the hope that it will be useful, but WITHOUT
duke@435 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
duke@435 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
duke@435 12 * version 2 for more details (a copy is included in the LICENSE file that
duke@435 13 * accompanied this code).
duke@435 14 *
duke@435 15 * You should have received a copy of the GNU General Public License version
duke@435 16 * 2 along with this work; if not, write to the Free Software Foundation,
duke@435 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
duke@435 18 *
trims@1907 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
trims@1907 20 * or visit www.oracle.com if you need additional information or have any
trims@1907 21 * questions.
duke@435 22 *
duke@435 23 */
duke@435 24
stefank@2314 25 #ifndef SHARE_VM_UTILITIES_HASHTABLE_HPP
stefank@2314 26 #define SHARE_VM_UTILITIES_HASHTABLE_HPP
stefank@2314 27
coleenp@4037 28 #include "classfile/classLoaderData.hpp"
stefank@2314 29 #include "memory/allocation.hpp"
stefank@2314 30 #include "oops/oop.hpp"
coleenp@2497 31 #include "oops/symbol.hpp"
stefank@2314 32 #include "runtime/handles.hpp"
stefank@2314 33
duke@435 34 // This is a generic hashtable, designed to be used for the symbol
duke@435 35 // and string tables.
duke@435 36 //
duke@435 37 // It is implemented as an open hash table with a fixed number of buckets.
duke@435 38 //
duke@435 39 // %note:
duke@435 40 // - TableEntrys are allocated in blocks to reduce the space overhead.
duke@435 41
duke@435 42
duke@435 43
zgu@3900 44 template <MEMFLAGS F> class BasicHashtableEntry : public CHeapObj<F> {
duke@435 45 friend class VMStructs;
duke@435 46 private:
duke@435 47 unsigned int _hash; // 32-bit hash for item
duke@435 48
duke@435 49 // Link to next element in the linked list for this bucket. EXCEPT
duke@435 50 // bit 0 set indicates that this entry is shared and must not be
duke@435 51 // unlinked from the table. Bit 0 is set during the dumping of the
duke@435 52 // archive. Since shared entries are immutable, _next fields in the
duke@435 53 // shared entries will not change. New entries will always be
duke@435 54 // unshared and since pointers are align, bit 0 will always remain 0
duke@435 55 // with no extra effort.
zgu@3900 56 BasicHashtableEntry<F>* _next;
duke@435 57
duke@435 58 // Windows IA64 compiler requires subclasses to be able to access these
duke@435 59 protected:
duke@435 60 // Entry objects should not be created, they should be taken from the
duke@435 61 // free list with BasicHashtable.new_entry().
duke@435 62 BasicHashtableEntry() { ShouldNotReachHere(); }
duke@435 63 // Entry objects should not be destroyed. They should be placed on
duke@435 64 // the free list instead with BasicHashtable.free_entry().
duke@435 65 ~BasicHashtableEntry() { ShouldNotReachHere(); }
duke@435 66
duke@435 67 public:
duke@435 68
duke@435 69 unsigned int hash() const { return _hash; }
duke@435 70 void set_hash(unsigned int hash) { _hash = hash; }
duke@435 71 unsigned int* hash_addr() { return &_hash; }
duke@435 72
zgu@3900 73 static BasicHashtableEntry<F>* make_ptr(BasicHashtableEntry<F>* p) {
duke@435 74 return (BasicHashtableEntry*)((intptr_t)p & -2);
duke@435 75 }
duke@435 76
zgu@3900 77 BasicHashtableEntry<F>* next() const {
duke@435 78 return make_ptr(_next);
duke@435 79 }
duke@435 80
zgu@3900 81 void set_next(BasicHashtableEntry<F>* next) {
duke@435 82 _next = next;
duke@435 83 }
duke@435 84
zgu@3900 85 BasicHashtableEntry<F>** next_addr() {
duke@435 86 return &_next;
duke@435 87 }
duke@435 88
duke@435 89 bool is_shared() const {
duke@435 90 return ((intptr_t)_next & 1) != 0;
duke@435 91 }
duke@435 92
duke@435 93 void set_shared() {
zgu@3900 94 _next = (BasicHashtableEntry<F>*)((intptr_t)_next | 1);
duke@435 95 }
duke@435 96 };
duke@435 97
duke@435 98
duke@435 99
zgu@3900 100 template <class T, MEMFLAGS F> class HashtableEntry : public BasicHashtableEntry<F> {
duke@435 101 friend class VMStructs;
duke@435 102 private:
coleenp@2497 103 T _literal; // ref to item in table.
duke@435 104
duke@435 105 public:
duke@435 106 // Literal
coleenp@2497 107 T literal() const { return _literal; }
coleenp@2497 108 T* literal_addr() { return &_literal; }
coleenp@2497 109 void set_literal(T s) { _literal = s; }
duke@435 110
duke@435 111 HashtableEntry* next() const {
zgu@3900 112 return (HashtableEntry*)BasicHashtableEntry<F>::next();
duke@435 113 }
duke@435 114 HashtableEntry** next_addr() {
zgu@3900 115 return (HashtableEntry**)BasicHashtableEntry<F>::next_addr();
duke@435 116 }
duke@435 117 };
duke@435 118
duke@435 119
duke@435 120
zgu@3900 121 template <MEMFLAGS F> class HashtableBucket : public CHeapObj<F> {
duke@435 122 friend class VMStructs;
duke@435 123 private:
duke@435 124 // Instance variable
zgu@3900 125 BasicHashtableEntry<F>* _entry;
duke@435 126
duke@435 127 public:
duke@435 128 // Accessing
duke@435 129 void clear() { _entry = NULL; }
duke@435 130
duke@435 131 // The following methods use order access methods to avoid race
duke@435 132 // conditions in multiprocessor systems.
zgu@3900 133 BasicHashtableEntry<F>* get_entry() const;
zgu@3900 134 void set_entry(BasicHashtableEntry<F>* l);
duke@435 135
duke@435 136 // The following method is not MT-safe and must be done under lock.
zgu@3900 137 BasicHashtableEntry<F>** entry_addr() { return &_entry; }
duke@435 138 };
duke@435 139
duke@435 140
zgu@3900 141 template <MEMFLAGS F> class BasicHashtable : public CHeapObj<F> {
duke@435 142 friend class VMStructs;
duke@435 143
duke@435 144 public:
duke@435 145 BasicHashtable(int table_size, int entry_size);
duke@435 146 BasicHashtable(int table_size, int entry_size,
zgu@3900 147 HashtableBucket<F>* buckets, int number_of_entries);
duke@435 148
duke@435 149 // Sharing support.
duke@435 150 void copy_buckets(char** top, char* end);
duke@435 151 void copy_table(char** top, char* end);
duke@435 152
duke@435 153 // Bucket handling
duke@435 154 int hash_to_index(unsigned int full_hash) {
duke@435 155 int h = full_hash % _table_size;
duke@435 156 assert(h >= 0 && h < _table_size, "Illegal hash value");
duke@435 157 return h;
duke@435 158 }
duke@435 159
duke@435 160 // Reverse the order of elements in each of the buckets.
duke@435 161 void reverse();
duke@435 162
duke@435 163 private:
duke@435 164 // Instance variables
duke@435 165 int _table_size;
zgu@3900 166 HashtableBucket<F>* _buckets;
tschatzl@8766 167 BasicHashtableEntry<F>* volatile _free_list;
duke@435 168 char* _first_free_entry;
duke@435 169 char* _end_block;
duke@435 170 int _entry_size;
tschatzl@8766 171 volatile int _number_of_entries;
duke@435 172
duke@435 173 protected:
duke@435 174
duke@435 175 #ifdef ASSERT
duke@435 176 int _lookup_count;
duke@435 177 int _lookup_length;
duke@435 178 void verify_lookup_length(double load);
duke@435 179 #endif
duke@435 180
duke@435 181 void initialize(int table_size, int entry_size, int number_of_entries);
duke@435 182
duke@435 183 // Accessor
duke@435 184 int entry_size() const { return _entry_size; }
duke@435 185
duke@435 186 // The following method is MT-safe and may be used with caution.
zgu@3900 187 BasicHashtableEntry<F>* bucket(int i);
duke@435 188
duke@435 189 // The following method is not MT-safe and must be done under lock.
zgu@3900 190 BasicHashtableEntry<F>** bucket_addr(int i) { return _buckets[i].entry_addr(); }
duke@435 191
mgerdin@7207 192 // Attempt to get an entry from the free list
mgerdin@7207 193 BasicHashtableEntry<F>* new_entry_free_list();
mgerdin@7207 194
duke@435 195 // Table entry management
zgu@3900 196 BasicHashtableEntry<F>* new_entry(unsigned int hashValue);
duke@435 197
coleenp@3865 198 // Used when moving the entry to another table
coleenp@3865 199 // Clean up links, but do not add to free_list
zgu@3900 200 void unlink_entry(BasicHashtableEntry<F>* entry) {
coleenp@3865 201 entry->set_next(NULL);
coleenp@3865 202 --_number_of_entries;
coleenp@3865 203 }
coleenp@3865 204
coleenp@3865 205 // Move over freelist and free block for allocation
coleenp@3865 206 void copy_freelist(BasicHashtable* src) {
coleenp@3865 207 _free_list = src->_free_list;
coleenp@3865 208 src->_free_list = NULL;
coleenp@3865 209 _first_free_entry = src->_first_free_entry;
coleenp@3865 210 src->_first_free_entry = NULL;
coleenp@3865 211 _end_block = src->_end_block;
coleenp@3865 212 src->_end_block = NULL;
coleenp@3865 213 }
coleenp@3865 214
coleenp@3865 215 // Free the buckets in this hashtable
coleenp@3875 216 void free_buckets();
coleenp@3865 217
tschatzl@8766 218 // Helper data structure containing context for the bucket entry unlink process,
tschatzl@8766 219 // storing the unlinked buckets in a linked list.
tschatzl@8766 220 // Also avoids the need to pass around these four members as parameters everywhere.
tschatzl@8766 221 struct BucketUnlinkContext {
tschatzl@8766 222 int _num_processed;
tschatzl@8766 223 int _num_removed;
tschatzl@8766 224 // Head and tail pointers for the linked list of removed entries.
tschatzl@8766 225 BasicHashtableEntry<F>* _removed_head;
tschatzl@8766 226 BasicHashtableEntry<F>* _removed_tail;
tschatzl@8766 227
tschatzl@8766 228 BucketUnlinkContext() : _num_processed(0), _num_removed(0), _removed_head(NULL), _removed_tail(NULL) {
tschatzl@8766 229 }
tschatzl@8766 230
tschatzl@8766 231 void free_entry(BasicHashtableEntry<F>* entry);
tschatzl@8766 232 };
tschatzl@8766 233 // Add of bucket entries linked together in the given context to the global free list. This method
tschatzl@8766 234 // is mt-safe wrt. to other calls of this method.
tschatzl@8766 235 void bulk_free_entries(BucketUnlinkContext* context);
duke@435 236 public:
acorn@3491 237 int table_size() { return _table_size; }
zgu@3900 238 void set_entry(int index, BasicHashtableEntry<F>* entry);
duke@435 239
zgu@3900 240 void add_entry(int index, BasicHashtableEntry<F>* entry);
duke@435 241
zgu@3900 242 void free_entry(BasicHashtableEntry<F>* entry);
duke@435 243
duke@435 244 int number_of_entries() { return _number_of_entries; }
duke@435 245
duke@435 246 void verify() PRODUCT_RETURN;
duke@435 247 };
duke@435 248
duke@435 249
zgu@3900 250 template <class T, MEMFLAGS F> class Hashtable : public BasicHashtable<F> {
duke@435 251 friend class VMStructs;
duke@435 252
duke@435 253 public:
duke@435 254 Hashtable(int table_size, int entry_size)
zgu@3900 255 : BasicHashtable<F>(table_size, entry_size) { }
duke@435 256
duke@435 257 Hashtable(int table_size, int entry_size,
zgu@3900 258 HashtableBucket<F>* buckets, int number_of_entries)
zgu@3900 259 : BasicHashtable<F>(table_size, entry_size, buckets, number_of_entries) { }
duke@435 260
duke@435 261 // Debugging
duke@435 262 void print() PRODUCT_RETURN;
duke@435 263
duke@435 264 // Reverse the order of elements in each of the buckets. Hashtable
duke@435 265 // entries which refer to objects at a lower address than 'boundary'
duke@435 266 // are separated from those which refer to objects at higher
duke@435 267 // addresses, and appear first in the list.
duke@435 268 void reverse(void* boundary = NULL);
duke@435 269
duke@435 270 protected:
duke@435 271
coleenp@2497 272 unsigned int compute_hash(Symbol* name) {
duke@435 273 return (unsigned int) name->identity_hash();
duke@435 274 }
duke@435 275
coleenp@2497 276 int index_for(Symbol* name) {
andrew@3963 277 return this->hash_to_index(compute_hash(name));
duke@435 278 }
duke@435 279
duke@435 280 // Table entry management
zgu@3900 281 HashtableEntry<T, F>* new_entry(unsigned int hashValue, T obj);
duke@435 282
duke@435 283 // The following method is MT-safe and may be used with caution.
zgu@3900 284 HashtableEntry<T, F>* bucket(int i) {
zgu@3900 285 return (HashtableEntry<T, F>*)BasicHashtable<F>::bucket(i);
duke@435 286 }
duke@435 287
duke@435 288 // The following method is not MT-safe and must be done under lock.
zgu@3900 289 HashtableEntry<T, F>** bucket_addr(int i) {
zgu@3900 290 return (HashtableEntry<T, F>**)BasicHashtable<F>::bucket_addr(i);
duke@435 291 }
coleenp@3865 292
mgerdin@7207 293 };
mgerdin@7207 294
mgerdin@7207 295 template <class T, MEMFLAGS F> class RehashableHashtable : public Hashtable<T, F> {
mgerdin@7207 296 protected:
mgerdin@7207 297
mgerdin@7207 298 enum {
mgerdin@7207 299 rehash_count = 100,
mgerdin@7207 300 rehash_multiple = 60
mgerdin@7207 301 };
mgerdin@7207 302
mgerdin@7207 303 // Check that the table is unbalanced
mgerdin@7207 304 bool check_rehash_table(int count);
mgerdin@7207 305
mgerdin@7207 306 public:
mgerdin@7207 307 RehashableHashtable(int table_size, int entry_size)
mgerdin@7207 308 : Hashtable<T, F>(table_size, entry_size) { }
mgerdin@7207 309
mgerdin@7207 310 RehashableHashtable(int table_size, int entry_size,
mgerdin@7207 311 HashtableBucket<F>* buckets, int number_of_entries)
mgerdin@7207 312 : Hashtable<T, F>(table_size, entry_size, buckets, number_of_entries) { }
mgerdin@7207 313
mgerdin@7207 314
coleenp@3865 315 // Function to move these elements into the new table.
mgerdin@7207 316 void move_to(RehashableHashtable<T, F>* new_table);
coleenp@3904 317 static bool use_alternate_hashcode() { return _seed != 0; }
minqi@6351 318 static juint seed() { return _seed; }
coleenp@3904 319
iklam@5144 320 static int literal_size(Symbol *symbol);
iklam@5144 321 static int literal_size(oop oop);
iklam@5144 322
iklam@5144 323 // The following two are currently not used, but are needed anyway because some
iklam@5144 324 // C++ compilers (MacOS and Solaris) force the instantiation of
iklam@5144 325 // Hashtable<ConstantPool*, mtClass>::dump_table() even though we never call this function
iklam@5144 326 // in the VM code.
iklam@5144 327 static int literal_size(ConstantPool *cp) {Unimplemented(); return 0;}
iklam@5144 328 static int literal_size(Klass *k) {Unimplemented(); return 0;}
iklam@5144 329
iklam@5144 330 void dump_table(outputStream* st, const char *table_name);
iklam@5144 331
coleenp@3904 332 private:
minqi@6351 333 static juint _seed;
duke@435 334 };
duke@435 335
duke@435 336
duke@435 337 // Verions of hashtable where two handles are used to compute the index.
duke@435 338
zgu@3900 339 template <class T, MEMFLAGS F> class TwoOopHashtable : public Hashtable<T, F> {
duke@435 340 friend class VMStructs;
duke@435 341 protected:
duke@435 342 TwoOopHashtable(int table_size, int entry_size)
zgu@3900 343 : Hashtable<T, F>(table_size, entry_size) {}
duke@435 344
zgu@3900 345 TwoOopHashtable(int table_size, int entry_size, HashtableBucket<F>* t,
duke@435 346 int number_of_entries)
zgu@3900 347 : Hashtable<T, F>(table_size, entry_size, t, number_of_entries) {}
duke@435 348
duke@435 349 public:
coleenp@4037 350 unsigned int compute_hash(Symbol* name, ClassLoaderData* loader_data) {
duke@435 351 unsigned int name_hash = name->identity_hash();
coleenp@4037 352 // loader is null with CDS
coleenp@4037 353 assert(loader_data != NULL || UseSharedSpaces || DumpSharedSpaces,
coleenp@4037 354 "only allowed with shared spaces");
coleenp@4037 355 unsigned int loader_hash = loader_data == NULL ? 0 : loader_data->identity_hash();
duke@435 356 return name_hash ^ loader_hash;
duke@435 357 }
duke@435 358
coleenp@4037 359 int index_for(Symbol* name, ClassLoaderData* loader_data) {
coleenp@4037 360 return this->hash_to_index(compute_hash(name, loader_data));
duke@435 361 }
duke@435 362 };
stefank@2314 363
stefank@2314 364 #endif // SHARE_VM_UTILITIES_HASHTABLE_HPP

mercurial