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.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 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 #if INCLUDE_CDS_JAVA_HEAP 66 inline oop read_string_from_compact_hashtable(address base_address, u4 offset) { 67 assert(sizeof(narrowOop) == sizeof(offset), "must be"); 68 narrowOop v = (narrowOop)offset; 69 return HeapShared::decode_from_archive(v); 70 } 71 72 static CompactHashtable< 73 const jchar*, oop, 74 read_string_from_compact_hashtable, 75 java_lang_String::equals 76 > _shared_table; 77 #endif 78 79 // -------------------------------------------------------------------------- 80 StringTable* StringTable::_the_table = NULL; 81 volatile bool StringTable::_shared_string_mapped = false; 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 size_t StringTable::item_added() { 211 return Atomic::add((size_t)1, &(the_table()->_items_count)); 212 } 213 214 size_t StringTable::add_items_count_to_clean(size_t ndead) { 215 size_t total = Atomic::add((size_t)ndead, &(the_table()->_uncleaned_items_count)); 216 log_trace(stringtable)( 217 "Uncleaned items:" SIZE_FORMAT " added: " SIZE_FORMAT " total:" SIZE_FORMAT, 218 the_table()->_uncleaned_items_count, ndead, total); 219 return total; 220 } 221 222 void StringTable::item_removed() { 223 Atomic::add((size_t)-1, &(the_table()->_items_count)); 224 } 225 226 double StringTable::get_load_factor() { 227 return (double)_items_count/_current_size; 228 } 229 230 double StringTable::get_dead_factor() { 231 return (double)_uncleaned_items_count/_current_size; 232 } 233 234 size_t StringTable::table_size() { 235 return ((size_t)1) << _local_table->get_size_log2(Thread::current()); 236 } 237 238 void StringTable::trigger_concurrent_work() { 239 MutexLockerEx ml(Service_lock, Mutex::_no_safepoint_check_flag); 240 the_table()->_has_work = true; 241 Service_lock->notify_all(); 242 } 243 244 // Probing 245 oop StringTable::lookup(Symbol* symbol) { 246 ResourceMark rm; 247 int length; 248 jchar* chars = symbol->as_unicode(length); 249 return lookup(chars, length); 250 } 251 252 oop StringTable::lookup(const jchar* name, int len) { 253 unsigned int hash = java_lang_String::hash_code(name, len); 254 oop string = StringTable::the_table()->lookup_shared(name, len, hash); 255 if (string != NULL) { 256 return string; 257 } 258 if (StringTable::_alt_hash) { 259 hash = hash_string(name, len, true); 260 } 261 return StringTable::the_table()->do_lookup(name, len, hash); 262 } 263 264 class StringTableGet : public StackObj { 265 Thread* _thread; 266 Handle _return; 267 public: 268 StringTableGet(Thread* thread) : _thread(thread) {} 269 void operator()(WeakHandle<vm_string_table_data>* val) { 270 oop result = val->resolve(); 271 assert(result != NULL, "Result should be reachable"); 272 _return = Handle(_thread, result); 273 } 274 oop get_res_oop() { 275 return _return(); 276 } 277 }; 278 279 oop StringTable::do_lookup(const jchar* name, int len, uintx hash) { 280 Thread* thread = Thread::current(); 281 StringTableLookupJchar lookup(thread, hash, name, len); 282 StringTableGet stg(thread); 283 bool rehash_warning; 284 _local_table->get(thread, lookup, stg, &rehash_warning); 285 if (rehash_warning) { 286 _needs_rehashing = true; 287 } 288 return stg.get_res_oop(); 289 } 290 291 // Interning 292 oop StringTable::intern(Symbol* symbol, TRAPS) { 293 if (symbol == NULL) return NULL; 294 ResourceMark rm(THREAD); 295 int length; 296 jchar* chars = symbol->as_unicode(length); 297 Handle string; 298 oop result = intern(string, chars, length, CHECK_NULL); 299 return result; 300 } 301 302 oop StringTable::intern(oop string, TRAPS) { 303 if (string == NULL) return NULL; 304 ResourceMark rm(THREAD); 305 int length; 306 Handle h_string (THREAD, string); 307 jchar* chars = java_lang_String::as_unicode_string(string, length, 308 CHECK_NULL); 309 oop result = intern(h_string, chars, length, CHECK_NULL); 310 return result; 311 } 312 313 oop StringTable::intern(const char* utf8_string, TRAPS) { 314 if (utf8_string == NULL) return NULL; 315 ResourceMark rm(THREAD); 316 int length = UTF8::unicode_length(utf8_string); 317 jchar* chars = NEW_RESOURCE_ARRAY(jchar, length); 318 UTF8::convert_to_unicode(utf8_string, chars, length); 319 Handle string; 320 oop result = intern(string, chars, length, CHECK_NULL); 321 return result; 322 } 323 324 oop StringTable::intern(Handle string_or_null_h, const jchar* name, int len, TRAPS) { 325 // shared table always uses java_lang_String::hash_code 326 unsigned int hash = java_lang_String::hash_code(name, len); 327 oop found_string = StringTable::the_table()->lookup_shared(name, len, hash); 328 if (found_string != NULL) { 329 return found_string; 330 } 331 if (StringTable::_alt_hash) { 332 hash = hash_string(name, len, true); 333 } 334 return StringTable::the_table()->do_intern(string_or_null_h, name, len, 335 hash, CHECK_NULL); 336 } 337 338 class StringTableCreateEntry : public StackObj { 339 private: 340 Thread* _thread; 341 Handle _return; 342 Handle _store; 343 public: 344 StringTableCreateEntry(Thread* thread, Handle store) 345 : _thread(thread), _store(store) {} 346 347 WeakHandle<vm_string_table_data> operator()() { // No dups found 348 WeakHandle<vm_string_table_data> wh = 349 WeakHandle<vm_string_table_data>::create(_store); 350 return wh; 351 } 352 void operator()(bool inserted, WeakHandle<vm_string_table_data>* val) { 353 oop result = val->resolve(); 354 assert(result != NULL, "Result should be reachable"); 355 _return = Handle(_thread, result); 356 } 357 oop get_return() const { 358 return _return(); 359 } 360 }; 361 362 oop StringTable::do_intern(Handle string_or_null_h, const jchar* name, 363 int len, uintx hash, TRAPS) { 364 HandleMark hm(THREAD); // cleanup strings created 365 Handle string_h; 366 367 if (!string_or_null_h.is_null()) { 368 string_h = string_or_null_h; 369 } else { 370 string_h = java_lang_String::create_from_unicode(name, len, CHECK_NULL); 371 } 372 373 // Deduplicate the string before it is interned. Note that we should never 374 // deduplicate a string after it has been interned. Doing so will counteract 375 // compiler optimizations done on e.g. interned string literals. 376 Universe::heap()->deduplicate_string(string_h()); 377 378 assert(java_lang_String::equals(string_h(), name, len), 379 "string must be properly initialized"); 380 assert(len == java_lang_String::length(string_h()), "Must be same length"); 381 StringTableLookupOop lookup(THREAD, hash, string_h); 382 StringTableCreateEntry stc(THREAD, string_h); 383 384 bool rehash_warning; 385 _local_table->get_insert_lazy(THREAD, lookup, stc, stc, &rehash_warning); 386 if (rehash_warning) { 387 _needs_rehashing = true; 388 } 389 return stc.get_return(); 390 } 391 392 // GC support 393 class StringTableIsAliveCounter : public BoolObjectClosure { 394 BoolObjectClosure* _real_boc; 395 public: 396 size_t _count; 397 size_t _count_total; 398 StringTableIsAliveCounter(BoolObjectClosure* boc) : _real_boc(boc), _count(0), 399 _count_total(0) {} 400 bool do_object_b(oop obj) { 401 bool ret = _real_boc->do_object_b(obj); 402 if (!ret) { 403 ++_count; 404 } 405 ++_count_total; 406 return ret; 407 } 408 }; 409 410 void StringTable::unlink_or_oops_do(BoolObjectClosure* is_alive, OopClosure* f, 411 size_t* processed, size_t* removed) { 412 DoNothingClosure dnc; 413 assert(is_alive != NULL, "No closure"); 414 StringTableIsAliveCounter stiac(is_alive); 415 OopClosure* tmp = f != NULL ? f : &dnc; 416 417 StringTable::the_table()->_weak_handles->weak_oops_do(&stiac, tmp); 418 419 // This is the serial case without ParState. 420 // Just set the correct number and check for a cleaning phase. 421 the_table()->_uncleaned_items_count = stiac._count; 422 StringTable::the_table()->check_concurrent_work(); 423 424 if (processed != NULL) { 425 *processed = stiac._count_total; 426 } 427 if (removed != NULL) { 428 *removed = stiac._count; 429 } 430 } 431 432 void StringTable::oops_do(OopClosure* f) { 433 assert(f != NULL, "No closure"); 434 StringTable::the_table()->_weak_handles->oops_do(f); 435 } 436 437 void StringTable::possibly_parallel_unlink( 438 OopStorage::ParState<false, false>* _par_state_string, BoolObjectClosure* cl, 439 size_t* processed, size_t* removed) 440 { 441 DoNothingClosure dnc; 442 assert(cl != NULL, "No closure"); 443 StringTableIsAliveCounter stiac(cl); 444 445 _par_state_string->weak_oops_do(&stiac, &dnc); 446 447 // Accumulate the dead strings. 448 the_table()->add_items_count_to_clean(stiac._count); 449 450 *processed = stiac._count_total; 451 *removed = stiac._count; 452 } 453 454 void StringTable::possibly_parallel_oops_do( 455 OopStorage::ParState<false /* concurrent */, false /* const */>* 456 _par_state_string, OopClosure* f) 457 { 458 assert(f != NULL, "No closure"); 459 _par_state_string->oops_do(f); 460 } 461 462 // Concurrent work 463 void StringTable::grow(JavaThread* jt) { 464 StringTableHash::GrowTask gt(_local_table); 465 if (!gt.prepare(jt)) { 466 return; 467 } 468 log_trace(stringtable)("Started to grow"); 469 { 470 TraceTime timer("Grow", TRACETIME_LOG(Debug, stringtable, perf)); 471 while (gt.do_task(jt)) { 472 gt.pause(jt); 473 { 474 ThreadBlockInVM tbivm(jt); 475 } 476 gt.cont(jt); 477 } 478 } 479 gt.done(jt); 480 _current_size = table_size(); 481 log_debug(stringtable)("Grown to size:" SIZE_FORMAT, _current_size); 482 } 483 484 struct StringTableDoDelete : StackObj { 485 void operator()(WeakHandle<vm_string_table_data>* val) { 486 /* do nothing */ 487 } 488 }; 489 490 struct StringTableDeleteCheck : StackObj { 491 long _count; 492 long _item; 493 StringTableDeleteCheck() : _count(0), _item(0) {} 494 bool operator()(WeakHandle<vm_string_table_data>* val) { 495 ++_item; 496 oop tmp = val->peek(); 497 if (tmp == NULL) { 498 ++_count; 499 return true; 500 } else { 501 return false; 502 } 503 } 504 }; 505 506 void StringTable::clean_dead_entries(JavaThread* jt) { 507 StringTableHash::BulkDeleteTask bdt(_local_table); 508 if (!bdt.prepare(jt)) { 509 return; 510 } 511 512 StringTableDeleteCheck stdc; 513 StringTableDoDelete stdd; 514 { 515 TraceTime timer("Clean", TRACETIME_LOG(Debug, stringtable, perf)); 516 while(bdt.do_task(jt, stdc, stdd)) { 517 bdt.pause(jt); 518 { 519 ThreadBlockInVM tbivm(jt); 520 } 521 bdt.cont(jt); 522 } 523 bdt.done(jt); 524 } 525 log_debug(stringtable)("Cleaned %ld of %ld", stdc._count, stdc._item); 526 } 527 528 void StringTable::check_concurrent_work() { 529 if (_has_work) { 530 return; 531 } 532 533 double load_factor = StringTable::get_load_factor(); 534 double dead_factor = StringTable::get_dead_factor(); 535 // We should clean/resize if we have more dead than alive, 536 // more items than preferred load factor or 537 // more dead items than water mark. 538 if ((dead_factor > load_factor) || 539 (load_factor > PREF_AVG_LIST_LEN) || 540 (dead_factor > CLEAN_DEAD_HIGH_WATER_MARK)) { 541 log_debug(stringtable)("Concurrent work triggered, live factor:%g dead factor:%g", 542 load_factor, dead_factor); 543 trigger_concurrent_work(); 544 } 545 } 546 547 void StringTable::concurrent_work(JavaThread* jt) { 548 _has_work = false; 549 double load_factor = get_load_factor(); 550 log_debug(stringtable, perf)("Concurrent work, live factor: %g", load_factor); 551 // We prefer growing, since that also removes dead items 552 if (load_factor > PREF_AVG_LIST_LEN && !_local_table->is_max_size_reached()) { 553 grow(jt); 554 } else { 555 clean_dead_entries(jt); 556 } 557 } 558 559 void StringTable::do_concurrent_work(JavaThread* jt) { 560 StringTable::the_table()->concurrent_work(jt); 561 } 562 563 // Rehash 564 bool StringTable::do_rehash() { 565 if (!_local_table->is_safepoint_safe()) { 566 return false; 567 } 568 569 // We use max size 570 StringTableHash* new_table = new StringTableHash(END_SIZE, END_SIZE, REHASH_LEN); 571 // Use alt hash from now on 572 _alt_hash = true; 573 if (!_local_table->try_move_nodes_to(Thread::current(), new_table)) { 574 _alt_hash = false; 575 delete new_table; 576 return false; 577 } 578 579 // free old table 580 delete _local_table; 581 _local_table = new_table; 582 583 return true; 584 } 585 586 void StringTable::try_rehash_table() { 587 static bool rehashed = false; 588 log_debug(stringtable)("Table imbalanced, rehashing called."); 589 590 // Grow instead of rehash. 591 if (get_load_factor() > PREF_AVG_LIST_LEN && 592 !_local_table->is_max_size_reached()) { 593 log_debug(stringtable)("Choosing growing over rehashing."); 594 trigger_concurrent_work(); 595 _needs_rehashing = false; 596 return; 597 } 598 // Already rehashed. 599 if (rehashed) { 600 log_warning(stringtable)("Rehashing already done, still long lists."); 601 trigger_concurrent_work(); 602 _needs_rehashing = false; 603 return; 604 } 605 606 murmur_seed = AltHashing::compute_seed(); 607 { 608 if (do_rehash()) { 609 rehashed = true; 610 } else { 611 log_info(stringtable)("Resizes in progress rehashing skipped."); 612 } 613 } 614 _needs_rehashing = false; 615 } 616 617 void StringTable::rehash_table() { 618 StringTable::the_table()->try_rehash_table(); 619 } 620 621 // Statistics 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 : StackObj { 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 // Verification 654 class VerifyStrings : StackObj { 655 public: 656 bool operator()(WeakHandle<vm_string_table_data>* val) { 657 oop s = val->peek(); 658 if (s != NULL) { 659 assert(java_lang_String::length(s) >= 0, "Length on string must work."); 660 } 661 return true; 662 }; 663 }; 664 665 // This verification is part of Universe::verify() and needs to be quick. 666 void StringTable::verify() { 667 Thread* thr = Thread::current(); 668 VerifyStrings vs; 669 if (!the_table()->_local_table->try_scan(thr, vs)) { 670 log_info(stringtable)("verify unavailable at this moment"); 671 } 672 } 673 674 // Verification and comp 675 class VerifyCompStrings : StackObj { 676 GrowableArray<oop>* _oops; 677 public: 678 size_t _errors; 679 VerifyCompStrings(GrowableArray<oop>* oops) : _oops(oops), _errors(0) {} 680 bool operator()(WeakHandle<vm_string_table_data>* val) { 681 oop s = val->resolve(); 682 if (s == NULL) { 683 return true; 684 } 685 int len = _oops->length(); 686 for (int i = 0; i < len; i++) { 687 bool eq = java_lang_String::equals(s, _oops->at(i)); 688 assert(!eq, "Duplicate strings"); 689 if (eq) { 690 _errors++; 691 } 692 } 693 _oops->push(s); 694 return true; 695 }; 696 }; 697 698 size_t StringTable::verify_and_compare_entries() { 699 Thread* thr = Thread::current(); 700 GrowableArray<oop>* oops = 701 new (ResourceObj::C_HEAP, mtInternal) 702 GrowableArray<oop>((int)the_table()->_current_size, true); 703 704 VerifyCompStrings vcs(oops); 705 if (!the_table()->_local_table->try_scan(thr, vcs)) { 706 log_info(stringtable)("verify unavailable at this moment"); 707 } 708 delete oops; 709 return vcs._errors; 710 } 711 712 // Dumping 713 class PrintString : StackObj { 714 Thread* _thr; 715 outputStream* _st; 716 public: 717 PrintString(Thread* thr, outputStream* st) : _thr(thr), _st(st) {} 718 bool operator()(WeakHandle<vm_string_table_data>* val) { 719 oop s = val->peek(); 720 if (s == NULL) { 721 return true; 722 } 723 typeArrayOop value = java_lang_String::value_no_keepalive(s); 724 int length = java_lang_String::length(s); 725 bool is_latin1 = java_lang_String::is_latin1(s); 726 727 if (length <= 0) { 728 _st->print("%d: ", length); 729 } else { 730 ResourceMark rm(_thr); 731 int utf8_length = length; 732 char* utf8_string; 733 734 if (!is_latin1) { 735 jchar* chars = value->char_at_addr(0); 736 utf8_string = UNICODE::as_utf8(chars, utf8_length); 737 } else { 738 jbyte* bytes = value->byte_at_addr(0); 739 utf8_string = UNICODE::as_utf8(bytes, utf8_length); 740 } 741 742 _st->print("%d: ", utf8_length); 743 HashtableTextDump::put_utf8(_st, utf8_string, utf8_length); 744 } 745 _st->cr(); 746 return true; 747 }; 748 }; 749 750 void StringTable::dump(outputStream* st, bool verbose) { 751 if (!verbose) { 752 the_table()->print_table_statistics(st, "StringTable"); 753 } else { 754 Thread* thr = Thread::current(); 755 ResourceMark rm(thr); 756 st->print_cr("VERSION: 1.1"); 757 PrintString ps(thr, st); 758 if (!the_table()->_local_table->try_scan(thr, ps)) { 759 st->print_cr("dump unavailable at this moment"); 760 } 761 } 762 } 763 764 // Utility for dumping strings 765 StringtableDCmd::StringtableDCmd(outputStream* output, bool heap) : 766 DCmdWithParser(output, heap), 767 _verbose("-verbose", "Dump the content of each string in the table", 768 "BOOLEAN", false, "false") { 769 _dcmdparser.add_dcmd_option(&_verbose); 770 } 771 772 void StringtableDCmd::execute(DCmdSource source, TRAPS) { 773 VM_DumpHashtable dumper(output(), VM_DumpHashtable::DumpStrings, 774 _verbose.value()); 775 VMThread::execute(&dumper); 776 } 777 778 int StringtableDCmd::num_arguments() { 779 ResourceMark rm; 780 StringtableDCmd* dcmd = new StringtableDCmd(NULL, false); 781 if (dcmd != NULL) { 782 DCmdMark mark(dcmd); 783 return dcmd->_dcmdparser.num_arguments(); 784 } else { 785 return 0; 786 } 787 } 788 789 // Sharing 790 #if INCLUDE_CDS_JAVA_HEAP 791 oop StringTable::lookup_shared(const jchar* name, int len, unsigned int hash) { 792 assert(hash == java_lang_String::hash_code(name, len), 793 "hash must be computed using java_lang_String::hash_code"); 794 return _shared_table.lookup(name, hash, len); 795 } 796 797 oop StringTable::create_archived_string(oop s, Thread* THREAD) { 798 assert(DumpSharedSpaces, "this function is only used with -Xshare:dump"); 799 800 if (HeapShared::is_archived_object(s)) { 801 return s; 802 } 803 804 oop new_s = NULL; 805 typeArrayOop v = java_lang_String::value_no_keepalive(s); 806 typeArrayOop new_v = (typeArrayOop)HeapShared::archive_heap_object(v, THREAD); 807 if (new_v == NULL) { 808 return NULL; 809 } 810 new_s = HeapShared::archive_heap_object(s, THREAD); 811 if (new_s == NULL) { 812 return NULL; 813 } 814 815 // adjust the pointer to the 'value' field in the new String oop 816 java_lang_String::set_value_raw(new_s, new_v); 817 return new_s; 818 } 819 820 class CompactStringTableWriter: public CompactHashtableWriter { 821 public: 822 CompactStringTableWriter(int num_entries, CompactHashtableStats* stats) : 823 CompactHashtableWriter(num_entries, stats) {} 824 void add(unsigned int hash, oop string) { 825 CompactHashtableWriter::add(hash, CompressedOops::encode(string)); 826 } 827 }; 828 829 struct CopyToArchive : StackObj { 830 CompactStringTableWriter* _writer; 831 CopyToArchive(CompactStringTableWriter* writer) : _writer(writer) {} 832 bool operator()(WeakHandle<vm_string_table_data>* val) { 833 oop s = val->peek(); 834 if (s == NULL) { 835 return true; 836 } 837 unsigned int hash = java_lang_String::hash_code(s); 838 if (hash == 0) { 839 return true; 840 } 841 842 java_lang_String::set_hash(s, hash); 843 oop new_s = StringTable::create_archived_string(s, Thread::current()); 844 if (new_s == NULL) { 845 return true; 846 } 847 848 val->replace(new_s); 849 // add to the compact table 850 _writer->add(hash, new_s); 851 return true; 852 } 853 }; 854 855 void StringTable::copy_shared_string_table(CompactStringTableWriter* writer) { 856 assert(HeapShared::is_heap_object_archiving_allowed(), "must be"); 857 858 CopyToArchive copy(writer); 859 StringTable::the_table()->_local_table->do_scan(Thread::current(), copy); 860 } 861 862 void StringTable::write_to_archive() { 863 assert(HeapShared::is_heap_object_archiving_allowed(), "must be"); 864 865 _shared_table.reset(); 866 int num_buckets = the_table()->_items_count / SharedSymbolTableBucketSize; 867 // calculation of num_buckets can result in zero buckets, we need at least one 868 CompactStringTableWriter writer(num_buckets > 1 ? num_buckets : 1, 869 &MetaspaceShared::stats()->string); 870 871 // Copy the interned strings into the "string space" within the java heap 872 copy_shared_string_table(&writer); 873 writer.dump(&_shared_table, "string"); 874 } 875 876 void StringTable::serialize(SerializeClosure* soc) { 877 _shared_table.serialize(soc); 878 879 if (soc->writing()) { 880 // Sanity. Make sure we don't use the shared table at dump time 881 _shared_table.reset(); 882 } else if (!_shared_string_mapped) { 883 _shared_table.reset(); 884 } 885 } 886 887 class SharedStringIterator { 888 OopClosure* _oop_closure; 889 public: 890 SharedStringIterator(OopClosure* f) : _oop_closure(f) {} 891 void do_value(oop string) { 892 _oop_closure->do_oop(&string); 893 } 894 }; 895 896 void StringTable::shared_oops_do(OopClosure* f) { 897 SharedStringIterator iter(f); 898 _shared_table.iterate(&iter); 899 } 900 #endif //INCLUDE_CDS_JAVA_HEAP