1 /* 2 * Copyright (c) 2019, 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/archiveHeapWriter.hpp" 28 #include "cds/archiveUtils.inline.hpp" 29 #include "cds/cds_globals.hpp" 30 #include "cds/cdsConfig.hpp" 31 #include "cds/classPrelinker.hpp" 32 #include "cds/classPreloader.hpp" 33 #include "cds/dynamicArchive.hpp" 34 #include "cds/metaspaceShared.hpp" 35 #include "cds/regeneratedClasses.hpp" 36 #include "classfile/classLoader.hpp" 37 #include "classfile/classLoaderData.inline.hpp" 38 #include "classfile/symbolTable.hpp" 39 #include "classfile/systemDictionaryShared.hpp" 40 #include "classfile/vmSymbols.hpp" 41 #include "gc/shared/collectedHeap.hpp" 42 #include "gc/shared/gcVMOperations.hpp" 43 #include "gc/shared/gc_globals.hpp" 44 #include "jvm.h" 45 #include "logging/log.hpp" 46 #include "memory/metaspaceClosure.hpp" 47 #include "memory/resourceArea.hpp" 48 #include "oops/klass.inline.hpp" 49 #include "runtime/arguments.hpp" 50 #include "runtime/os.hpp" 51 #include "runtime/sharedRuntime.hpp" 52 #include "runtime/vmThread.hpp" 53 #include "runtime/vmOperations.hpp" 54 #include "utilities/align.hpp" 55 #include "utilities/bitMap.inline.hpp" 56 57 58 class DynamicArchiveBuilder : public ArchiveBuilder { 59 const char* _archive_name; 60 public: 61 DynamicArchiveBuilder(const char* archive_name) : _archive_name(archive_name) {} 62 void mark_pointer(address* ptr_loc) { 63 ArchivePtrMarker::mark_pointer(ptr_loc); 64 } 65 66 static int dynamic_dump_method_comparator(Method* a, Method* b) { 67 Symbol* a_name = a->name(); 68 Symbol* b_name = b->name(); 69 70 if (a_name == b_name) { 71 return 0; 72 } 73 74 u4 a_offset = ArchiveBuilder::current()->any_to_offset_u4(a_name); 75 u4 b_offset = ArchiveBuilder::current()->any_to_offset_u4(b_name); 76 77 if (a_offset < b_offset) { 78 return -1; 79 } else { 80 assert(a_offset > b_offset, "must be"); 81 return 1; 82 } 83 } 84 85 public: 86 DynamicArchiveHeader *_header; 87 88 void init_header(); 89 void release_header(); 90 void post_dump(); 91 void sort_methods(); 92 void sort_methods(InstanceKlass* ik) const; 93 void remark_pointers_for_instance_klass(InstanceKlass* k, bool should_mark) const; 94 void write_archive(char* serialized_data); 95 void gather_array_klasses(); 96 97 public: 98 DynamicArchiveBuilder() : ArchiveBuilder() { } 99 100 // Do this before and after the archive dump to see if any corruption 101 // is caused by dynamic dumping. 102 void verify_universe(const char* info) { 103 if (VerifyBeforeExit) { 104 log_info(cds)("Verify %s", info); 105 // Among other things, this ensures that Eden top is correct. 106 Universe::heap()->prepare_for_verify(); 107 Universe::verify(info); 108 } 109 } 110 111 void doit() { 112 verify_universe("Before CDS dynamic dump"); 113 DEBUG_ONLY(SystemDictionaryShared::NoClassLoadingMark nclm); 114 115 // Block concurrent class unloading from changing the _dumptime_table 116 MutexLocker ml(DumpTimeTable_lock, Mutex::_no_safepoint_check_flag); 117 SystemDictionaryShared::check_excluded_classes(); 118 119 if (SystemDictionaryShared::is_dumptime_table_empty()) { 120 log_warning(cds, dynamic)("There is no class to be included in the dynamic archive."); 121 return; 122 } 123 124 log_info(cds,dynamic)("CDS dynamic dump: clinit = %ldms)", 125 ClassLoader::class_init_time_ms()); 126 127 init_header(); 128 gather_source_objs(); 129 gather_array_klasses(); 130 reserve_buffer(); 131 132 log_info(cds, dynamic)("Copying %d klasses and %d symbols", 133 klasses()->length(), symbols()->length()); 134 dump_rw_metadata(); 135 dump_ro_metadata(); 136 relocate_metaspaceobj_embedded_pointers(); 137 138 verify_estimate_size(_estimated_metaspaceobj_bytes, "MetaspaceObjs"); 139 140 sort_methods(); 141 142 { 143 ArchiveBuilder::OtherROAllocMark mark; 144 ClassPreloader::record_preloaded_classes(false); 145 } 146 147 log_info(cds)("Make classes shareable"); 148 make_klasses_shareable(); 149 150 char* serialized_data; 151 { 152 // Write the symbol table and system dictionaries to the RO space. 153 // Note that these tables still point to the *original* objects, so 154 // they would need to call DynamicArchive::original_to_target() to 155 // get the correct addresses. 156 assert(current_dump_region() == ro_region(), "Must be RO space"); 157 SymbolTable::write_to_archive(symbols()); 158 159 ArchiveBuilder::OtherROAllocMark mark; 160 SystemDictionaryShared::write_to_archive(false); 161 162 DynamicArchive::dump_array_klasses(); 163 ClassPreloader::record_initiated_classes(false); 164 TrainingData::dump_training_data(); 165 166 serialized_data = ro_region()->top(); 167 WriteClosure wc(ro_region()); 168 ArchiveBuilder::serialize_dynamic_archivable_items(&wc); 169 } 170 171 verify_estimate_size(_estimated_hashtable_bytes, "Hashtables"); 172 173 log_info(cds)("Adjust lambda proxy class dictionary"); 174 SystemDictionaryShared::adjust_lambda_proxy_class_dictionary(); 175 176 log_info(cds)("Adjust method info dictionary"); 177 SystemDictionaryShared::adjust_method_info_dictionary(); 178 179 log_info(cds)("Make training data shareable"); 180 make_training_data_shareable(); 181 182 relocate_to_requested(); 183 184 write_archive(serialized_data); 185 release_header(); 186 DynamicArchive::post_dump(); 187 188 post_dump(); 189 190 assert(_num_dump_regions_used == _total_dump_regions, "must be"); 191 verify_universe("After CDS dynamic dump"); 192 } 193 194 virtual void iterate_roots(MetaspaceClosure* it) { 195 FileMapInfo::metaspace_pointers_do(it); 196 SystemDictionaryShared::dumptime_classes_do(it); 197 TrainingData::iterate_roots(it); 198 iterate_primitive_array_klasses(it); 199 } 200 201 void iterate_primitive_array_klasses(MetaspaceClosure* it) { 202 for (int i = T_BOOLEAN; i <= T_LONG; i++) { 203 assert(is_java_primitive((BasicType)i), "sanity"); 204 Klass* k = Universe::typeArrayKlass((BasicType)i); // this give you "[I", etc 205 assert(MetaspaceShared::is_shared_static((void*)k), 206 "one-dimensional primitive array should be in static archive"); 207 ArrayKlass* ak = ArrayKlass::cast(k); 208 while (ak != nullptr && ak->is_shared()) { 209 Klass* next_k = ak->array_klass_or_null(); 210 if (next_k != nullptr) { 211 ak = ArrayKlass::cast(next_k); 212 } else { 213 ak = nullptr; 214 } 215 } 216 if (ak != nullptr) { 217 assert(ak->dimension() > 1, "sanity"); 218 // this is the lowest dimension that's not in the static archive 219 it->push(&ak); 220 } 221 } 222 } 223 }; 224 225 void DynamicArchiveBuilder::init_header() { 226 FileMapInfo* mapinfo = new FileMapInfo(_archive_name, false); 227 assert(FileMapInfo::dynamic_info() == mapinfo, "must be"); 228 FileMapInfo* base_info = FileMapInfo::current_info(); 229 // header only be available after populate_header 230 mapinfo->populate_header(base_info->core_region_alignment()); 231 _header = mapinfo->dynamic_header(); 232 233 _header->set_base_header_crc(base_info->crc()); 234 for (int i = 0; i < MetaspaceShared::n_regions; i++) { 235 _header->set_base_region_crc(i, base_info->region_crc(i)); 236 } 237 } 238 239 void DynamicArchiveBuilder::release_header() { 240 // We temporarily allocated a dynamic FileMapInfo for dumping, which makes it appear we 241 // have mapped a dynamic archive, but we actually have not. We are in a safepoint now. 242 // Let's free it so that if class loading happens after we leave the safepoint, nothing 243 // bad will happen. 244 assert(SafepointSynchronize::is_at_safepoint(), "must be"); 245 FileMapInfo *mapinfo = FileMapInfo::dynamic_info(); 246 assert(mapinfo != nullptr && _header == mapinfo->dynamic_header(), "must be"); 247 delete mapinfo; 248 assert(!DynamicArchive::is_mapped(), "must be"); 249 _header = nullptr; 250 } 251 252 void DynamicArchiveBuilder::post_dump() { 253 ArchivePtrMarker::reset_map_and_vs(); 254 ClassPreloader::dispose(); 255 ClassPrelinker::dispose(); 256 } 257 258 void DynamicArchiveBuilder::sort_methods() { 259 InstanceKlass::disable_method_binary_search(); 260 for (int i = 0; i < klasses()->length(); i++) { 261 Klass* k = get_buffered_addr(klasses()->at(i)); 262 if (k->is_instance_klass()) { 263 sort_methods(InstanceKlass::cast(k)); 264 } 265 } 266 } 267 268 // The address order of the copied Symbols may be different than when the original 269 // klasses were created. Re-sort all the tables. See Method::sort_methods(). 270 void DynamicArchiveBuilder::sort_methods(InstanceKlass* ik) const { 271 assert(ik != nullptr, "DynamicArchiveBuilder currently doesn't support dumping the base archive"); 272 if (MetaspaceShared::is_in_shared_metaspace(ik)) { 273 // We have reached a supertype that's already in the base archive 274 return; 275 } 276 assert(is_in_buffer_space(ik), "method sorting must be done on buffered class, not original class"); 277 if (ik->java_mirror() == nullptr) { 278 // null mirror means this class has already been visited and methods are already sorted 279 return; 280 } 281 ik->remove_java_mirror(); 282 283 if (log_is_enabled(Debug, cds, dynamic)) { 284 ResourceMark rm; 285 log_debug(cds, dynamic)("sorting methods for " PTR_FORMAT " (" PTR_FORMAT ") %s", 286 p2i(ik), p2i(to_requested(ik)), ik->external_name()); 287 } 288 289 // Method sorting may re-layout the [iv]tables, which would change the offset(s) 290 // of the locations in an InstanceKlass that would contain pointers. Let's clear 291 // all the existing pointer marking bits, and re-mark the pointers after sorting. 292 remark_pointers_for_instance_klass(ik, false); 293 294 // Make sure all supertypes have been sorted 295 sort_methods(ik->java_super()); 296 Array<InstanceKlass*>* interfaces = ik->local_interfaces(); 297 int len = interfaces->length(); 298 for (int i = 0; i < len; i++) { 299 sort_methods(interfaces->at(i)); 300 } 301 302 #ifdef ASSERT 303 if (ik->methods() != nullptr) { 304 for (int m = 0; m < ik->methods()->length(); m++) { 305 Symbol* name = ik->methods()->at(m)->name(); 306 assert(MetaspaceShared::is_in_shared_metaspace(name) || is_in_buffer_space(name), "must be"); 307 } 308 } 309 if (ik->default_methods() != nullptr) { 310 for (int m = 0; m < ik->default_methods()->length(); m++) { 311 Symbol* name = ik->default_methods()->at(m)->name(); 312 assert(MetaspaceShared::is_in_shared_metaspace(name) || is_in_buffer_space(name), "must be"); 313 } 314 } 315 #endif 316 317 Method::sort_methods(ik->methods(), /*set_idnums=*/true, dynamic_dump_method_comparator); 318 if (ik->default_methods() != nullptr) { 319 Method::sort_methods(ik->default_methods(), /*set_idnums=*/false, dynamic_dump_method_comparator); 320 } 321 if (ik->is_linked()) { 322 // If the class has already been linked, we must relayout the i/v tables, whose order depends 323 // on the method sorting order. 324 // If the class is unlinked, we cannot layout the i/v tables yet. This is OK, as the 325 // i/v tables will be initialized at runtime after bytecode verification. 326 ik->vtable().initialize_vtable(); 327 ik->itable().initialize_itable(); 328 } 329 330 // Set all the pointer marking bits after sorting. 331 remark_pointers_for_instance_klass(ik, true); 332 } 333 334 template<bool should_mark> 335 class PointerRemarker: public MetaspaceClosure { 336 public: 337 virtual bool do_ref(Ref* ref, bool read_only) { 338 if (should_mark) { 339 ArchivePtrMarker::mark_pointer(ref->addr()); 340 } else { 341 ArchivePtrMarker::clear_pointer(ref->addr()); 342 } 343 return false; // don't recurse 344 } 345 }; 346 347 void DynamicArchiveBuilder::remark_pointers_for_instance_klass(InstanceKlass* k, bool should_mark) const { 348 if (should_mark) { 349 PointerRemarker<true> marker; 350 k->metaspace_pointers_do(&marker); 351 marker.finish(); 352 } else { 353 PointerRemarker<false> marker; 354 k->metaspace_pointers_do(&marker); 355 marker.finish(); 356 } 357 } 358 359 void DynamicArchiveBuilder::write_archive(char* serialized_data) { 360 _header->set_shared_path_table(FileMapInfo::shared_path_table().table()); 361 _header->set_serialized_data(serialized_data); 362 363 FileMapInfo* dynamic_info = FileMapInfo::dynamic_info(); 364 assert(dynamic_info != nullptr, "Sanity"); 365 366 dynamic_info->open_for_write(); 367 ArchiveHeapInfo no_heap_for_dynamic_dump; 368 ArchiveBuilder::write_archive(dynamic_info, &no_heap_for_dynamic_dump); 369 370 address base = _requested_dynamic_archive_bottom; 371 address top = _requested_dynamic_archive_top; 372 size_t file_size = pointer_delta(top, base, sizeof(char)); 373 374 log_info(cds, dynamic)("Written dynamic archive " PTR_FORMAT " - " PTR_FORMAT 375 " [" UINT32_FORMAT " bytes header, " SIZE_FORMAT " bytes total]", 376 p2i(base), p2i(top), _header->header_size(), file_size); 377 378 log_info(cds, dynamic)("%d klasses; %d symbols", klasses()->length(), symbols()->length()); 379 } 380 381 void DynamicArchiveBuilder::gather_array_klasses() { 382 for (int i = 0; i < klasses()->length(); i++) { 383 if (klasses()->at(i)->is_objArray_klass()) { 384 ObjArrayKlass* oak = ObjArrayKlass::cast(klasses()->at(i)); 385 Klass* elem = oak->element_klass(); 386 if (MetaspaceShared::is_shared_static(elem)) { 387 // Only capture the array klass whose element_klass is in the static archive. 388 // During run time, setup (see DynamicArchive::setup_array_klasses()) is needed 389 // so that the element_klass can find its array klasses from the dynamic archive. 390 DynamicArchive::append_array_klass(oak); 391 } else { 392 // The element_klass and its array klasses are in the same archive. 393 assert(!MetaspaceShared::is_shared_static(oak), 394 "we should not gather klasses that are already in the static archive"); 395 } 396 } 397 } 398 log_debug(cds)("Total array klasses gathered for dynamic archive: %d", DynamicArchive::num_array_klasses()); 399 } 400 401 class VM_PopulateDynamicDumpSharedSpace: public VM_GC_Sync_Operation { 402 DynamicArchiveBuilder _builder; 403 public: 404 VM_PopulateDynamicDumpSharedSpace(const char* archive_name) 405 : VM_GC_Sync_Operation(), _builder(archive_name) {} 406 VMOp_Type type() const { return VMOp_PopulateDumpSharedSpace; } 407 void doit() { 408 ResourceMark rm; 409 if (AllowArchivingWithJavaAgent) { 410 log_warning(cds)("This archive was created with AllowArchivingWithJavaAgent. It should be used " 411 "for testing purposes only and should not be used in a production environment"); 412 } 413 FileMapInfo::check_nonempty_dir_in_shared_path_table(); 414 415 _builder.doit(); 416 } 417 ~VM_PopulateDynamicDumpSharedSpace() { 418 RegeneratedClasses::cleanup(); 419 } 420 }; 421 422 // _array_klasses and _dynamic_archive_array_klasses only hold the array klasses 423 // which have element klass in the static archive. 424 GrowableArray<ObjArrayKlass*>* DynamicArchive::_array_klasses = nullptr; 425 Array<ObjArrayKlass*>* DynamicArchive::_dynamic_archive_array_klasses = nullptr; 426 427 void DynamicArchive::append_array_klass(ObjArrayKlass* ak) { 428 if (_array_klasses == nullptr) { 429 _array_klasses = new (mtClassShared) GrowableArray<ObjArrayKlass*>(50, mtClassShared); 430 } 431 _array_klasses->append(ak); 432 } 433 434 void DynamicArchive::dump_array_klasses() { 435 assert(CDSConfig::is_dumping_dynamic_archive(), "sanity"); 436 if (_array_klasses != nullptr) { 437 ArchiveBuilder* builder = ArchiveBuilder::current(); 438 int num_array_klasses = _array_klasses->length(); 439 _dynamic_archive_array_klasses = 440 ArchiveBuilder::new_ro_array<ObjArrayKlass*>(num_array_klasses); 441 for (int i = 0; i < num_array_klasses; i++) { 442 builder->write_pointer_in_buffer(_dynamic_archive_array_klasses->adr_at(i), _array_klasses->at(i)); 443 } 444 } 445 } 446 447 void DynamicArchive::setup_array_klasses() { 448 if (_dynamic_archive_array_klasses != nullptr) { 449 for (int i = 0; i < _dynamic_archive_array_klasses->length(); i++) { 450 ObjArrayKlass* oak = _dynamic_archive_array_klasses->at(i); 451 assert(!oak->is_typeArray_klass(), "all type array classes must be in static archive"); 452 453 Klass* elm = oak->element_klass(); 454 assert(MetaspaceShared::is_shared_static((void*)elm), "must be"); 455 456 if (elm->is_instance_klass()) { 457 assert(InstanceKlass::cast(elm)->array_klasses() == nullptr, "must be"); 458 InstanceKlass::cast(elm)->set_array_klasses(oak); 459 } else { 460 assert(elm->is_array_klass(), "sanity"); 461 assert(ArrayKlass::cast(elm)->higher_dimension() == nullptr, "must be"); 462 ArrayKlass::cast(elm)->set_higher_dimension(oak); 463 } 464 } 465 log_debug(cds)("Total array klasses read from dynamic archive: %d", _dynamic_archive_array_klasses->length()); 466 } 467 } 468 469 void DynamicArchive::serialize_array_klasses(SerializeClosure* soc) { 470 soc->do_ptr(&_dynamic_archive_array_klasses); 471 } 472 473 void DynamicArchive::make_array_klasses_shareable() { 474 if (_array_klasses != nullptr) { 475 int num_array_klasses = _array_klasses->length(); 476 for (int i = 0; i < num_array_klasses; i++) { 477 ObjArrayKlass* k = ArchiveBuilder::current()->get_buffered_addr(_array_klasses->at(i)); 478 k->remove_unshareable_info(); 479 } 480 } 481 } 482 483 void DynamicArchive::post_dump() { 484 if (_array_klasses != nullptr) { 485 delete _array_klasses; 486 _array_klasses = nullptr; 487 } 488 } 489 490 int DynamicArchive::num_array_klasses() { 491 return _array_klasses != nullptr ? _array_klasses->length() : 0; 492 } 493 494 void DynamicArchive::check_for_dynamic_dump() { 495 if (CDSConfig::is_dumping_dynamic_archive() && !UseSharedSpaces) { 496 // This could happen if SharedArchiveFile has failed to load: 497 // - -Xshare:off was specified 498 // - SharedArchiveFile points to an non-existent file. 499 // - SharedArchiveFile points to an archive that has failed CRC check 500 // - SharedArchiveFile is not specified and the VM doesn't have a compatible default archive 501 502 #define __THEMSG " is unsupported when base CDS archive is not loaded. Run with -Xlog:cds for more info." 503 if (RecordDynamicDumpInfo) { 504 log_error(cds)("-XX:+RecordDynamicDumpInfo%s", __THEMSG); 505 MetaspaceShared::unrecoverable_loading_error(); 506 } else { 507 assert(ArchiveClassesAtExit != nullptr, "sanity"); 508 log_warning(cds)("-XX:ArchiveClassesAtExit" __THEMSG); 509 } 510 #undef __THEMSG 511 CDSConfig::disable_dumping_dynamic_archive(); 512 } 513 } 514 515 void DynamicArchive::dump_at_exit(JavaThread* current, const char* archive_name) { 516 ExceptionMark em(current); 517 ResourceMark rm(current); 518 519 if (!CDSConfig::is_dumping_dynamic_archive() || archive_name == nullptr) { 520 return; 521 } 522 523 log_info(cds, dynamic)("Preparing for dynamic dump at exit in thread %s", current->name()); 524 525 JavaThread* THREAD = current; // For TRAPS processing related to link_shared_classes 526 527 { 528 // FIXME-HACK - make sure we have at least one class in the dynamic archive 529 TempNewSymbol class_name = SymbolTable::new_symbol("sun/nio/cs/IBM850"); // unusual class; shouldn't be used by our tests cases. 530 SystemDictionary::resolve_or_null(class_name, Handle(), Handle(), THREAD); 531 guarantee(!HAS_PENDING_EXCEPTION, "must have this class"); 532 } 533 534 MetaspaceShared::link_shared_classes(false/*not from jcmd*/, THREAD); 535 if (!HAS_PENDING_EXCEPTION) { 536 // copy shared path table to saved. 537 TrainingData::init_dumptime_table(CHECK); // captures TrainingDataSetLocker 538 if (!HAS_PENDING_EXCEPTION) { 539 VM_PopulateDynamicDumpSharedSpace op(archive_name); 540 VMThread::execute(&op); 541 return; 542 } 543 } 544 545 // One of the prepatory steps failed 546 oop ex = current->pending_exception(); 547 log_error(cds)("Dynamic dump has failed"); 548 log_error(cds)("%s: %s", ex->klass()->external_name(), 549 java_lang_String::as_utf8_string(java_lang_Throwable::message(ex))); 550 CLEAR_PENDING_EXCEPTION; 551 CDSConfig::disable_dumping_dynamic_archive(); // Just for good measure 552 } 553 554 // This is called by "jcmd VM.cds dynamic_dump" 555 void DynamicArchive::dump_for_jcmd(const char* archive_name, TRAPS) { 556 assert(UseSharedSpaces && RecordDynamicDumpInfo, "already checked in arguments.cpp"); 557 assert(ArchiveClassesAtExit == nullptr, "already checked in arguments.cpp"); 558 assert(CDSConfig::is_dumping_dynamic_archive(), "already checked by check_for_dynamic_dump() during VM startup"); 559 MetaspaceShared::link_shared_classes(true/*from jcmd*/, CHECK); 560 // copy shared path table to saved. 561 TrainingData::init_dumptime_table(CHECK); // captures TrainingDataSetLocker 562 VM_PopulateDynamicDumpSharedSpace op(archive_name); 563 VMThread::execute(&op); 564 } 565 566 bool DynamicArchive::validate(FileMapInfo* dynamic_info) { 567 assert(!dynamic_info->is_static(), "must be"); 568 // Check if the recorded base archive matches with the current one 569 FileMapInfo* base_info = FileMapInfo::current_info(); 570 DynamicArchiveHeader* dynamic_header = dynamic_info->dynamic_header(); 571 572 // Check the header crc 573 if (dynamic_header->base_header_crc() != base_info->crc()) { 574 log_warning(cds)("Dynamic archive cannot be used: static archive header checksum verification failed."); 575 return false; 576 } 577 578 // Check each space's crc 579 for (int i = 0; i < MetaspaceShared::n_regions; i++) { 580 if (dynamic_header->base_region_crc(i) != base_info->region_crc(i)) { 581 log_warning(cds)("Dynamic archive cannot be used: static archive region #%d checksum verification failed.", i); 582 return false; 583 } 584 } 585 586 return true; 587 } 588 589 void DynamicArchiveHeader::print(outputStream* st) { 590 ResourceMark rm; 591 592 st->print_cr("- base_header_crc: 0x%08x", base_header_crc()); 593 for (int i = 0; i < NUM_CDS_REGIONS; i++) { 594 st->print_cr("- base_region_crc[%d]: 0x%08x", i, base_region_crc(i)); 595 } 596 }