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