1 /* 2 * Copyright (c) 1997, 2024, 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 "cds/archiveBuilder.hpp" 27 #include "cds/archiveHeapLoader.inline.hpp" 28 #include "cds/archiveHeapWriter.hpp" 29 #include "cds/cdsConfig.hpp" 30 #include "cds/filemap.hpp" 31 #include "cds/heapShared.hpp" 32 #include "classfile/altHashing.hpp" 33 #include "classfile/compactHashtable.hpp" 34 #include "classfile/javaClasses.inline.hpp" 35 #include "classfile/stringTable.hpp" 36 #include "classfile/vmClasses.hpp" 37 #include "gc/shared/collectedHeap.hpp" 38 #include "gc/shared/oopStorage.inline.hpp" 39 #include "gc/shared/oopStorageSet.hpp" 40 #include "gc/shared/stringdedup/stringDedup.hpp" 41 #include "logging/log.hpp" 42 #include "logging/logStream.hpp" 43 #include "memory/allocation.inline.hpp" 44 #include "memory/oopFactory.hpp" 45 #include "memory/resourceArea.hpp" 46 #include "oops/access.inline.hpp" 47 #include "oops/compressedOops.hpp" 48 #include "oops/oop.inline.hpp" 49 #include "oops/typeArrayOop.inline.hpp" 50 #include "oops/weakHandle.inline.hpp" 51 #include "runtime/atomic.hpp" 52 #include "runtime/handles.inline.hpp" 53 #include "runtime/interfaceSupport.inline.hpp" 54 #include "runtime/mutexLocker.hpp" 55 #include "runtime/safepointVerifiers.hpp" 56 #include "runtime/timerTrace.hpp" 57 #include "runtime/trimNativeHeap.hpp" 58 #include "runtime/vmOperations.hpp" 59 #include "services/diagnosticCommand.hpp" 60 #include "utilities/concurrentHashTable.inline.hpp" 61 #include "utilities/concurrentHashTableTasks.inline.hpp" 62 #include "utilities/macros.hpp" 63 #include "utilities/resizeableResourceHash.hpp" 64 #include "utilities/utf8.hpp" 65 #if INCLUDE_G1GC 66 #include "gc/g1/g1CollectedHeap.hpp" 67 #endif 68 69 // We prefer short chains of avg 2 70 const double PREF_AVG_LIST_LEN = 2.0; 71 // 2^24 is max size 72 const size_t END_SIZE = 24; 73 // If a chain gets to 100 something might be wrong 74 const size_t REHASH_LEN = 100; 75 // If we have as many dead items as 50% of the number of bucket 76 const double CLEAN_DEAD_HIGH_WATER_MARK = 0.5; 77 78 #if INCLUDE_CDS_JAVA_HEAP 79 bool StringTable::_is_two_dimensional_shared_strings_array = false; 80 OopHandle StringTable::_shared_strings_array; 81 int StringTable::_shared_strings_array_root_index; 82 83 inline oop StringTable::read_string_from_compact_hashtable(address base_address, u4 index) { 84 assert(ArchiveHeapLoader::is_in_use(), "sanity"); 85 objArrayOop array = (objArrayOop)(_shared_strings_array.resolve()); 86 oop s; 87 88 if (!_is_two_dimensional_shared_strings_array) { 89 s = array->obj_at((int)index); 90 } else { 91 int primary_index = index >> _secondary_array_index_bits; 92 int secondary_index = index & _secondary_array_index_mask; 93 objArrayOop secondary = (objArrayOop)array->obj_at(primary_index); 94 s = secondary->obj_at(secondary_index); 95 } 96 97 assert(java_lang_String::is_instance(s), "must be"); 98 return s; 99 } 100 101 typedef CompactHashtable< 102 const jchar*, oop, 103 StringTable::read_string_from_compact_hashtable, 104 java_lang_String::equals> SharedStringTable; 105 106 static SharedStringTable _shared_table; 107 #endif 108 109 // -------------------------------------------------------------------------- 110 111 typedef ConcurrentHashTable<StringTableConfig, mtSymbol> StringTableHash; 112 static StringTableHash* _local_table = nullptr; 113 114 volatile bool StringTable::_has_work = false; 115 volatile bool StringTable::_needs_rehashing = false; 116 OopStorage* StringTable::_oop_storage; 117 118 static size_t _current_size = 0; 119 static volatile size_t _items_count = 0; 120 121 volatile bool _alt_hash = false; 122 123 static bool _rehashed = false; 124 static uint64_t _alt_hash_seed = 0; 125 126 static unsigned int hash_string(const jchar* s, int len, bool useAlt) { 127 return useAlt ? 128 AltHashing::halfsiphash_32(_alt_hash_seed, s, len) : 129 java_lang_String::hash_code(s, len); 130 } 131 132 class StringTableConfig : public StackObj { 133 private: 134 public: 135 typedef WeakHandle Value; 136 137 static uintx get_hash(Value const& value, bool* is_dead) { 138 oop val_oop = value.peek(); 139 if (val_oop == nullptr) { 140 *is_dead = true; 141 return 0; 142 } 143 *is_dead = false; 144 ResourceMark rm; 145 // All String oops are hashed as unicode 146 int length; 147 jchar* chars = java_lang_String::as_unicode_string_or_null(val_oop, length); 148 if (chars != nullptr) { 149 return hash_string(chars, length, _alt_hash); 150 } 151 vm_exit_out_of_memory(length, OOM_MALLOC_ERROR, "get hash from oop"); 152 return 0; 153 } 154 // We use default allocation/deallocation but counted 155 static void* allocate_node(void* context, size_t size, Value const& value) { 156 StringTable::item_added(); 157 return AllocateHeap(size, mtSymbol); 158 } 159 static void free_node(void* context, void* memory, Value& value) { 160 value.release(StringTable::_oop_storage); 161 FreeHeap(memory); 162 StringTable::item_removed(); 163 } 164 }; 165 166 class StringTableLookupJchar : StackObj { 167 private: 168 Thread* _thread; 169 uintx _hash; 170 int _len; 171 const jchar* _str; 172 Handle _found; 173 174 public: 175 StringTableLookupJchar(Thread* thread, uintx hash, const jchar* key, int len) 176 : _thread(thread), _hash(hash), _len(len), _str(key) { 177 } 178 uintx get_hash() const { 179 return _hash; 180 } 181 bool equals(WeakHandle* value) { 182 oop val_oop = value->peek(); 183 if (val_oop == nullptr) { 184 return false; 185 } 186 bool equals = java_lang_String::equals(val_oop, _str, _len); 187 if (!equals) { 188 return false; 189 } 190 // Need to resolve weak handle and Handleize through possible safepoint. 191 _found = Handle(_thread, value->resolve()); 192 return true; 193 } 194 bool is_dead(WeakHandle* value) { 195 oop val_oop = value->peek(); 196 return val_oop == nullptr; 197 } 198 }; 199 200 class StringTableLookupOop : public StackObj { 201 private: 202 Thread* _thread; 203 uintx _hash; 204 Handle _find; 205 Handle _found; // Might be a different oop with the same value that's already 206 // in the table, which is the point. 207 public: 208 StringTableLookupOop(Thread* thread, uintx hash, Handle handle) 209 : _thread(thread), _hash(hash), _find(handle) { } 210 211 uintx get_hash() const { 212 return _hash; 213 } 214 215 bool equals(WeakHandle* value) { 216 oop val_oop = value->peek(); 217 if (val_oop == nullptr) { 218 return false; 219 } 220 bool equals = java_lang_String::equals(_find(), val_oop); 221 if (!equals) { 222 return false; 223 } 224 // Need to resolve weak handle and Handleize through possible safepoint. 225 _found = Handle(_thread, value->resolve()); 226 return true; 227 } 228 229 bool is_dead(WeakHandle* value) { 230 oop val_oop = value->peek(); 231 return val_oop == nullptr; 232 } 233 }; 234 235 void StringTable::create_table() { 236 size_t start_size_log_2 = ceil_log2(StringTableSize); 237 _current_size = ((size_t)1) << start_size_log_2; 238 log_trace(stringtable)("Start size: " SIZE_FORMAT " (" SIZE_FORMAT ")", 239 _current_size, start_size_log_2); 240 _local_table = new StringTableHash(start_size_log_2, END_SIZE, REHASH_LEN, true); 241 _oop_storage = OopStorageSet::create_weak("StringTable Weak", mtSymbol); 242 _oop_storage->register_num_dead_callback(&gc_notification); 243 244 #if INCLUDE_CDS_JAVA_HEAP 245 if (ArchiveHeapLoader::is_in_use()) { 246 _shared_strings_array = OopHandle(Universe::vm_global(), HeapShared::get_root(_shared_strings_array_root_index)); 247 } 248 #endif 249 } 250 251 void StringTable::item_added() { 252 Atomic::inc(&_items_count); 253 } 254 255 void StringTable::item_removed() { 256 Atomic::dec(&_items_count); 257 } 258 259 double StringTable::get_load_factor() { 260 return double(_items_count)/double(_current_size); 261 } 262 263 double StringTable::get_dead_factor(size_t num_dead) { 264 return double(num_dead)/double(_current_size); 265 } 266 267 size_t StringTable::table_size() { 268 return ((size_t)1) << _local_table->get_size_log2(Thread::current()); 269 } 270 271 bool StringTable::has_work() { 272 return Atomic::load_acquire(&_has_work); 273 } 274 275 void StringTable::trigger_concurrent_work() { 276 // Avoid churn on ServiceThread 277 if (!has_work()) { 278 MutexLocker ml(Service_lock, Mutex::_no_safepoint_check_flag); 279 Atomic::store(&_has_work, true); 280 Service_lock->notify_all(); 281 } 282 } 283 284 // Probing 285 oop StringTable::lookup(Symbol* symbol) { 286 ResourceMark rm; 287 int length; 288 jchar* chars = symbol->as_unicode(length); 289 return lookup(chars, length); 290 } 291 292 oop StringTable::lookup(const jchar* name, int len) { 293 unsigned int hash = java_lang_String::hash_code(name, len); 294 oop string = lookup_shared(name, len, hash); 295 if (string != nullptr) { 296 return string; 297 } 298 if (_alt_hash) { 299 hash = hash_string(name, len, true); 300 } 301 return do_lookup(name, len, hash); 302 } 303 304 class StringTableGet : public StackObj { 305 Thread* _thread; 306 Handle _return; 307 public: 308 StringTableGet(Thread* thread) : _thread(thread) {} 309 void operator()(WeakHandle* val) { 310 oop result = val->resolve(); 311 assert(result != nullptr, "Result should be reachable"); 312 _return = Handle(_thread, result); 313 } 314 oop get_res_oop() { 315 return _return(); 316 } 317 }; 318 319 void StringTable::update_needs_rehash(bool rehash) { 320 if (rehash) { 321 _needs_rehashing = true; 322 trigger_concurrent_work(); 323 } 324 } 325 326 oop StringTable::do_lookup(const jchar* name, int len, uintx hash) { 327 Thread* thread = Thread::current(); 328 StringTableLookupJchar lookup(thread, hash, name, len); 329 StringTableGet stg(thread); 330 bool rehash_warning; 331 _local_table->get(thread, lookup, stg, &rehash_warning); 332 update_needs_rehash(rehash_warning); 333 return stg.get_res_oop(); 334 } 335 336 // Interning 337 oop StringTable::intern(Symbol* symbol, TRAPS) { 338 if (symbol == nullptr) return nullptr; 339 ResourceMark rm(THREAD); 340 int length; 341 jchar* chars = symbol->as_unicode(length); 342 Handle string; 343 oop result = intern(string, chars, length, CHECK_NULL); 344 return result; 345 } 346 347 oop StringTable::intern(oop string, TRAPS) { 348 if (string == nullptr) return nullptr; 349 ResourceMark rm(THREAD); 350 int length; 351 Handle h_string (THREAD, string); 352 jchar* chars = java_lang_String::as_unicode_string(string, length, 353 CHECK_NULL); 354 oop result = intern(h_string, chars, length, CHECK_NULL); 355 return result; 356 } 357 358 oop StringTable::intern(const char* utf8_string, TRAPS) { 359 if (utf8_string == nullptr) return nullptr; 360 ResourceMark rm(THREAD); 361 int length = UTF8::unicode_length(utf8_string); 362 jchar* chars = NEW_RESOURCE_ARRAY(jchar, length); 363 UTF8::convert_to_unicode(utf8_string, chars, length); 364 Handle string; 365 oop result = intern(string, chars, length, CHECK_NULL); 366 return result; 367 } 368 369 oop StringTable::intern(Handle string_or_null_h, const jchar* name, int len, TRAPS) { 370 // shared table always uses java_lang_String::hash_code 371 unsigned int hash = java_lang_String::hash_code(name, len); 372 oop found_string = lookup_shared(name, len, hash); 373 if (found_string != nullptr) { 374 return found_string; 375 } 376 if (_alt_hash) { 377 hash = hash_string(name, len, true); 378 } 379 found_string = do_lookup(name, len, hash); 380 if (found_string != nullptr) { 381 return found_string; 382 } 383 return do_intern(string_or_null_h, name, len, hash, THREAD); 384 } 385 386 oop StringTable::do_intern(Handle string_or_null_h, const jchar* name, 387 int len, uintx hash, TRAPS) { 388 HandleMark hm(THREAD); // cleanup strings created 389 Handle string_h; 390 391 if (!string_or_null_h.is_null()) { 392 string_h = string_or_null_h; 393 } else { 394 string_h = java_lang_String::create_from_unicode(name, len, CHECK_NULL); 395 } 396 397 assert(java_lang_String::equals(string_h(), name, len), 398 "string must be properly initialized"); 399 assert(len == java_lang_String::length(string_h()), "Must be same length"); 400 401 // Notify deduplication support that the string is being interned. A string 402 // must never be deduplicated after it has been interned. Doing so interferes 403 // with compiler optimizations done on e.g. interned string literals. 404 if (StringDedup::is_enabled()) { 405 StringDedup::notify_intern(string_h()); 406 } 407 408 StringTableLookupOop lookup(THREAD, hash, string_h); 409 StringTableGet stg(THREAD); 410 411 bool rehash_warning; 412 do { 413 // Callers have already looked up the String using the jchar* name, so just go to add. 414 WeakHandle wh(_oop_storage, string_h); 415 // The hash table takes ownership of the WeakHandle, even if it's not inserted. 416 if (_local_table->insert(THREAD, lookup, wh, &rehash_warning)) { 417 update_needs_rehash(rehash_warning); 418 return wh.resolve(); 419 } 420 // In case another thread did a concurrent add, return value already in the table. 421 // This could fail if the String got gc'ed concurrently, so loop back until success. 422 if (_local_table->get(THREAD, lookup, stg, &rehash_warning)) { 423 update_needs_rehash(rehash_warning); 424 return stg.get_res_oop(); 425 } 426 } while(true); 427 } 428 429 // Concurrent work 430 void StringTable::grow(JavaThread* jt) { 431 StringTableHash::GrowTask gt(_local_table); 432 if (!gt.prepare(jt)) { 433 return; 434 } 435 log_trace(stringtable)("Started to grow"); 436 { 437 TraceTime timer("Grow", TRACETIME_LOG(Debug, stringtable, perf)); 438 while (gt.do_task(jt)) { 439 gt.pause(jt); 440 { 441 ThreadBlockInVM tbivm(jt); 442 } 443 gt.cont(jt); 444 } 445 } 446 gt.done(jt); 447 _current_size = table_size(); 448 log_debug(stringtable)("Grown to size:" SIZE_FORMAT, _current_size); 449 } 450 451 struct StringTableDoDelete : StackObj { 452 void operator()(WeakHandle* val) { 453 /* do nothing */ 454 } 455 }; 456 457 struct StringTableDeleteCheck : StackObj { 458 long _count; 459 long _item; 460 StringTableDeleteCheck() : _count(0), _item(0) {} 461 bool operator()(WeakHandle* val) { 462 ++_item; 463 oop tmp = val->peek(); 464 if (tmp == nullptr) { 465 ++_count; 466 return true; 467 } else { 468 return false; 469 } 470 } 471 }; 472 473 void StringTable::clean_dead_entries(JavaThread* jt) { 474 StringTableHash::BulkDeleteTask bdt(_local_table); 475 if (!bdt.prepare(jt)) { 476 return; 477 } 478 479 StringTableDeleteCheck stdc; 480 StringTableDoDelete stdd; 481 NativeHeapTrimmer::SuspendMark sm("stringtable"); 482 { 483 TraceTime timer("Clean", TRACETIME_LOG(Debug, stringtable, perf)); 484 while(bdt.do_task(jt, stdc, stdd)) { 485 bdt.pause(jt); 486 { 487 ThreadBlockInVM tbivm(jt); 488 } 489 bdt.cont(jt); 490 } 491 bdt.done(jt); 492 } 493 log_debug(stringtable)("Cleaned %ld of %ld", stdc._count, stdc._item); 494 } 495 496 void StringTable::gc_notification(size_t num_dead) { 497 log_trace(stringtable)("Uncleaned items:" SIZE_FORMAT, num_dead); 498 499 if (has_work()) { 500 return; 501 } 502 503 double load_factor = StringTable::get_load_factor(); 504 double dead_factor = StringTable::get_dead_factor(num_dead); 505 // We should clean/resize if we have more dead than alive, 506 // more items than preferred load factor or 507 // more dead items than water mark. 508 if ((dead_factor > load_factor) || 509 (load_factor > PREF_AVG_LIST_LEN) || 510 (dead_factor > CLEAN_DEAD_HIGH_WATER_MARK)) { 511 log_debug(stringtable)("Concurrent work triggered, live factor: %g dead factor: %g", 512 load_factor, dead_factor); 513 trigger_concurrent_work(); 514 } 515 } 516 517 bool StringTable::should_grow() { 518 return get_load_factor() > PREF_AVG_LIST_LEN && !_local_table->is_max_size_reached(); 519 } 520 521 void StringTable::do_concurrent_work(JavaThread* jt) { 522 // Rehash if needed. Rehashing goes to a safepoint but the rest of this 523 // work is concurrent. 524 if (needs_rehashing() && maybe_rehash_table()) { 525 Atomic::release_store(&_has_work, false); 526 return; // done, else grow 527 } 528 log_debug(stringtable, perf)("Concurrent work, live factor: %g", get_load_factor()); 529 // We prefer growing, since that also removes dead items 530 if (should_grow()) { 531 grow(jt); 532 } else { 533 clean_dead_entries(jt); 534 } 535 Atomic::release_store(&_has_work, false); 536 } 537 538 // Called at VM_Operation safepoint 539 void StringTable::rehash_table() { 540 assert(SafepointSynchronize::is_at_safepoint(), "must be called at safepoint"); 541 // The ServiceThread initiates the rehashing so it is not resizing. 542 assert (_local_table->is_safepoint_safe(), "Should not be resizing now"); 543 544 _alt_hash_seed = AltHashing::compute_seed(); 545 546 // We use current size, not max size. 547 size_t new_size = _local_table->get_size_log2(Thread::current()); 548 StringTableHash* new_table = new StringTableHash(new_size, END_SIZE, REHASH_LEN, true); 549 // Use alt hash from now on 550 _alt_hash = true; 551 _local_table->rehash_nodes_to(Thread::current(), new_table); 552 553 // free old table 554 delete _local_table; 555 _local_table = new_table; 556 557 _rehashed = true; 558 _needs_rehashing = false; 559 } 560 561 bool StringTable::maybe_rehash_table() { 562 log_debug(stringtable)("Table imbalanced, rehashing called."); 563 564 // Grow instead of rehash. 565 if (should_grow()) { 566 log_debug(stringtable)("Choosing growing over rehashing."); 567 _needs_rehashing = false; 568 return false; 569 } 570 // Already rehashed. 571 if (_rehashed) { 572 log_warning(stringtable)("Rehashing already done, still long lists."); 573 _needs_rehashing = false; 574 return false; 575 } 576 577 VM_RehashStringTable op; 578 VMThread::execute(&op); 579 return true; // return true because we tried. 580 } 581 582 // Statistics 583 static size_t literal_size(oop obj) { 584 if (obj == nullptr) { 585 return 0; 586 } 587 588 size_t word_size = obj->size(); 589 590 if (obj->klass() == vmClasses::String_klass()) { 591 // This may overcount if String.value arrays are shared. 592 word_size += java_lang_String::value(obj)->size(); 593 } 594 595 return word_size * HeapWordSize; 596 } 597 598 struct SizeFunc : StackObj { 599 size_t operator()(WeakHandle* val) { 600 oop s = val->peek(); 601 if (s == nullptr) { 602 // Dead 603 return 0; 604 } 605 return literal_size(s); 606 }; 607 }; 608 609 TableStatistics StringTable::get_table_statistics() { 610 static TableStatistics ts; 611 SizeFunc sz; 612 ts = _local_table->statistics_get(Thread::current(), sz, ts); 613 return ts; 614 } 615 616 void StringTable::print_table_statistics(outputStream* st) { 617 SizeFunc sz; 618 _local_table->statistics_to(Thread::current(), sz, st, "StringTable"); 619 #if INCLUDE_CDS_JAVA_HEAP 620 if (!_shared_table.empty()) { 621 _shared_table.print_table_statistics(st, "Shared String Table"); 622 } 623 #endif 624 } 625 626 // Verification 627 class VerifyStrings : StackObj { 628 public: 629 bool operator()(WeakHandle* val) { 630 oop s = val->peek(); 631 if (s != nullptr) { 632 assert(java_lang_String::length(s) >= 0, "Length on string must work."); 633 } 634 return true; 635 }; 636 }; 637 638 // This verification is part of Universe::verify() and needs to be quick. 639 void StringTable::verify() { 640 VerifyStrings vs; 641 _local_table->do_safepoint_scan(vs); 642 } 643 644 // Verification and comp 645 class VerifyCompStrings : StackObj { 646 static unsigned string_hash(oop const& str) { 647 return java_lang_String::hash_code_noupdate(str); 648 } 649 static bool string_equals(oop const& a, oop const& b) { 650 return java_lang_String::equals(a, b); 651 } 652 653 ResizeableResourceHashtable<oop, bool, AnyObj::C_HEAP, mtInternal, 654 string_hash, string_equals> _table; 655 public: 656 size_t _errors; 657 VerifyCompStrings() : _table(unsigned(_items_count / 8) + 1, 0 /* do not resize */), _errors(0) {} 658 bool operator()(WeakHandle* val) { 659 oop s = val->resolve(); 660 if (s == nullptr) { 661 return true; 662 } 663 bool created; 664 _table.put_if_absent(s, true, &created); 665 assert(created, "Duplicate strings"); 666 if (!created) { 667 _errors++; 668 } 669 return true; 670 }; 671 }; 672 673 size_t StringTable::verify_and_compare_entries() { 674 Thread* thr = Thread::current(); 675 VerifyCompStrings vcs; 676 _local_table->do_scan(thr, vcs); 677 return vcs._errors; 678 } 679 680 static void print_string(Thread* current, outputStream* st, oop s) { 681 typeArrayOop value = java_lang_String::value_no_keepalive(s); 682 int length = java_lang_String::length(s); 683 bool is_latin1 = java_lang_String::is_latin1(s); 684 685 if (length <= 0) { 686 st->print("%d: ", length); 687 } else { 688 ResourceMark rm(current); 689 size_t utf8_length = length; 690 char* utf8_string; 691 692 if (!is_latin1) { 693 jchar* chars = value->char_at_addr(0); 694 utf8_string = UNICODE::as_utf8(chars, utf8_length); 695 } else { 696 jbyte* bytes = value->byte_at_addr(0); 697 utf8_string = UNICODE::as_utf8(bytes, utf8_length); 698 } 699 700 st->print("%zu: ", utf8_length); 701 HashtableTextDump::put_utf8(st, utf8_string, utf8_length); 702 } 703 st->cr(); 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* val) { 713 oop s = val->peek(); 714 if (s == nullptr) { 715 return true; 716 } 717 print_string(_thr, _st, s); 718 return true; 719 }; 720 }; 721 722 class PrintSharedString : StackObj { 723 Thread* _thr; 724 outputStream* _st; 725 public: 726 PrintSharedString(Thread* thr, outputStream* st) : _thr(thr), _st(st) {} 727 void do_value(oop s) { 728 if (s == nullptr) { 729 return; 730 } 731 print_string(_thr, _st, s); 732 }; 733 }; 734 735 void StringTable::dump(outputStream* st, bool verbose) { 736 if (!verbose) { 737 print_table_statistics(st); 738 } else { 739 Thread* thr = Thread::current(); 740 ResourceMark rm(thr); 741 st->print_cr("VERSION: 1.1"); 742 PrintString ps(thr, st); 743 if (!_local_table->try_scan(thr, ps)) { 744 st->print_cr("dump unavailable at this moment"); 745 } 746 #if INCLUDE_CDS_JAVA_HEAP 747 if (!_shared_table.empty()) { 748 st->print_cr("#----------------"); 749 st->print_cr("# Shared strings:"); 750 st->print_cr("#----------------"); 751 PrintSharedString pss(thr, st); 752 _shared_table.iterate(&pss); 753 } 754 #endif 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 // Sharing 773 #if INCLUDE_CDS_JAVA_HEAP 774 size_t StringTable::shared_entry_count() { 775 return _shared_table.entry_count(); 776 } 777 778 oop StringTable::lookup_shared(const jchar* name, int len, unsigned int hash) { 779 assert(hash == java_lang_String::hash_code(name, len), 780 "hash must be computed using java_lang_String::hash_code"); 781 return _shared_table.lookup(name, hash, len); 782 } 783 784 oop StringTable::lookup_shared(const jchar* name, int len) { 785 return _shared_table.lookup(name, java_lang_String::hash_code(name, len), len); 786 } 787 788 // This is called BEFORE we enter the CDS safepoint. We can allocate heap objects. 789 // This should be called when we know no more strings will be added (which will be easy 790 // to guarantee because CDS runs with a single Java thread. See JDK-8253495.) 791 void StringTable::allocate_shared_strings_array(TRAPS) { 792 if (!CDSConfig::is_dumping_heap()) { 793 return; 794 } 795 if (_items_count > (size_t)max_jint) { 796 fatal("Too many strings to be archived: %zu", _items_count); 797 } 798 799 int total = (int)_items_count; 800 size_t single_array_size = objArrayOopDesc::object_size(total); 801 802 log_info(cds)("allocated string table for %d strings", total); 803 804 if (!ArchiveHeapWriter::is_too_large_to_archive(single_array_size)) { 805 // The entire table can fit in a single array 806 objArrayOop array = oopFactory::new_objArray(vmClasses::Object_klass(), total, CHECK); 807 _shared_strings_array = OopHandle(Universe::vm_global(), array); 808 log_info(cds)("string table array (single level) length = %d", total); 809 } else { 810 // Split the table in two levels of arrays. 811 int primary_array_length = (total + _secondary_array_max_length - 1) / _secondary_array_max_length; 812 size_t primary_array_size = objArrayOopDesc::object_size(primary_array_length); 813 size_t secondary_array_size = objArrayOopDesc::object_size(_secondary_array_max_length); 814 815 if (ArchiveHeapWriter::is_too_large_to_archive(secondary_array_size)) { 816 // This can only happen if you have an extremely large number of classes that 817 // refer to more than 16384 * 16384 = 26M interned strings! Not a practical concern 818 // but bail out for safety. 819 log_error(cds)("Too many strings to be archived: %zu", _items_count); 820 MetaspaceShared::unrecoverable_writing_error(); 821 } 822 823 objArrayOop primary = oopFactory::new_objArray(vmClasses::Object_klass(), primary_array_length, CHECK); 824 objArrayHandle primaryHandle(THREAD, primary); 825 _shared_strings_array = OopHandle(Universe::vm_global(), primary); 826 827 log_info(cds)("string table array (primary) length = %d", primary_array_length); 828 for (int i = 0; i < primary_array_length; i++) { 829 int len; 830 if (total > _secondary_array_max_length) { 831 len = _secondary_array_max_length; 832 } else { 833 len = total; 834 } 835 total -= len; 836 837 objArrayOop secondary = oopFactory::new_objArray(vmClasses::Object_klass(), len, CHECK); 838 primaryHandle()->obj_at_put(i, secondary); 839 840 log_info(cds)("string table array (secondary)[%d] length = %d", i, len); 841 assert(!ArchiveHeapWriter::is_too_large_to_archive(secondary), "sanity"); 842 } 843 844 assert(total == 0, "must be"); 845 _is_two_dimensional_shared_strings_array = true; 846 } 847 } 848 849 #ifndef PRODUCT 850 void StringTable::verify_secondary_array_index_bits() { 851 int max; 852 for (max = 1; ; max++) { 853 size_t next_size = objArrayOopDesc::object_size(1 << (max + 1)); 854 if (ArchiveHeapWriter::is_too_large_to_archive(next_size)) { 855 break; 856 } 857 } 858 // Currently max is 17 for +UseCompressedOops, 16 for -UseCompressedOops. 859 // When we add support for Shenandoah (which has a smaller mininum region size than G1), 860 // max will become 15/14. 861 // 862 // We use _secondary_array_index_bits==14 as that will be the eventual value, and will 863 // make testing easier. 864 assert(_secondary_array_index_bits <= max, 865 "_secondary_array_index_bits (%d) must be smaller than max possible value (%d)", 866 _secondary_array_index_bits, max); 867 } 868 #endif // PRODUCT 869 870 // This is called AFTER we enter the CDS safepoint. 871 // 872 // For each shared string: 873 // [1] Store it into _shared_strings_array. Encode its position as a 32-bit index. 874 // [2] Store the index and hashcode into _shared_table. 875 oop StringTable::init_shared_table(const DumpedInternedStrings* dumped_interned_strings) { 876 assert(HeapShared::can_write(), "must be"); 877 objArrayOop array = (objArrayOop)(_shared_strings_array.resolve()); 878 879 verify_secondary_array_index_bits(); 880 881 _shared_table.reset(); 882 CompactHashtableWriter writer((int)_items_count, ArchiveBuilder::string_stats()); 883 884 int index = 0; 885 auto copy_into_array = [&] (oop string, bool value_ignored) { 886 unsigned int hash = java_lang_String::hash_code(string); 887 writer.add(hash, index); 888 889 if (!_is_two_dimensional_shared_strings_array) { 890 assert(index < array->length(), "no strings should have been added"); 891 array->obj_at_put(index, string); 892 } else { 893 int primary_index = index >> _secondary_array_index_bits; 894 int secondary_index = index & _secondary_array_index_mask; 895 896 assert(primary_index < array->length(), "no strings should have been added"); 897 objArrayOop secondary = (objArrayOop)array->obj_at(primary_index); 898 899 assert(secondary != nullptr && secondary->is_objArray(), "must be"); 900 assert(secondary_index < secondary->length(), "no strings should have been added"); 901 secondary->obj_at_put(secondary_index, string); 902 } 903 904 index ++; 905 }; 906 dumped_interned_strings->iterate_all(copy_into_array); 907 908 writer.dump(&_shared_table, "string"); 909 910 return array; 911 } 912 913 void StringTable::set_shared_strings_array_index(int root_index) { 914 _shared_strings_array_root_index = root_index; 915 } 916 917 void StringTable::serialize_shared_table_header(SerializeClosure* soc) { 918 if (soc->writing() && !HeapShared::can_write()) { 919 _shared_table.reset(); 920 _is_two_dimensional_shared_strings_array = false; 921 _shared_strings_array_root_index = -1; 922 } 923 924 _shared_table.serialize_header(soc); 925 926 if (soc->writing()) { 927 // Sanity. Make sure we don't use the shared table at dump time 928 _shared_table.reset(); 929 } else if (!ArchiveHeapLoader::is_in_use()) { 930 _shared_table.reset(); 931 } 932 933 soc->do_bool(&_is_two_dimensional_shared_strings_array); 934 soc->do_int(&_shared_strings_array_root_index); 935 } 936 #endif //INCLUDE_CDS_JAVA_HEAP