src/share/vm/utilities/hashtable.hpp

Wed, 04 Jul 2012 15:55:45 -0400

author
coleenp
date
Wed, 04 Jul 2012 15:55:45 -0400
changeset 3904
ace99a6ffc83
parent 3900
d2a62e0f25eb
child 3963
5e2dc722e70d
permissions
-rw-r--r--

7181200: JVM new hashing code breaks SA in product mode
Summary: Made new_hash() overloaded rather than a virtual function so SA code doesn't need to be changed.
Reviewed-by: kvn, acorn, dholmes, fparain

duke@435 1 /*
acorn@3491 2 * Copyright (c) 2003, 2012, 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
stefank@2314 28 #include "memory/allocation.hpp"
stefank@2314 29 #include "oops/oop.hpp"
coleenp@2497 30 #include "oops/symbol.hpp"
stefank@2314 31 #include "runtime/handles.hpp"
stefank@2314 32
duke@435 33 // This is a generic hashtable, designed to be used for the symbol
duke@435 34 // and string tables.
duke@435 35 //
duke@435 36 // It is implemented as an open hash table with a fixed number of buckets.
duke@435 37 //
duke@435 38 // %note:
duke@435 39 // - TableEntrys are allocated in blocks to reduce the space overhead.
duke@435 40
duke@435 41
duke@435 42
zgu@3900 43 template <MEMFLAGS F> class BasicHashtableEntry : public CHeapObj<F> {
duke@435 44 friend class VMStructs;
duke@435 45 private:
duke@435 46 unsigned int _hash; // 32-bit hash for item
duke@435 47
duke@435 48 // Link to next element in the linked list for this bucket. EXCEPT
duke@435 49 // bit 0 set indicates that this entry is shared and must not be
duke@435 50 // unlinked from the table. Bit 0 is set during the dumping of the
duke@435 51 // archive. Since shared entries are immutable, _next fields in the
duke@435 52 // shared entries will not change. New entries will always be
duke@435 53 // unshared and since pointers are align, bit 0 will always remain 0
duke@435 54 // with no extra effort.
zgu@3900 55 BasicHashtableEntry<F>* _next;
duke@435 56
duke@435 57 // Windows IA64 compiler requires subclasses to be able to access these
duke@435 58 protected:
duke@435 59 // Entry objects should not be created, they should be taken from the
duke@435 60 // free list with BasicHashtable.new_entry().
duke@435 61 BasicHashtableEntry() { ShouldNotReachHere(); }
duke@435 62 // Entry objects should not be destroyed. They should be placed on
duke@435 63 // the free list instead with BasicHashtable.free_entry().
duke@435 64 ~BasicHashtableEntry() { ShouldNotReachHere(); }
duke@435 65
duke@435 66 public:
duke@435 67
duke@435 68 unsigned int hash() const { return _hash; }
duke@435 69 void set_hash(unsigned int hash) { _hash = hash; }
duke@435 70 unsigned int* hash_addr() { return &_hash; }
duke@435 71
zgu@3900 72 static BasicHashtableEntry<F>* make_ptr(BasicHashtableEntry<F>* p) {
duke@435 73 return (BasicHashtableEntry*)((intptr_t)p & -2);
duke@435 74 }
duke@435 75
zgu@3900 76 BasicHashtableEntry<F>* next() const {
duke@435 77 return make_ptr(_next);
duke@435 78 }
duke@435 79
zgu@3900 80 void set_next(BasicHashtableEntry<F>* next) {
duke@435 81 _next = next;
duke@435 82 }
duke@435 83
zgu@3900 84 BasicHashtableEntry<F>** next_addr() {
duke@435 85 return &_next;
duke@435 86 }
duke@435 87
duke@435 88 bool is_shared() const {
duke@435 89 return ((intptr_t)_next & 1) != 0;
duke@435 90 }
duke@435 91
duke@435 92 void set_shared() {
zgu@3900 93 _next = (BasicHashtableEntry<F>*)((intptr_t)_next | 1);
duke@435 94 }
duke@435 95 };
duke@435 96
duke@435 97
duke@435 98
zgu@3900 99 template <class T, MEMFLAGS F> class HashtableEntry : public BasicHashtableEntry<F> {
duke@435 100 friend class VMStructs;
duke@435 101 private:
coleenp@2497 102 T _literal; // ref to item in table.
duke@435 103
duke@435 104 public:
duke@435 105 // Literal
coleenp@2497 106 T literal() const { return _literal; }
coleenp@2497 107 T* literal_addr() { return &_literal; }
coleenp@2497 108 void set_literal(T s) { _literal = s; }
duke@435 109
duke@435 110 HashtableEntry* next() const {
zgu@3900 111 return (HashtableEntry*)BasicHashtableEntry<F>::next();
duke@435 112 }
duke@435 113 HashtableEntry** next_addr() {
zgu@3900 114 return (HashtableEntry**)BasicHashtableEntry<F>::next_addr();
duke@435 115 }
duke@435 116 };
duke@435 117
duke@435 118
duke@435 119
zgu@3900 120 template <MEMFLAGS F> class HashtableBucket : public CHeapObj<F> {
duke@435 121 friend class VMStructs;
duke@435 122 private:
duke@435 123 // Instance variable
zgu@3900 124 BasicHashtableEntry<F>* _entry;
duke@435 125
duke@435 126 public:
duke@435 127 // Accessing
duke@435 128 void clear() { _entry = NULL; }
duke@435 129
duke@435 130 // The following methods use order access methods to avoid race
duke@435 131 // conditions in multiprocessor systems.
zgu@3900 132 BasicHashtableEntry<F>* get_entry() const;
zgu@3900 133 void set_entry(BasicHashtableEntry<F>* l);
duke@435 134
duke@435 135 // The following method is not MT-safe and must be done under lock.
zgu@3900 136 BasicHashtableEntry<F>** entry_addr() { return &_entry; }
duke@435 137 };
duke@435 138
duke@435 139
zgu@3900 140 template <MEMFLAGS F> class BasicHashtable : public CHeapObj<F> {
duke@435 141 friend class VMStructs;
duke@435 142
duke@435 143 public:
duke@435 144 BasicHashtable(int table_size, int entry_size);
duke@435 145 BasicHashtable(int table_size, int entry_size,
zgu@3900 146 HashtableBucket<F>* buckets, int number_of_entries);
duke@435 147
duke@435 148 // Sharing support.
duke@435 149 void copy_buckets(char** top, char* end);
duke@435 150 void copy_table(char** top, char* end);
duke@435 151
duke@435 152 // Bucket handling
duke@435 153 int hash_to_index(unsigned int full_hash) {
duke@435 154 int h = full_hash % _table_size;
duke@435 155 assert(h >= 0 && h < _table_size, "Illegal hash value");
duke@435 156 return h;
duke@435 157 }
duke@435 158
duke@435 159 // Reverse the order of elements in each of the buckets.
duke@435 160 void reverse();
duke@435 161
duke@435 162 private:
duke@435 163 // Instance variables
duke@435 164 int _table_size;
zgu@3900 165 HashtableBucket<F>* _buckets;
zgu@3900 166 BasicHashtableEntry<F>* _free_list;
duke@435 167 char* _first_free_entry;
duke@435 168 char* _end_block;
duke@435 169 int _entry_size;
duke@435 170 int _number_of_entries;
duke@435 171
duke@435 172 protected:
duke@435 173
duke@435 174 #ifdef ASSERT
duke@435 175 int _lookup_count;
duke@435 176 int _lookup_length;
duke@435 177 void verify_lookup_length(double load);
duke@435 178 #endif
duke@435 179
coleenp@3865 180 enum {
coleenp@3865 181 rehash_count = 100,
coleenp@3865 182 rehash_multiple = 60
coleenp@3865 183 };
coleenp@3865 184
duke@435 185 void initialize(int table_size, int entry_size, int number_of_entries);
duke@435 186
duke@435 187 // Accessor
duke@435 188 int entry_size() const { return _entry_size; }
duke@435 189
duke@435 190 // The following method is MT-safe and may be used with caution.
zgu@3900 191 BasicHashtableEntry<F>* bucket(int i);
duke@435 192
duke@435 193 // The following method is not MT-safe and must be done under lock.
zgu@3900 194 BasicHashtableEntry<F>** bucket_addr(int i) { return _buckets[i].entry_addr(); }
duke@435 195
duke@435 196 // Table entry management
zgu@3900 197 BasicHashtableEntry<F>* new_entry(unsigned int hashValue);
duke@435 198
coleenp@3865 199 // Check that the table is unbalanced
coleenp@3865 200 bool check_rehash_table(int count);
coleenp@3865 201
coleenp@3865 202 // Used when moving the entry to another table
coleenp@3865 203 // Clean up links, but do not add to free_list
zgu@3900 204 void unlink_entry(BasicHashtableEntry<F>* entry) {
coleenp@3865 205 entry->set_next(NULL);
coleenp@3865 206 --_number_of_entries;
coleenp@3865 207 }
coleenp@3865 208
coleenp@3865 209 // Move over freelist and free block for allocation
coleenp@3865 210 void copy_freelist(BasicHashtable* src) {
coleenp@3865 211 _free_list = src->_free_list;
coleenp@3865 212 src->_free_list = NULL;
coleenp@3865 213 _first_free_entry = src->_first_free_entry;
coleenp@3865 214 src->_first_free_entry = NULL;
coleenp@3865 215 _end_block = src->_end_block;
coleenp@3865 216 src->_end_block = NULL;
coleenp@3865 217 }
coleenp@3865 218
coleenp@3865 219 // Free the buckets in this hashtable
coleenp@3875 220 void free_buckets();
coleenp@3865 221
duke@435 222 public:
acorn@3491 223 int table_size() { return _table_size; }
zgu@3900 224 void set_entry(int index, BasicHashtableEntry<F>* entry);
duke@435 225
zgu@3900 226 void add_entry(int index, BasicHashtableEntry<F>* entry);
duke@435 227
zgu@3900 228 void free_entry(BasicHashtableEntry<F>* entry);
duke@435 229
duke@435 230 int number_of_entries() { return _number_of_entries; }
duke@435 231
duke@435 232 void verify() PRODUCT_RETURN;
duke@435 233 };
duke@435 234
duke@435 235
zgu@3900 236 template <class T, MEMFLAGS F> class Hashtable : public BasicHashtable<F> {
duke@435 237 friend class VMStructs;
duke@435 238
duke@435 239 public:
duke@435 240 Hashtable(int table_size, int entry_size)
zgu@3900 241 : BasicHashtable<F>(table_size, entry_size) { }
duke@435 242
duke@435 243 Hashtable(int table_size, int entry_size,
zgu@3900 244 HashtableBucket<F>* buckets, int number_of_entries)
zgu@3900 245 : BasicHashtable<F>(table_size, entry_size, buckets, number_of_entries) { }
duke@435 246
duke@435 247 // Debugging
duke@435 248 void print() PRODUCT_RETURN;
duke@435 249
duke@435 250 // Reverse the order of elements in each of the buckets. Hashtable
duke@435 251 // entries which refer to objects at a lower address than 'boundary'
duke@435 252 // are separated from those which refer to objects at higher
duke@435 253 // addresses, and appear first in the list.
duke@435 254 void reverse(void* boundary = NULL);
duke@435 255
duke@435 256 protected:
duke@435 257
coleenp@2497 258 unsigned int compute_hash(Symbol* name) {
duke@435 259 return (unsigned int) name->identity_hash();
duke@435 260 }
duke@435 261
coleenp@2497 262 int index_for(Symbol* name) {
duke@435 263 return hash_to_index(compute_hash(name));
duke@435 264 }
duke@435 265
duke@435 266 // Table entry management
zgu@3900 267 HashtableEntry<T, F>* new_entry(unsigned int hashValue, T obj);
duke@435 268
duke@435 269 // The following method is MT-safe and may be used with caution.
zgu@3900 270 HashtableEntry<T, F>* bucket(int i) {
zgu@3900 271 return (HashtableEntry<T, F>*)BasicHashtable<F>::bucket(i);
duke@435 272 }
duke@435 273
duke@435 274 // The following method is not MT-safe and must be done under lock.
zgu@3900 275 HashtableEntry<T, F>** bucket_addr(int i) {
zgu@3900 276 return (HashtableEntry<T, F>**)BasicHashtable<F>::bucket_addr(i);
duke@435 277 }
coleenp@3865 278
coleenp@3865 279 // Function to move these elements into the new table.
zgu@3900 280 void move_to(Hashtable<T, F>* new_table);
coleenp@3904 281 static bool use_alternate_hashcode() { return _seed != 0; }
coleenp@3904 282 static jint seed() { return _seed; }
coleenp@3904 283
coleenp@3904 284 private:
coleenp@3904 285 static jint _seed;
coleenp@3904 286
coleenp@3904 287 unsigned int new_hash(Symbol* s);
coleenp@3904 288 unsigned int new_hash(oop string);
duke@435 289 };
duke@435 290
duke@435 291
duke@435 292 // Verions of hashtable where two handles are used to compute the index.
duke@435 293
zgu@3900 294 template <class T, MEMFLAGS F> class TwoOopHashtable : public Hashtable<T, F> {
duke@435 295 friend class VMStructs;
duke@435 296 protected:
duke@435 297 TwoOopHashtable(int table_size, int entry_size)
zgu@3900 298 : Hashtable<T, F>(table_size, entry_size) {}
duke@435 299
zgu@3900 300 TwoOopHashtable(int table_size, int entry_size, HashtableBucket<F>* t,
duke@435 301 int number_of_entries)
zgu@3900 302 : Hashtable<T, F>(table_size, entry_size, t, number_of_entries) {}
duke@435 303
duke@435 304 public:
coleenp@2497 305 unsigned int compute_hash(Symbol* name, Handle loader) {
duke@435 306 // Be careful with identity_hash(), it can safepoint and if this
duke@435 307 // were one expression, the compiler could choose to unhandle each
duke@435 308 // oop before calling identity_hash() for either of them. If the first
duke@435 309 // causes a GC, the next would fail.
duke@435 310 unsigned int name_hash = name->identity_hash();
duke@435 311 unsigned int loader_hash = loader.is_null() ? 0 : loader->identity_hash();
duke@435 312 return name_hash ^ loader_hash;
duke@435 313 }
duke@435 314
coleenp@2497 315 int index_for(Symbol* name, Handle loader) {
coleenp@2547 316 return this->hash_to_index(compute_hash(name, loader));
duke@435 317 }
duke@435 318 };
stefank@2314 319
stefank@2314 320 #endif // SHARE_VM_UTILITIES_HASHTABLE_HPP

mercurial