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