28 #include "classfile/javaClasses.inline.hpp" |
28 #include "classfile/javaClasses.inline.hpp" |
29 #include "classfile/stringTable.hpp" |
29 #include "classfile/stringTable.hpp" |
30 #include "classfile/systemDictionary.hpp" |
30 #include "classfile/systemDictionary.hpp" |
31 #include "gc/shared/collectedHeap.hpp" |
31 #include "gc/shared/collectedHeap.hpp" |
32 #include "gc/shared/oopStorage.inline.hpp" |
32 #include "gc/shared/oopStorage.inline.hpp" |
33 #include "gc/shared/oopStorageParState.inline.hpp" |
|
34 #include "logging/log.hpp" |
33 #include "logging/log.hpp" |
35 #include "logging/logStream.hpp" |
34 #include "logging/logStream.hpp" |
36 #include "memory/allocation.inline.hpp" |
35 #include "memory/allocation.inline.hpp" |
37 #include "memory/filemap.hpp" |
36 #include "memory/filemap.hpp" |
38 #include "memory/heapShared.inline.hpp" |
37 #include "memory/heapShared.inline.hpp" |
77 java_lang_String::equals |
76 java_lang_String::equals |
78 > _shared_table; |
77 > _shared_table; |
79 #endif |
78 #endif |
80 |
79 |
81 // -------------------------------------------------------------------------- |
80 // -------------------------------------------------------------------------- |
82 StringTable* StringTable::_the_table = NULL; |
81 |
83 volatile bool StringTable::_alt_hash = false; |
82 typedef ConcurrentHashTable<WeakHandle<vm_string_table_data>, |
84 |
83 StringTableConfig, mtSymbol> StringTableHash; |
|
84 static StringTableHash* _local_table = NULL; |
|
85 |
|
86 volatile bool StringTable::_has_work = false; |
|
87 volatile bool StringTable::_needs_rehashing = false; |
|
88 |
|
89 volatile size_t StringTable::_uncleaned_items_count = 0; |
|
90 OopStorage* StringTable::_weak_handles = NULL; |
|
91 |
|
92 static size_t _current_size = 0; |
|
93 static volatile size_t _items_count = 0; |
|
94 |
|
95 volatile bool _alt_hash = false; |
85 static juint murmur_seed = 0; |
96 static juint murmur_seed = 0; |
86 |
97 |
87 uintx hash_string(const jchar* s, int len, bool useAlt) { |
98 uintx hash_string(const jchar* s, int len, bool useAlt) { |
88 return useAlt ? |
99 return useAlt ? |
89 AltHashing::murmur3_32(murmur_seed, s, len) : |
100 AltHashing::murmur3_32(murmur_seed, s, len) : |
105 ResourceMark rm(THREAD); |
116 ResourceMark rm(THREAD); |
106 // All String oops are hashed as unicode |
117 // All String oops are hashed as unicode |
107 int length; |
118 int length; |
108 jchar* chars = java_lang_String::as_unicode_string(val_oop, length, THREAD); |
119 jchar* chars = java_lang_String::as_unicode_string(val_oop, length, THREAD); |
109 if (chars != NULL) { |
120 if (chars != NULL) { |
110 return hash_string(chars, length, StringTable::_alt_hash); |
121 return hash_string(chars, length, _alt_hash); |
111 } |
122 } |
112 vm_exit_out_of_memory(length, OOM_MALLOC_ERROR, "get hash from oop"); |
123 vm_exit_out_of_memory(length, OOM_MALLOC_ERROR, "get hash from oop"); |
113 return 0; |
124 return 0; |
114 } |
125 } |
115 // We use default allocation/deallocation but counted |
126 // We use default allocation/deallocation but counted |
194 size_t ret; |
205 size_t ret; |
195 for (ret = 1; ((size_t)1 << ret) < val; ++ret); |
206 for (ret = 1; ((size_t)1 << ret) < val; ++ret); |
196 return ret; |
207 return ret; |
197 } |
208 } |
198 |
209 |
199 StringTable::StringTable() : _local_table(NULL), _current_size(0), _has_work(0), |
210 void StringTable::create_table() { |
200 _needs_rehashing(false), _weak_handles(NULL), _items_count(0), _uncleaned_items_count(0) { |
|
201 _weak_handles = new OopStorage("StringTable weak", |
211 _weak_handles = new OopStorage("StringTable weak", |
202 StringTableWeakAlloc_lock, |
212 StringTableWeakAlloc_lock, |
203 StringTableWeakActive_lock); |
213 StringTableWeakActive_lock); |
204 size_t start_size_log_2 = ceil_log2(StringTableSize); |
214 size_t start_size_log_2 = ceil_log2(StringTableSize); |
205 _current_size = ((size_t)1) << start_size_log_2; |
215 _current_size = ((size_t)1) << start_size_log_2; |
206 log_trace(stringtable)("Start size: " SIZE_FORMAT " (" SIZE_FORMAT ")", |
216 log_trace(stringtable)("Start size: " SIZE_FORMAT " (" SIZE_FORMAT ")", |
207 _current_size, start_size_log_2); |
217 _current_size, start_size_log_2); |
208 _local_table = new StringTableHash(start_size_log_2, END_SIZE, REHASH_LEN); |
218 _local_table = new StringTableHash(start_size_log_2, END_SIZE, REHASH_LEN); |
209 } |
219 } |
210 |
220 |
211 void StringTable::update_needs_rehash(bool rehash) { |
|
212 if (rehash) { |
|
213 _needs_rehashing = true; |
|
214 } |
|
215 } |
|
216 |
|
217 size_t StringTable::item_added() { |
221 size_t StringTable::item_added() { |
218 return Atomic::add((size_t)1, &(the_table()->_items_count)); |
222 return Atomic::add((size_t)1, &_items_count); |
219 } |
223 } |
220 |
224 |
221 size_t StringTable::add_items_to_clean(size_t ndead) { |
225 size_t StringTable::add_items_to_clean(size_t ndead) { |
222 size_t total = Atomic::add((size_t)ndead, &(the_table()->_uncleaned_items_count)); |
226 size_t total = Atomic::add((size_t)ndead, &_uncleaned_items_count); |
223 log_trace(stringtable)( |
227 log_trace(stringtable)( |
224 "Uncleaned items:" SIZE_FORMAT " added: " SIZE_FORMAT " total:" SIZE_FORMAT, |
228 "Uncleaned items:" SIZE_FORMAT " added: " SIZE_FORMAT " total:" SIZE_FORMAT, |
225 the_table()->_uncleaned_items_count, ndead, total); |
229 _uncleaned_items_count, ndead, total); |
226 return total; |
230 return total; |
227 } |
231 } |
228 |
232 |
229 void StringTable::item_removed() { |
233 void StringTable::item_removed() { |
230 Atomic::add((size_t)-1, &(the_table()->_items_count)); |
234 Atomic::add((size_t)-1, &_items_count); |
231 } |
235 } |
232 |
236 |
233 double StringTable::get_load_factor() const { |
237 double StringTable::get_load_factor() { |
234 return (double)_items_count/_current_size; |
238 return (double)_items_count/_current_size; |
235 } |
239 } |
236 |
240 |
237 double StringTable::get_dead_factor() const { |
241 double StringTable::get_dead_factor() { |
238 return (double)_uncleaned_items_count/_current_size; |
242 return (double)_uncleaned_items_count/_current_size; |
239 } |
243 } |
240 |
244 |
241 size_t StringTable::table_size() { |
245 size_t StringTable::table_size() { |
242 return ((size_t)1) << _local_table->get_size_log2(Thread::current()); |
246 return ((size_t)1) << _local_table->get_size_log2(Thread::current()); |
243 } |
247 } |
244 |
248 |
245 void StringTable::trigger_concurrent_work() { |
249 void StringTable::trigger_concurrent_work() { |
246 MutexLocker ml(Service_lock, Mutex::_no_safepoint_check_flag); |
250 MutexLocker ml(Service_lock, Mutex::_no_safepoint_check_flag); |
247 the_table()->_has_work = true; |
251 _has_work = true; |
248 Service_lock->notify_all(); |
252 Service_lock->notify_all(); |
249 } |
253 } |
250 |
254 |
251 // Probing |
255 // Probing |
252 oop StringTable::lookup(Symbol* symbol) { |
256 oop StringTable::lookup(Symbol* symbol) { |
256 return lookup(chars, length); |
260 return lookup(chars, length); |
257 } |
261 } |
258 |
262 |
259 oop StringTable::lookup(const jchar* name, int len) { |
263 oop StringTable::lookup(const jchar* name, int len) { |
260 unsigned int hash = java_lang_String::hash_code(name, len); |
264 unsigned int hash = java_lang_String::hash_code(name, len); |
261 oop string = StringTable::the_table()->lookup_shared(name, len, hash); |
265 oop string = lookup_shared(name, len, hash); |
262 if (string != NULL) { |
266 if (string != NULL) { |
263 return string; |
267 return string; |
264 } |
268 } |
265 if (StringTable::_alt_hash) { |
269 if (_alt_hash) { |
266 hash = hash_string(name, len, true); |
270 hash = hash_string(name, len, true); |
267 } |
271 } |
268 return StringTable::the_table()->do_lookup(name, len, hash); |
272 return do_lookup(name, len, hash); |
269 } |
273 } |
270 |
274 |
271 class StringTableGet : public StackObj { |
275 class StringTableGet : public StackObj { |
272 Thread* _thread; |
276 Thread* _thread; |
273 Handle _return; |
277 Handle _return; |
327 } |
331 } |
328 |
332 |
329 oop StringTable::intern(Handle string_or_null_h, const jchar* name, int len, TRAPS) { |
333 oop StringTable::intern(Handle string_or_null_h, const jchar* name, int len, TRAPS) { |
330 // shared table always uses java_lang_String::hash_code |
334 // shared table always uses java_lang_String::hash_code |
331 unsigned int hash = java_lang_String::hash_code(name, len); |
335 unsigned int hash = java_lang_String::hash_code(name, len); |
332 oop found_string = StringTable::the_table()->lookup_shared(name, len, hash); |
336 oop found_string = lookup_shared(name, len, hash); |
333 if (found_string != NULL) { |
337 if (found_string != NULL) { |
334 return found_string; |
338 return found_string; |
335 } |
339 } |
336 if (StringTable::_alt_hash) { |
340 if (_alt_hash) { |
337 hash = hash_string(name, len, true); |
341 hash = hash_string(name, len, true); |
338 } |
342 } |
339 found_string = StringTable::the_table()->do_lookup(name, len, hash); |
343 found_string = do_lookup(name, len, hash); |
340 if (found_string != NULL) { |
344 if (found_string != NULL) { |
341 return found_string; |
345 return found_string; |
342 } |
346 } |
343 return StringTable::the_table()->do_intern(string_or_null_h, name, len, |
347 return do_intern(string_or_null_h, name, len, hash, CHECK_NULL); |
344 hash, CHECK_NULL); |
|
345 } |
348 } |
346 |
349 |
347 oop StringTable::do_intern(Handle string_or_null_h, const jchar* name, |
350 oop StringTable::do_intern(Handle string_or_null_h, const jchar* name, |
348 int len, uintx hash, TRAPS) { |
351 int len, uintx hash, TRAPS) { |
349 HandleMark hm(THREAD); // cleanup strings created |
352 HandleMark hm(THREAD); // cleanup strings created |
382 } while(true); |
385 } while(true); |
383 } |
386 } |
384 |
387 |
385 void StringTable::oops_do(OopClosure* f) { |
388 void StringTable::oops_do(OopClosure* f) { |
386 assert(f != NULL, "No closure"); |
389 assert(f != NULL, "No closure"); |
387 StringTable::the_table()->_weak_handles->oops_do(f); |
390 _weak_handles->oops_do(f); |
388 } |
|
389 |
|
390 void StringTable::possibly_parallel_oops_do( |
|
391 OopStorage::ParState<false /* concurrent */, false /* const */>* |
|
392 _par_state_string, OopClosure* f) |
|
393 { |
|
394 assert(f != NULL, "No closure"); |
|
395 _par_state_string->oops_do(f); |
|
396 } |
391 } |
397 |
392 |
398 // Concurrent work |
393 // Concurrent work |
399 void StringTable::grow(JavaThread* jt) { |
394 void StringTable::grow(JavaThread* jt) { |
400 StringTableHash::GrowTask gt(_local_table); |
395 StringTableHash::GrowTask gt(_local_table); |
478 load_factor, dead_factor); |
473 load_factor, dead_factor); |
479 trigger_concurrent_work(); |
474 trigger_concurrent_work(); |
480 } |
475 } |
481 } |
476 } |
482 |
477 |
483 void StringTable::concurrent_work(JavaThread* jt) { |
478 void StringTable::do_concurrent_work(JavaThread* jt) { |
484 _has_work = false; |
479 _has_work = false; |
485 double load_factor = get_load_factor(); |
480 double load_factor = get_load_factor(); |
486 log_debug(stringtable, perf)("Concurrent work, live factor: %g", load_factor); |
481 log_debug(stringtable, perf)("Concurrent work, live factor: %g", load_factor); |
487 // We prefer growing, since that also removes dead items |
482 // We prefer growing, since that also removes dead items |
488 if (load_factor > PREF_AVG_LIST_LEN && !_local_table->is_max_size_reached()) { |
483 if (load_factor > PREF_AVG_LIST_LEN && !_local_table->is_max_size_reached()) { |
640 |
627 |
641 size_t StringTable::verify_and_compare_entries() { |
628 size_t StringTable::verify_and_compare_entries() { |
642 Thread* thr = Thread::current(); |
629 Thread* thr = Thread::current(); |
643 GrowableArray<oop>* oops = |
630 GrowableArray<oop>* oops = |
644 new (ResourceObj::C_HEAP, mtInternal) |
631 new (ResourceObj::C_HEAP, mtInternal) |
645 GrowableArray<oop>((int)the_table()->_current_size, true); |
632 GrowableArray<oop>((int)_current_size, true); |
646 |
633 |
647 VerifyCompStrings vcs(oops); |
634 VerifyCompStrings vcs(oops); |
648 if (!the_table()->_local_table->try_scan(thr, vcs)) { |
635 if (!_local_table->try_scan(thr, vcs)) { |
649 log_info(stringtable)("verify unavailable at this moment"); |
636 log_info(stringtable)("verify unavailable at this moment"); |
650 } |
637 } |
651 delete oops; |
638 delete oops; |
652 return vcs._errors; |
639 return vcs._errors; |
653 } |
640 } |
690 }; |
677 }; |
691 }; |
678 }; |
692 |
679 |
693 void StringTable::dump(outputStream* st, bool verbose) { |
680 void StringTable::dump(outputStream* st, bool verbose) { |
694 if (!verbose) { |
681 if (!verbose) { |
695 the_table()->print_table_statistics(st, "StringTable"); |
682 print_table_statistics(st, "StringTable"); |
696 } else { |
683 } else { |
697 Thread* thr = Thread::current(); |
684 Thread* thr = Thread::current(); |
698 ResourceMark rm(thr); |
685 ResourceMark rm(thr); |
699 st->print_cr("VERSION: 1.1"); |
686 st->print_cr("VERSION: 1.1"); |
700 PrintString ps(thr, st); |
687 PrintString ps(thr, st); |
701 if (!the_table()->_local_table->try_scan(thr, ps)) { |
688 if (!_local_table->try_scan(thr, ps)) { |
702 st->print_cr("dump unavailable at this moment"); |
689 st->print_cr("dump unavailable at this moment"); |
703 } |
690 } |
704 } |
691 } |
705 } |
692 } |
706 |
693 |
783 |
770 |
784 void StringTable::copy_shared_string_table(CompactHashtableWriter* writer) { |
771 void StringTable::copy_shared_string_table(CompactHashtableWriter* writer) { |
785 assert(HeapShared::is_heap_object_archiving_allowed(), "must be"); |
772 assert(HeapShared::is_heap_object_archiving_allowed(), "must be"); |
786 |
773 |
787 CopyToArchive copy(writer); |
774 CopyToArchive copy(writer); |
788 StringTable::the_table()->_local_table->do_safepoint_scan(copy); |
775 _local_table->do_safepoint_scan(copy); |
789 } |
776 } |
790 |
777 |
791 void StringTable::write_to_archive() { |
778 void StringTable::write_to_archive() { |
792 assert(HeapShared::is_heap_object_archiving_allowed(), "must be"); |
779 assert(HeapShared::is_heap_object_archiving_allowed(), "must be"); |
793 |
780 |
794 _shared_table.reset(); |
781 _shared_table.reset(); |
795 int num_buckets = CompactHashtableWriter::default_num_buckets( |
782 int num_buckets = CompactHashtableWriter::default_num_buckets(_items_count); |
796 StringTable::the_table()->_items_count); |
|
797 CompactHashtableWriter writer(num_buckets, |
783 CompactHashtableWriter writer(num_buckets, |
798 &MetaspaceShared::stats()->string); |
784 &MetaspaceShared::stats()->string); |
799 |
785 |
800 // Copy the interned strings into the "string space" within the java heap |
786 // Copy the interned strings into the "string space" within the java heap |
801 copy_shared_string_table(&writer); |
787 copy_shared_string_table(&writer); |