32 #include "memory/gcLocker.inline.hpp" |
33 #include "memory/gcLocker.inline.hpp" |
33 #include "oops/oop.inline.hpp" |
34 #include "oops/oop.inline.hpp" |
34 #include "oops/oop.inline2.hpp" |
35 #include "oops/oop.inline2.hpp" |
35 #include "runtime/mutexLocker.hpp" |
36 #include "runtime/mutexLocker.hpp" |
36 #include "utilities/hashtable.inline.hpp" |
37 #include "utilities/hashtable.inline.hpp" |
|
38 #include "utilities/numberSeq.hpp" |
37 |
39 |
38 // -------------------------------------------------------------------------- |
40 // -------------------------------------------------------------------------- |
39 |
41 |
40 SymbolTable* SymbolTable::_the_table = NULL; |
42 SymbolTable* SymbolTable::_the_table = NULL; |
41 // Static arena for symbols that are not deallocated |
43 // Static arena for symbols that are not deallocated |
42 Arena* SymbolTable::_arena = NULL; |
44 Arena* SymbolTable::_arena = NULL; |
|
45 bool SymbolTable::_needs_rehashing = false; |
|
46 jint SymbolTable::_seed = 0; |
43 |
47 |
44 Symbol* SymbolTable::allocate_symbol(const u1* name, int len, bool c_heap, TRAPS) { |
48 Symbol* SymbolTable::allocate_symbol(const u1* name, int len, bool c_heap, TRAPS) { |
45 // Don't allow symbols to be created which cannot fit in a Symbol*. |
49 // Don't allow symbols to be created which cannot fit in a Symbol*. |
46 if (len > Symbol::max_length()) { |
50 if (len > Symbol::max_length()) { |
47 THROW_MSG_0(vmSymbols::java_lang_InternalError(), |
51 THROW_MSG_0(vmSymbols::java_lang_InternalError(), |
119 gclog_or_tty->print(" [Symbols=%d size=" SIZE_FORMAT "K] ", total, |
123 gclog_or_tty->print(" [Symbols=%d size=" SIZE_FORMAT "K] ", total, |
120 (memory_total*HeapWordSize)/1024); |
124 (memory_total*HeapWordSize)/1024); |
121 } |
125 } |
122 } |
126 } |
123 |
127 |
|
128 unsigned int SymbolTable::new_hash(Symbol* sym) { |
|
129 ResourceMark rm; |
|
130 // Use alternate hashing algorithm on this symbol. |
|
131 return AltHashing::murmur3_32(seed(), (const jbyte*)sym->as_C_string(), sym->utf8_length()); |
|
132 } |
|
133 |
|
134 // Create a new table and using alternate hash code, populate the new table |
|
135 // with the existing strings. Set flag to use the alternate hash code afterwards. |
|
136 void SymbolTable::rehash_table() { |
|
137 assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint"); |
|
138 assert(!DumpSharedSpaces, "this should never happen with -Xshare:dump"); |
|
139 // Create a new symbol table |
|
140 SymbolTable* new_table = new SymbolTable(); |
|
141 |
|
142 // Initialize the global seed for hashing. |
|
143 _seed = AltHashing::compute_seed(); |
|
144 assert(seed() != 0, "shouldn't be zero"); |
|
145 |
|
146 the_table()->move_to(new_table); |
|
147 |
|
148 // Delete the table and buckets (entries are reused in new table). |
|
149 delete _the_table; |
|
150 // Don't check if we need rehashing until the table gets unbalanced again. |
|
151 // Then rehash with a new global seed. |
|
152 _needs_rehashing = false; |
|
153 _the_table = new_table; |
|
154 } |
124 |
155 |
125 // Lookup a symbol in a bucket. |
156 // Lookup a symbol in a bucket. |
126 |
157 |
127 Symbol* SymbolTable::lookup(int index, const char* name, |
158 Symbol* SymbolTable::lookup(int index, const char* name, |
128 int len, unsigned int hash) { |
159 int len, unsigned int hash) { |
|
160 int count = 0; |
129 for (HashtableEntry<Symbol*>* e = bucket(index); e != NULL; e = e->next()) { |
161 for (HashtableEntry<Symbol*>* e = bucket(index); e != NULL; e = e->next()) { |
|
162 count++; // count all entries in this bucket, not just ones with same hash |
130 if (e->hash() == hash) { |
163 if (e->hash() == hash) { |
131 Symbol* sym = e->literal(); |
164 Symbol* sym = e->literal(); |
132 if (sym->equals(name, len)) { |
165 if (sym->equals(name, len)) { |
133 // something is referencing this symbol now. |
166 // something is referencing this symbol now. |
134 sym->increment_refcount(); |
167 sym->increment_refcount(); |
135 return sym; |
168 return sym; |
136 } |
169 } |
137 } |
170 } |
138 } |
171 } |
|
172 // If the bucket size is too deep check if this hash code is insufficient. |
|
173 if (count >= BasicHashtable::rehash_count && !needs_rehashing()) { |
|
174 _needs_rehashing = check_rehash_table(count); |
|
175 } |
139 return NULL; |
176 return NULL; |
|
177 } |
|
178 |
|
179 // Pick hashing algorithm, but return value already given if not using a new |
|
180 // hash algorithm. |
|
181 unsigned int SymbolTable::hash_symbol(const char* s, int len, unsigned int hashValue) { |
|
182 return use_alternate_hashcode() ? |
|
183 AltHashing::murmur3_32(seed(), (const jbyte*)s, len) : |
|
184 (hashValue != 0 ? hashValue : java_lang_String::to_hash(s, len)); |
140 } |
185 } |
141 |
186 |
142 |
187 |
143 // We take care not to be blocking while holding the |
188 // We take care not to be blocking while holding the |
144 // SymbolTable_lock. Otherwise, the system might deadlock, since the |
189 // SymbolTable_lock. Otherwise, the system might deadlock, since the |
285 int index = table->hash_to_index(hash); |
330 int index = table->hash_to_index(hash); |
286 return table->basic_add(index, (u1*)name, (int)strlen(name), hash, false, THREAD); |
331 return table->basic_add(index, (u1*)name, (int)strlen(name), hash, false, THREAD); |
287 } |
332 } |
288 |
333 |
289 Symbol* SymbolTable::basic_add(int index, u1 *name, int len, |
334 Symbol* SymbolTable::basic_add(int index, u1 *name, int len, |
290 unsigned int hashValue, bool c_heap, TRAPS) { |
335 unsigned int hashValue_arg, bool c_heap, TRAPS) { |
291 assert(!Universe::heap()->is_in_reserved(name) || GC_locker::is_active(), |
336 assert(!Universe::heap()->is_in_reserved(name) || GC_locker::is_active(), |
292 "proposed name of symbol must be stable"); |
337 "proposed name of symbol must be stable"); |
293 |
338 |
294 // Grab SymbolTable_lock first. |
339 // Grab SymbolTable_lock first. |
295 MutexLocker ml(SymbolTable_lock, THREAD); |
340 MutexLocker ml(SymbolTable_lock, THREAD); |
|
341 |
|
342 // Check if the symbol table has been rehashed, if so, need to recalculate |
|
343 // the hash value. |
|
344 unsigned int hashValue = hash_symbol((const char*)name, len, hashValue_arg); |
296 |
345 |
297 // Since look-up was done lock-free, we need to check if another |
346 // Since look-up was done lock-free, we need to check if another |
298 // thread beat us in the race to insert the symbol. |
347 // thread beat us in the race to insert the symbol. |
299 Symbol* test = lookup(index, (char*)name, len, hashValue); |
348 Symbol* test = lookup(index, (char*)name, len, hashValue); |
300 if (test != NULL) { |
349 if (test != NULL) { |
330 |
379 |
331 // Hold SymbolTable_lock through the symbol creation |
380 // Hold SymbolTable_lock through the symbol creation |
332 MutexLocker ml(SymbolTable_lock, THREAD); |
381 MutexLocker ml(SymbolTable_lock, THREAD); |
333 |
382 |
334 for (int i=0; i<names_count; i++) { |
383 for (int i=0; i<names_count; i++) { |
|
384 // Check if the symbol table has been rehashed, if so, need to recalculate |
|
385 // the hash value. |
|
386 unsigned int hashValue = hash_symbol(names[i], lengths[i], hashValues[i]); |
335 // Since look-up was done lock-free, we need to check if another |
387 // Since look-up was done lock-free, we need to check if another |
336 // thread beat us in the race to insert the symbol. |
388 // thread beat us in the race to insert the symbol. |
337 int index = hash_to_index(hashValues[i]); |
389 int index = hash_to_index(hashValue); |
338 Symbol* test = lookup(index, names[i], lengths[i], hashValues[i]); |
390 Symbol* test = lookup(index, names[i], lengths[i], hashValue); |
339 if (test != NULL) { |
391 if (test != NULL) { |
340 // A race occurred and another thread introduced the symbol, this one |
392 // A race occurred and another thread introduced the symbol, this one |
341 // will be dropped and collected. Use test instead. |
393 // will be dropped and collected. Use test instead. |
342 cp->symbol_at_put(cp_indices[i], test); |
394 cp->symbol_at_put(cp_indices[i], test); |
343 assert(test->refcount() != 0, "lookup should have incremented the count"); |
395 assert(test->refcount() != 0, "lookup should have incremented the count"); |
345 // Create a new symbol. The null class loader is never unloaded so these |
397 // Create a new symbol. The null class loader is never unloaded so these |
346 // are allocated specially in a permanent arena. |
398 // are allocated specially in a permanent arena. |
347 bool c_heap = class_loader() != NULL; |
399 bool c_heap = class_loader() != NULL; |
348 Symbol* sym = allocate_symbol((const u1*)names[i], lengths[i], c_heap, CHECK_(false)); |
400 Symbol* sym = allocate_symbol((const u1*)names[i], lengths[i], c_heap, CHECK_(false)); |
349 assert(sym->equals(names[i], lengths[i]), "symbol must be properly initialized"); // why wouldn't it be??? |
401 assert(sym->equals(names[i], lengths[i]), "symbol must be properly initialized"); // why wouldn't it be??? |
350 HashtableEntry<Symbol*>* entry = new_entry(hashValues[i], sym); |
402 HashtableEntry<Symbol*>* entry = new_entry(hashValue, sym); |
351 add_entry(index, entry); |
403 add_entry(index, entry); |
352 cp->symbol_at_put(cp_indices[i], sym); |
404 cp->symbol_at_put(cp_indices[i], sym); |
353 } |
405 } |
354 } |
406 } |
355 return true; |
407 return true; |
366 guarantee(p->hash() == h, "broken hash in symbol table entry"); |
418 guarantee(p->hash() == h, "broken hash in symbol table entry"); |
367 guarantee(the_table()->hash_to_index(h) == i, |
419 guarantee(the_table()->hash_to_index(h) == i, |
368 "wrong index in symbol table"); |
420 "wrong index in symbol table"); |
369 } |
421 } |
370 } |
422 } |
|
423 } |
|
424 |
|
425 void SymbolTable::dump(outputStream* st) { |
|
426 NumberSeq summary; |
|
427 for (int i = 0; i < the_table()->table_size(); ++i) { |
|
428 int count = 0; |
|
429 for (HashtableEntry<Symbol*>* e = the_table()->bucket(i); |
|
430 e != NULL; e = e->next()) { |
|
431 count++; |
|
432 } |
|
433 summary.add((double)count); |
|
434 } |
|
435 st->print_cr("SymbolTable statistics:"); |
|
436 st->print_cr("Number of buckets : %7d", summary.num()); |
|
437 st->print_cr("Average bucket size : %7.0f", summary.avg()); |
|
438 st->print_cr("Variance of bucket size : %7.0f", summary.variance()); |
|
439 st->print_cr("Std. dev. of bucket size: %7.0f", summary.sd()); |
|
440 st->print_cr("Maximum bucket size : %7.0f", summary.maximum()); |
371 } |
441 } |
372 |
442 |
373 |
443 |
374 //--------------------------------------------------------------------------- |
444 //--------------------------------------------------------------------------- |
375 // Non-product code |
445 // Non-product code |
512 |
581 |
513 |
582 |
514 // -------------------------------------------------------------------------- |
583 // -------------------------------------------------------------------------- |
515 StringTable* StringTable::_the_table = NULL; |
584 StringTable* StringTable::_the_table = NULL; |
516 |
585 |
|
586 bool StringTable::_needs_rehashing = false; |
|
587 jint StringTable::_seed = 0; |
|
588 |
|
589 // Pick hashing algorithm |
|
590 unsigned int StringTable::hash_string(const jchar* s, int len, unsigned int hashValue) { |
|
591 return use_alternate_hashcode() ? AltHashing::murmur3_32(seed(), s, len) : |
|
592 (hashValue != 0 ? hashValue : java_lang_String::to_hash(s, len)); |
|
593 } |
|
594 |
517 oop StringTable::lookup(int index, jchar* name, |
595 oop StringTable::lookup(int index, jchar* name, |
518 int len, unsigned int hash) { |
596 int len, unsigned int hash) { |
|
597 int count = 0; |
519 for (HashtableEntry<oop>* l = bucket(index); l != NULL; l = l->next()) { |
598 for (HashtableEntry<oop>* l = bucket(index); l != NULL; l = l->next()) { |
|
599 count++; |
520 if (l->hash() == hash) { |
600 if (l->hash() == hash) { |
521 if (java_lang_String::equals(l->literal(), name, len)) { |
601 if (java_lang_String::equals(l->literal(), name, len)) { |
522 return l->literal(); |
602 return l->literal(); |
523 } |
603 } |
524 } |
604 } |
525 } |
605 } |
|
606 // If the bucket size is too deep check if this hash code is insufficient. |
|
607 if (count >= BasicHashtable::rehash_count && !needs_rehashing()) { |
|
608 _needs_rehashing = check_rehash_table(count); |
|
609 } |
526 return NULL; |
610 return NULL; |
527 } |
611 } |
528 |
612 |
529 |
613 |
530 oop StringTable::basic_add(int index, Handle string_or_null, jchar* name, |
614 oop StringTable::basic_add(int index, Handle string_or_null, jchar* name, |
531 int len, unsigned int hashValue, TRAPS) { |
615 int len, unsigned int hashValue_arg, TRAPS) { |
532 debug_only(StableMemoryChecker smc(name, len * sizeof(name[0]))); |
616 debug_only(StableMemoryChecker smc(name, len * sizeof(name[0]))); |
533 assert(!Universe::heap()->is_in_reserved(name) || GC_locker::is_active(), |
617 assert(!Universe::heap()->is_in_reserved(name) || GC_locker::is_active(), |
534 "proposed name of symbol must be stable"); |
618 "proposed name of symbol must be stable"); |
535 |
619 |
536 Handle string; |
620 Handle string; |
545 MutexLocker ml(StringTable_lock, THREAD); |
629 MutexLocker ml(StringTable_lock, THREAD); |
546 |
630 |
547 assert(java_lang_String::equals(string(), name, len), |
631 assert(java_lang_String::equals(string(), name, len), |
548 "string must be properly initialized"); |
632 "string must be properly initialized"); |
549 |
633 |
|
634 // Check if the symbol table has been rehashed, if so, need to recalculate |
|
635 // the hash value before second lookup. |
|
636 unsigned int hashValue = hash_string(name, len, hashValue_arg); |
|
637 |
550 // Since look-up was done lock-free, we need to check if another |
638 // Since look-up was done lock-free, we need to check if another |
551 // thread beat us in the race to insert the symbol. |
639 // thread beat us in the race to insert the symbol. |
552 |
640 |
553 oop test = lookup(index, name, len, hashValue); // calls lookup(u1*, int) |
641 oop test = lookup(index, name, len, hashValue); // calls lookup(u1*, int) |
554 if (test != NULL) { |
642 if (test != NULL) { |
564 |
652 |
565 oop StringTable::lookup(Symbol* symbol) { |
653 oop StringTable::lookup(Symbol* symbol) { |
566 ResourceMark rm; |
654 ResourceMark rm; |
567 int length; |
655 int length; |
568 jchar* chars = symbol->as_unicode(length); |
656 jchar* chars = symbol->as_unicode(length); |
569 unsigned int hashValue = java_lang_String::hash_string(chars, length); |
657 unsigned int hashValue = hash_string(chars, length); |
570 int index = the_table()->hash_to_index(hashValue); |
658 int index = the_table()->hash_to_index(hashValue); |
571 return the_table()->lookup(index, chars, length, hashValue); |
659 return the_table()->lookup(index, chars, length, hashValue); |
572 } |
660 } |
573 |
661 |
574 |
662 |
575 oop StringTable::intern(Handle string_or_null, jchar* name, |
663 oop StringTable::intern(Handle string_or_null, jchar* name, |
576 int len, TRAPS) { |
664 int len, TRAPS) { |
577 unsigned int hashValue = java_lang_String::hash_string(name, len); |
665 unsigned int hashValue = hash_string(name, len); |
578 int index = the_table()->hash_to_index(hashValue); |
666 int index = the_table()->hash_to_index(hashValue); |
579 oop string = the_table()->lookup(index, name, len, hashValue); |
667 oop string = the_table()->lookup(index, name, len, hashValue); |
580 |
668 |
581 // Found |
669 // Found |
582 if (string != NULL) return string; |
670 if (string != NULL) return string; |
673 guarantee(the_table()->hash_to_index(h) == i, |
761 guarantee(the_table()->hash_to_index(h) == i, |
674 "wrong index in string table"); |
762 "wrong index in string table"); |
675 } |
763 } |
676 } |
764 } |
677 } |
765 } |
|
766 |
|
767 void StringTable::dump(outputStream* st) { |
|
768 NumberSeq summary; |
|
769 for (int i = 0; i < the_table()->table_size(); ++i) { |
|
770 HashtableEntry<oop>* p = the_table()->bucket(i); |
|
771 int count = 0; |
|
772 for ( ; p != NULL; p = p->next()) { |
|
773 count++; |
|
774 } |
|
775 summary.add((double)count); |
|
776 } |
|
777 st->print_cr("StringTable statistics:"); |
|
778 st->print_cr("Number of buckets : %7d", summary.num()); |
|
779 st->print_cr("Average bucket size : %7.0f", summary.avg()); |
|
780 st->print_cr("Variance of bucket size : %7.0f", summary.variance()); |
|
781 st->print_cr("Std. dev. of bucket size: %7.0f", summary.sd()); |
|
782 st->print_cr("Maximum bucket size : %7.0f", summary.maximum()); |
|
783 } |
|
784 |
|
785 |
|
786 unsigned int StringTable::new_hash(oop string) { |
|
787 ResourceMark rm; |
|
788 int length; |
|
789 jchar* chars = java_lang_String::as_unicode_string(string, length); |
|
790 // Use alternate hashing algorithm on the string |
|
791 return AltHashing::murmur3_32(seed(), chars, length); |
|
792 } |
|
793 |
|
794 // Create a new table and using alternate hash code, populate the new table |
|
795 // with the existing strings. Set flag to use the alternate hash code afterwards. |
|
796 void StringTable::rehash_table() { |
|
797 assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint"); |
|
798 assert(!DumpSharedSpaces, "this should never happen with -Xshare:dump"); |
|
799 StringTable* new_table = new StringTable(); |
|
800 |
|
801 // Initialize new global seed for hashing. |
|
802 _seed = AltHashing::compute_seed(); |
|
803 assert(seed() != 0, "shouldn't be zero"); |
|
804 |
|
805 // Rehash the table |
|
806 the_table()->move_to(new_table); |
|
807 |
|
808 // Delete the table and buckets (entries are reused in new table). |
|
809 delete _the_table; |
|
810 // Don't check if we need rehashing until the table gets unbalanced again. |
|
811 // Then rehash with a new global seed. |
|
812 _needs_rehashing = false; |
|
813 _the_table = new_table; |
|
814 } |