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