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