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