rev 50787 : 8205583: Crash in ConcurrentHashTable do_bulk_delete_locked_for
Reviewed-by:
rev 50788 : [mq]: 8205583_gerard
1 /*
2 * Copyright (c) 1997, 2018, 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 #include "precompiled.hpp"
26 #include "classfile/altHashing.hpp"
27 #include "classfile/compactHashtable.inline.hpp"
28 #include "classfile/javaClasses.inline.hpp"
29 #include "classfile/stringTable.hpp"
30 #include "classfile/systemDictionary.hpp"
31 #include "gc/shared/collectedHeap.hpp"
32 #include "gc/shared/oopStorage.inline.hpp"
33 #include "gc/shared/oopStorageParState.inline.hpp"
34 #include "logging/log.hpp"
35 #include "logging/logStream.hpp"
36 #include "memory/allocation.inline.hpp"
37 #include "memory/filemap.hpp"
38 #include "memory/metaspaceShared.hpp"
39 #include "memory/resourceArea.hpp"
40 #include "memory/universe.hpp"
41 #include "oops/access.inline.hpp"
42 #include "oops/oop.inline.hpp"
43 #include "oops/typeArrayOop.inline.hpp"
44 #include "oops/weakHandle.inline.hpp"
45 #include "runtime/atomic.hpp"
46 #include "runtime/handles.inline.hpp"
47 #include "runtime/mutexLocker.hpp"
48 #include "runtime/safepointVerifiers.hpp"
49 #include "runtime/timerTrace.hpp"
50 #include "runtime/interfaceSupport.inline.hpp"
51 #include "services/diagnosticCommand.hpp"
52 #include "utilities/concurrentHashTable.inline.hpp"
53 #include "utilities/concurrentHashTableTasks.inline.hpp"
54 #include "utilities/macros.hpp"
55
56 // We prefer short chains of avg 2
57 #define PREF_AVG_LIST_LEN 2
58 // 2^24 is max size
59 #define END_SIZE 24
60 // If a chain gets to 32 something might be wrong
61 #define REHASH_LEN 32
62 // If we have as many dead items as 50% of the number of bucket
63 #define CLEAN_DEAD_HIGH_WATER_MARK 0.5
64
65 // --------------------------------------------------------------------------
66 StringTable* StringTable::_the_table = NULL;
67 bool StringTable::_shared_string_mapped = false;
68 CompactHashtable<oop, char> StringTable::_shared_table;
69 bool StringTable::_alt_hash = false;
70
71 static juint murmur_seed = 0;
72
73 uintx hash_string(const jchar* s, int len, bool useAlt) {
74 return useAlt ?
75 AltHashing::murmur3_32(murmur_seed, s, len) :
76 java_lang_String::hash_code(s, len);
77 }
78
79 class StringTableConfig : public StringTableHash::BaseConfig {
80 private:
81 public:
82 static uintx get_hash(WeakHandle<vm_string_table_data> const& value,
83 bool* is_dead) {
84 EXCEPTION_MARK;
85 oop val_oop = value.peek();
86 if (val_oop == NULL) {
87 *is_dead = true;
88 return 0;
89 }
90 *is_dead = false;
91 ResourceMark rm(THREAD);
92 // All String oops are hashed as unicode
93 int length;
94 jchar* chars = java_lang_String::as_unicode_string(val_oop, length, THREAD);
95 if (chars != NULL) {
96 return hash_string(chars, length, StringTable::_alt_hash);
97 }
98 vm_exit_out_of_memory(length, OOM_MALLOC_ERROR, "get hash from oop");
99 return 0;
100 }
101 // We use default allocation/deallocation but counted
102 static void* allocate_node(size_t size,
103 WeakHandle<vm_string_table_data> const& value) {
104 StringTable::item_added();
105 return StringTableHash::BaseConfig::allocate_node(size, value);
106 }
107 static void free_node(void* memory,
108 WeakHandle<vm_string_table_data> const& value) {
109 value.release();
110 StringTableHash::BaseConfig::free_node(memory, value);
111 StringTable::item_removed();
112 }
113 };
114
115 class StringTableLookupJchar : StackObj {
116 private:
117 Thread* _thread;
118 uintx _hash;
119 int _len;
120 const jchar* _str;
121 Handle _found;
122
123 public:
124 StringTableLookupJchar(Thread* thread, uintx hash, const jchar* key, int len)
125 : _thread(thread), _hash(hash), _str(key), _len(len) {
126 }
127 uintx get_hash() const {
128 return _hash;
129 }
130 bool equals(WeakHandle<vm_string_table_data>* value, bool* is_dead) {
131 oop val_oop = value->peek();
132 if (val_oop == NULL) {
133 // dead oop, mark this hash dead for cleaning
134 *is_dead = true;
135 return false;
136 }
137 bool equals = java_lang_String::equals(val_oop, (jchar*)_str, _len);
138 if (!equals) {
139 return false;
140 }
141 // Need to resolve weak handle and Handleize through possible safepoint.
142 _found = Handle(_thread, value->resolve());
143 return true;
144 }
145 };
146
147 class StringTableLookupOop : public StackObj {
148 private:
149 Thread* _thread;
150 uintx _hash;
151 Handle _find;
152 Handle _found; // Might be a different oop with the same value that's already
153 // in the table, which is the point.
154 public:
155 StringTableLookupOop(Thread* thread, uintx hash, Handle handle)
156 : _thread(thread), _hash(hash), _find(handle) { }
157
158 uintx get_hash() const {
159 return _hash;
160 }
161
162 bool equals(WeakHandle<vm_string_table_data>* value, bool* is_dead) {
163 oop val_oop = value->peek();
164 if (val_oop == NULL) {
165 // dead oop, mark this hash dead for cleaning
166 *is_dead = true;
167 return false;
168 }
169 bool equals = java_lang_String::equals(_find(), val_oop);
170 if (!equals) {
171 return false;
172 }
173 // Need to resolve weak handle and Handleize through possible safepoint.
174 _found = Handle(_thread, value->resolve());
175 return true;
176 }
177 };
178
179 static size_t ceil_pow_2(uintx val) {
180 size_t ret;
181 for (ret = 1; ((size_t)1 << ret) < val; ++ret);
182 return ret;
183 }
184
185 StringTable::StringTable() : _local_table(NULL), _current_size(0), _has_work(0),
186 _needs_rehashing(false), _weak_handles(NULL), _items(0), _uncleaned_items(0) {
187 _weak_handles = new OopStorage("StringTable weak",
188 StringTableWeakAlloc_lock,
189 StringTableWeakActive_lock);
190 size_t start_size_log_2 = ceil_pow_2(StringTableSize);
191 _current_size = ((size_t)1) << start_size_log_2;
192 log_trace(stringtable)("Start size: " SIZE_FORMAT " (" SIZE_FORMAT ")",
193 _current_size, start_size_log_2);
194 _local_table = new StringTableHash(start_size_log_2, END_SIZE, REHASH_LEN);
195 }
196
197 size_t StringTable::item_added() {
198 return Atomic::add((size_t)1, &(the_table()->_items));
199 }
200
201 size_t StringTable::add_items_to_clean(size_t ndead) {
202 size_t total = Atomic::add((size_t)ndead, &(the_table()->_uncleaned_items));
203 log_trace(stringtable)(
204 "Uncleaned items:" SIZE_FORMAT " added: " SIZE_FORMAT " total:" SIZE_FORMAT,
205 the_table()->_uncleaned_items, ndead, total);
206 return total;
207 }
208
209 void StringTable::item_removed() {
210 Atomic::add((size_t)-1, &(the_table()->_items));
211 }
212
213 double StringTable::get_load_factor() {
214 return (_items*1.0)/_current_size;
215 }
216
217 double StringTable::get_dead_factor() {
218 return (_uncleaned_items*1.0)/_current_size;
219 }
220
221 size_t StringTable::table_size(Thread* thread) {
222 return ((size_t)(1)) << _local_table->get_size_log2(thread != NULL ? thread
223 : Thread::current());
224 }
225
226 void StringTable::trigger_concurrent_work() {
227 MutexLockerEx ml(Service_lock, Mutex::_no_safepoint_check_flag);
228 the_table()->_has_work = true;
229 Service_lock->notify_all();
230 }
231
232 // Probing
233 oop StringTable::lookup(Symbol* symbol) {
234 ResourceMark rm;
235 int length;
236 jchar* chars = symbol->as_unicode(length);
237 return lookup(chars, length);
238 }
239
240 oop StringTable::lookup(jchar* name, int len) {
241 unsigned int hash = java_lang_String::hash_code(name, len);
242 oop string = StringTable::the_table()->lookup_shared(name, len, hash);
243 if (string != NULL) {
244 return string;
245 }
246 if (StringTable::_alt_hash) {
247 hash = hash_string(name, len, true);
248 }
249 return StringTable::the_table()->do_lookup(name, len, hash);
250 }
251
252 class StringTableGet : public StackObj {
253 Thread* _thread;
254 Handle _return;
255 public:
256 StringTableGet(Thread* thread) : _thread(thread) {}
257 void operator()(WeakHandle<vm_string_table_data>* val) {
258 oop result = val->resolve();
259 assert(result != NULL, "Result should be reachable");
260 _return = Handle(_thread, result);
261 }
262 oop get_res_oop() {
263 return _return();
264 }
265 };
266
267 oop StringTable::do_lookup(jchar* name, int len, uintx hash) {
268 Thread* thread = Thread::current();
269 StringTableLookupJchar lookup(thread, hash, name, len);
270 StringTableGet stg(thread);
271 bool rehash_warning;
272 _local_table->get(thread, lookup, stg, &rehash_warning);
273 if (rehash_warning) {
274 _needs_rehashing = true;
275 }
276 return stg.get_res_oop();
277 }
278
279 // Interning
280 oop StringTable::intern(Symbol* symbol, TRAPS) {
281 if (symbol == NULL) return NULL;
282 ResourceMark rm(THREAD);
283 int length;
284 jchar* chars = symbol->as_unicode(length);
285 Handle string;
286 oop result = intern(string, chars, length, CHECK_NULL);
287 return result;
288 }
289
290 oop StringTable::intern(oop string, TRAPS) {
291 if (string == NULL) return NULL;
292 ResourceMark rm(THREAD);
293 int length;
294 Handle h_string (THREAD, string);
295 jchar* chars = java_lang_String::as_unicode_string(string, length,
296 CHECK_NULL);
297 oop result = intern(h_string, chars, length, CHECK_NULL);
298 return result;
299 }
300
301 oop StringTable::intern(const char* utf8_string, TRAPS) {
302 if (utf8_string == NULL) return NULL;
303 ResourceMark rm(THREAD);
304 int length = UTF8::unicode_length(utf8_string);
305 jchar* chars = NEW_RESOURCE_ARRAY(jchar, length);
306 UTF8::convert_to_unicode(utf8_string, chars, length);
307 Handle string;
308 oop result = intern(string, chars, length, CHECK_NULL);
309 return result;
310 }
311
312 oop StringTable::intern(Handle string_or_null_h, jchar* name, int len, TRAPS) {
313 // shared table always uses java_lang_String::hash_code
314 unsigned int hash = java_lang_String::hash_code(name, len);
315 oop found_string = StringTable::the_table()->lookup_shared(name, len, hash);
316 if (found_string != NULL) {
317 return found_string;
318 }
319 if (StringTable::_alt_hash) {
320 hash = hash_string(name, len, true);
321 }
322 return StringTable::the_table()->do_intern(string_or_null_h, name, len,
323 hash, CHECK_NULL);
324 }
325
326 class StringTableCreateEntry : public StackObj {
327 private:
328 Thread* _thread;
329 Handle _return;
330 Handle _store;
331 public:
332 StringTableCreateEntry(Thread* thread, Handle store)
333 : _thread(thread), _store(store) {}
334
335 WeakHandle<vm_string_table_data> operator()() { // No dups found
336 WeakHandle<vm_string_table_data> wh =
337 WeakHandle<vm_string_table_data>::create(_store);
338 return wh;
339 }
340 void operator()(bool inserted, WeakHandle<vm_string_table_data>* val) {
341 oop result = val->resolve();
342 assert(result != NULL, "Result should be reachable");
343 _return = Handle(_thread, result);
344 }
345 oop get_return() const {
346 return _return();
347 }
348 };
349
350 oop StringTable::do_intern(Handle string_or_null_h, jchar* name,
351 int len, uintx hash, TRAPS) {
352 HandleMark hm(THREAD); // cleanup strings created
353 Handle string_h;
354
355 if (!string_or_null_h.is_null()) {
356 string_h = string_or_null_h;
357 } else {
358 string_h = java_lang_String::create_from_unicode(name, len, CHECK_NULL);
359 }
360
361 // Deduplicate the string before it is interned. Note that we should never
362 // deduplicate a string after it has been interned. Doing so will counteract
363 // compiler optimizations done on e.g. interned string literals.
364 Universe::heap()->deduplicate_string(string_h());
365
366 assert(java_lang_String::equals(string_h(), name, len),
367 "string must be properly initialized");
368 assert(len == java_lang_String::length(string_h()), "Must be same length");
369 StringTableLookupOop lookup(THREAD, hash, string_h);
370 StringTableCreateEntry stc(THREAD, string_h);
371
372 bool rehash_warning;
373 _local_table->get_insert_lazy(THREAD, lookup, stc, stc, &rehash_warning);
374 if (rehash_warning) {
375 _needs_rehashing = true;
376 }
377 return stc.get_return();
378 }
379
380 // GC support
381 class StringTableIsAliveCounter : public BoolObjectClosure {
382 BoolObjectClosure* _real_boc;
383 public:
384 size_t _count;
385 size_t _count_total;
386 StringTableIsAliveCounter(BoolObjectClosure* boc) : _real_boc(boc), _count(0),
387 _count_total(0) {}
388 bool do_object_b(oop obj) {
389 bool ret = _real_boc->do_object_b(obj);
390 if (!ret) {
391 ++_count;
392 }
393 ++_count_total;
394 return ret;
395 }
396 };
397
398 void StringTable::unlink_or_oops_do(BoolObjectClosure* is_alive, OopClosure* f,
399 int* processed, int* removed) {
400 DoNothingClosure dnc;
401 assert(is_alive != NULL, "No closure");
402 StringTableIsAliveCounter stiac(is_alive);
403 OopClosure* tmp = f != NULL ? f : &dnc;
404
405 StringTable::the_table()->_weak_handles->weak_oops_do(&stiac, tmp);
406
407 // This is the serial case without ParState.
408 // Just set the correct number and check for a cleaning phase.
409 the_table()->_uncleaned_items = stiac._count;
410 StringTable::the_table()->check_concurrent_work();
411
412 if (processed != NULL) {
413 *processed = (int) stiac._count_total;
414 }
415 if (removed != NULL) {
416 *removed = (int) stiac._count;
417 }
418 }
419
420 void StringTable::oops_do(OopClosure* f) {
421 assert(f != NULL, "No closure");
422 StringTable::the_table()->_weak_handles->oops_do(f);
423 }
424
425 void StringTable::possibly_parallel_unlink(
426 OopStorage::ParState<false, false>* _par_state_string, BoolObjectClosure* cl,
427 int* processed, int* removed)
428 {
429 DoNothingClosure dnc;
430 assert(cl != NULL, "No closure");
431 StringTableIsAliveCounter stiac(cl);
432
433 _par_state_string->weak_oops_do(&stiac, &dnc);
434
435 // Accumulate the dead strings.
436 the_table()->add_items_to_clean(stiac._count);
437
438 *processed = (int) stiac._count_total;
439 *removed = (int) stiac._count;
440 }
441
442 void StringTable::possibly_parallel_oops_do(
443 OopStorage::ParState<false /* concurrent */, false /* const */>*
444 _par_state_string, OopClosure* f)
445 {
446 assert(f != NULL, "No closure");
447 _par_state_string->oops_do(f);
448 }
449
450 // Concurrent work
451 void StringTable::grow(JavaThread* jt) {
452 StringTableHash::GrowTask gt(_local_table);
453 if (!gt.prepare(jt)) {
454 return;
455 }
456 log_trace(stringtable)("Started to grow");
457 {
458 TraceTime timer("Grow", TRACETIME_LOG(Debug, stringtable, perf));
459 while (gt.do_task(jt)) {
460 gt.pause(jt);
461 {
462 ThreadBlockInVM tbivm(jt);
463 }
464 gt.cont(jt);
465 }
466 }
467 gt.done(jt);
468 _current_size = table_size(jt);
469 log_debug(stringtable)("Grown to size:" SIZE_FORMAT, _current_size);
470 }
471
472 struct StringTableDoDelete : StackObj {
473 void operator()(WeakHandle<vm_string_table_data>* val) {
474 /* do nothing */
475 }
476 };
477
478 struct StringTableDeleteCheck : StackObj {
479 long _count;
480 long _item;
481 StringTableDeleteCheck() : _count(0), _item(0) {}
482 bool operator()(WeakHandle<vm_string_table_data>* val) {
483 ++_item;
484 oop tmp = val->peek();
485 if (tmp == NULL) {
486 ++_count;
487 return true;
488 } else {
489 return false;
490 }
491 }
492 };
493
494 void StringTable::clean_dead_entries(JavaThread* jt) {
495 StringTableHash::BulkDeleteTask bdt(_local_table);
496 if (!bdt.prepare(jt)) {
497 return;
498 }
499
500 StringTableDeleteCheck stdc;
501 StringTableDoDelete stdd;
502 {
503 TraceTime timer("Clean", TRACETIME_LOG(Debug, stringtable, perf));
504 while(bdt.do_task(jt, stdc, stdd)) {
505 bdt.pause(jt);
506 {
507 ThreadBlockInVM tbivm(jt);
508 }
509 bdt.cont(jt);
510 }
511 bdt.done(jt);
512 }
513 log_debug(stringtable)("Cleaned %ld of %ld", stdc._count, stdc._item);
514 }
515
516 void StringTable::check_concurrent_work() {
517 if (_has_work) {
518 return;
519 }
520
521 double load_factor = StringTable::get_load_factor();
522 double dead_factor = StringTable::get_dead_factor();
523 // We should clean/resize if we have more dead than alive,
524 // more items than preferred load factor or
525 // more dead items than water mark.
526 if ((dead_factor > load_factor) ||
527 (load_factor > PREF_AVG_LIST_LEN) ||
528 (dead_factor > CLEAN_DEAD_HIGH_WATER_MARK)) {
529 log_debug(stringtable)("Concurrent work triggered, live factor:%g dead factor:%g",
530 load_factor, dead_factor);
531 trigger_concurrent_work();
532 }
533 }
534
535 void StringTable::concurrent_work(JavaThread* jt) {
536 _has_work = false;
537 double load_factor = get_load_factor();
538 log_debug(stringtable, perf)("Concurrent work, live factor: %g", load_factor);
539 // We prefer growing, since that also removes dead items
540 if (load_factor > PREF_AVG_LIST_LEN && !_local_table->is_max_size_reached()) {
541 grow(jt);
542 } else {
543 clean_dead_entries(jt);
544 }
545 }
546
547 void StringTable::do_concurrent_work(JavaThread* jt) {
548 StringTable::the_table()->concurrent_work(jt);
549 }
550
551 // Rehash
552 bool StringTable::do_rehash() {
553 if (!_local_table->is_safepoint_safe()) {
554 return false;
555 }
556
557 // We use max size
558 StringTableHash* new_table = new StringTableHash(END_SIZE, END_SIZE, REHASH_LEN);
559 // Use alt hash from now on
560 _alt_hash = true;
561 if (!_local_table->try_move_nodes_to(Thread::current(), new_table)) {
562 _alt_hash = false;
563 delete new_table;
564 return false;
565 }
566
567 // free old table
568 delete _local_table;
569 _local_table = new_table;
570
571 return true;
572 }
573
574 void StringTable::try_rehash_table() {
575 static bool rehashed = false;
576 log_debug(stringtable)("Table imbalanced, rehashing called.");
577
578 // Grow instead of rehash.
579 if (get_load_factor() > PREF_AVG_LIST_LEN &&
580 !_local_table->is_max_size_reached()) {
581 log_debug(stringtable)("Choosing growing over rehashing.");
582 trigger_concurrent_work();
583 _needs_rehashing = false;
584 return;
585 }
586 // Already rehashed.
587 if (rehashed) {
588 log_warning(stringtable)("Rehashing already done, still long lists.");
589 trigger_concurrent_work();
590 _needs_rehashing = false;
591 return;
592 }
593
594 murmur_seed = AltHashing::compute_seed();
595 {
596 if (do_rehash()) {
597 rehashed = true;
598 } else {
599 log_info(stringtable)("Resizes in progress rehashing skipped.");
600 }
601 }
602 _needs_rehashing = false;
603 }
604
605 void StringTable::rehash_table() {
606 StringTable::the_table()->try_rehash_table();
607 }
608
609 // Statistics
610 static int literal_size(oop obj) {
611 // NOTE: this would over-count if (pre-JDK8)
612 // java_lang_Class::has_offset_field() is true and the String.value array is
613 // shared by several Strings. However, starting from JDK8, the String.value
614 // array is not shared anymore.
615 if (obj == NULL) {
616 return 0;
617 } else if (obj->klass() == SystemDictionary::String_klass()) {
618 return (obj->size() + java_lang_String::value(obj)->size()) * HeapWordSize;
619 } else {
620 return obj->size();
621 }
622 }
623
624 struct SizeFunc : StackObj {
625 size_t operator()(WeakHandle<vm_string_table_data>* val) {
626 oop s = val->peek();
627 if (s == NULL) {
628 // Dead
629 return 0;
630 }
631 return literal_size(s);
632 };
633 };
634
635 void StringTable::print_table_statistics(outputStream* st,
636 const char* table_name) {
637 SizeFunc sz;
638 _local_table->statistics_to(Thread::current(), sz, st, table_name);
639 }
640
641 // Verification
642 class VerifyStrings : StackObj {
643 public:
644 bool operator()(WeakHandle<vm_string_table_data>* val) {
645 oop s = val->peek();
646 if (s != NULL) {
647 assert(java_lang_String::length(s) >= 0, "Length on string must work.");
648 }
649 return true;
650 };
651 };
652
653 // This verification is part of Universe::verify() and needs to be quick.
654 void StringTable::verify() {
655 Thread* thr = Thread::current();
656 VerifyStrings vs;
657 if (!the_table()->_local_table->try_scan(thr, vs)) {
658 log_info(stringtable)("verify unavailable at this moment");
659 }
660 }
661
662 // Verification and comp
663 class VerifyCompStrings : StackObj {
664 GrowableArray<oop>* _oops;
665 public:
666 size_t _errors;
667 VerifyCompStrings(GrowableArray<oop>* oops) : _oops(oops), _errors(0) {}
668 bool operator()(WeakHandle<vm_string_table_data>* val) {
669 oop s = val->resolve();
670 if (s == NULL) {
671 return true;
672 }
673 int len = _oops->length();
674 for (int i = 0; i < len; i++) {
675 bool eq = java_lang_String::equals(s, _oops->at(i));
676 assert(!eq, "Duplicate strings");
677 if (eq) {
678 _errors++;
679 }
680 }
681 _oops->push(s);
682 return true;
683 };
684 };
685
686 size_t StringTable::verify_and_compare_entries() {
687 Thread* thr = Thread::current();
688 GrowableArray<oop>* oops =
689 new (ResourceObj::C_HEAP, mtInternal)
690 GrowableArray<oop>((int)the_table()->_current_size, true);
691
692 VerifyCompStrings vcs(oops);
693 if (!the_table()->_local_table->try_scan(thr, vcs)) {
694 log_info(stringtable)("verify unavailable at this moment");
695 }
696 delete oops;
697 return vcs._errors;
698 }
699
700 // Dumping
701 class PrintString : StackObj {
702 Thread* _thr;
703 outputStream* _st;
704 public:
705 PrintString(Thread* thr, outputStream* st) : _thr(thr), _st(st) {}
706 bool operator()(WeakHandle<vm_string_table_data>* val) {
707 oop s = val->peek();
708 if (s == NULL) {
709 return true;
710 }
711 typeArrayOop value = java_lang_String::value_no_keepalive(s);
712 int length = java_lang_String::length(s);
713 bool is_latin1 = java_lang_String::is_latin1(s);
714
715 if (length <= 0) {
716 _st->print("%d: ", length);
717 } else {
718 ResourceMark rm(_thr);
719 int utf8_length = length;
720 char* utf8_string;
721
722 if (!is_latin1) {
723 jchar* chars = value->char_at_addr(0);
724 utf8_string = UNICODE::as_utf8(chars, utf8_length);
725 } else {
726 jbyte* bytes = value->byte_at_addr(0);
727 utf8_string = UNICODE::as_utf8(bytes, utf8_length);
728 }
729
730 _st->print("%d: ", utf8_length);
731 HashtableTextDump::put_utf8(_st, utf8_string, utf8_length);
732 }
733 _st->cr();
734 return true;
735 };
736 };
737
738 void StringTable::dump(outputStream* st, bool verbose) {
739 if (!verbose) {
740 the_table()->print_table_statistics(st, "StringTable");
741 } else {
742 Thread* thr = Thread::current();
743 ResourceMark rm(thr);
744 st->print_cr("VERSION: 1.1");
745 PrintString ps(thr, st);
746 if (!the_table()->_local_table->try_scan(thr, ps)) {
747 st->print_cr("dump unavailable at this moment");
748 }
749 }
750 }
751
752 // Utility for dumping strings
753 StringtableDCmd::StringtableDCmd(outputStream* output, bool heap) :
754 DCmdWithParser(output, heap),
755 _verbose("-verbose", "Dump the content of each string in the table",
756 "BOOLEAN", false, "false") {
757 _dcmdparser.add_dcmd_option(&_verbose);
758 }
759
760 void StringtableDCmd::execute(DCmdSource source, TRAPS) {
761 VM_DumpHashtable dumper(output(), VM_DumpHashtable::DumpStrings,
762 _verbose.value());
763 VMThread::execute(&dumper);
764 }
765
766 int StringtableDCmd::num_arguments() {
767 ResourceMark rm;
768 StringtableDCmd* dcmd = new StringtableDCmd(NULL, false);
769 if (dcmd != NULL) {
770 DCmdMark mark(dcmd);
771 return dcmd->_dcmdparser.num_arguments();
772 } else {
773 return 0;
774 }
775 }
776
777 // Sharing
778 #if INCLUDE_CDS_JAVA_HEAP
779 oop StringTable::lookup_shared(jchar* name, int len, unsigned int hash) {
780 assert(hash == java_lang_String::hash_code(name, len),
781 "hash must be computed using java_lang_String::hash_code");
782 return _shared_table.lookup((const char*)name, hash, len);
783 }
784
785 oop StringTable::create_archived_string(oop s, Thread* THREAD) {
786 assert(DumpSharedSpaces, "this function is only used with -Xshare:dump");
787
788 oop new_s = NULL;
789 typeArrayOop v = java_lang_String::value_no_keepalive(s);
790 typeArrayOop new_v =
791 (typeArrayOop)MetaspaceShared::archive_heap_object(v, THREAD);
792 if (new_v == NULL) {
793 return NULL;
794 }
795 new_s = MetaspaceShared::archive_heap_object(s, THREAD);
796 if (new_s == NULL) {
797 return NULL;
798 }
799
800 // adjust the pointer to the 'value' field in the new String oop
801 java_lang_String::set_value_raw(new_s, new_v);
802 return new_s;
803 }
804
805 struct CopyToArchive : StackObj {
806 CompactStringTableWriter* _writer;
807 CopyToArchive(CompactStringTableWriter* writer) : _writer(writer) {}
808 bool operator()(WeakHandle<vm_string_table_data>* val) {
809 oop s = val->peek();
810 if (s == NULL) {
811 return true;
812 }
813 unsigned int hash = java_lang_String::hash_code(s);
814 if (hash == 0) {
815 return true;
816 }
817
818 java_lang_String::set_hash(s, hash);
819 oop new_s = StringTable::create_archived_string(s, Thread::current());
820 if (new_s == NULL) {
821 return true;
822 }
823
824 val->replace(new_s);
825 // add to the compact table
826 _writer->add(hash, new_s);
827 return true;
828 }
829 };
830
831 void StringTable::copy_shared_string_table(CompactStringTableWriter* writer) {
832 assert(MetaspaceShared::is_heap_object_archiving_allowed(), "must be");
833
834 CopyToArchive copy(writer);
835 StringTable::the_table()->_local_table->do_scan(Thread::current(), copy);
836 }
837
838 void StringTable::write_to_archive() {
839 assert(MetaspaceShared::is_heap_object_archiving_allowed(), "must be");
840
841 _shared_table.reset();
842 int num_buckets = the_table()->_items / SharedSymbolTableBucketSize;
843 // calculation of num_buckets can result in zero buckets, we need at least one
844 CompactStringTableWriter writer(num_buckets > 1 ? num_buckets : 1,
845 &MetaspaceShared::stats()->string);
846
847 // Copy the interned strings into the "string space" within the java heap
848 copy_shared_string_table(&writer);
849 writer.dump(&_shared_table);
850 }
851
852 void StringTable::serialize(SerializeClosure* soc) {
853 _shared_table.set_type(CompactHashtable<oop, char>::_string_table);
854 _shared_table.serialize(soc);
855
856 if (soc->writing()) {
857 // Sanity. Make sure we don't use the shared table at dump time
858 _shared_table.reset();
859 } else if (!_shared_string_mapped) {
860 _shared_table.reset();
861 }
862 }
863
864 void StringTable::shared_oops_do(OopClosure* f) {
865 _shared_table.oops_do(f);
866 }
867 #endif //INCLUDE_CDS_JAVA_HEAP
--- EOF ---