/* * Copyright (c) 2019, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. *
*/
// Do this before and after the archive dump to see if any corruption // is caused by dynamic dumping. void verify_universe(constchar* info) { if (VerifyBeforeExit) {
log_info(cds)("Verify %s", info); // Among other things, this ensures that Eden top is correct.
Universe::heap()->prepare_for_verify();
Universe::verify(info);
}
}
// Block concurrent class unloading from changing the _dumptime_table
MutexLocker ml(DumpTimeTable_lock, Mutex::_no_safepoint_check_flag);
SystemDictionaryShared::check_excluded_classes();
if (SystemDictionaryShared::is_dumptime_table_empty()) {
log_warning(cds, dynamic)("There is no class to be included in the dynamic archive."); return;
}
// save dumptime tables
SystemDictionaryShared::clone_dumptime_tables();
char* serialized_data;
{ // Write the symbol table and system dictionaries to the RO space. // Note that these tables still point to the *original* objects, so // they would need to call DynamicArchive::original_to_target() to // get the correct addresses.
assert(current_dump_space() == ro_region(), "Must be RO space");
SymbolTable::write_to_archive(symbols());
void DynamicArchiveBuilder::init_header() {
FileMapInfo* mapinfo = new FileMapInfo(_archive_name, false);
assert(FileMapInfo::dynamic_info() == mapinfo, "must be");
FileMapInfo* base_info = FileMapInfo::current_info(); // header only be available after populate_header
mapinfo->populate_header(base_info->core_region_alignment());
_header = mapinfo->dynamic_header();
_header->set_base_header_crc(base_info->crc()); for (int i = 0; i < MetaspaceShared::n_regions; i++) {
_header->set_base_region_crc(i, base_info->region_crc(i));
}
}
void DynamicArchiveBuilder::release_header() { // We temporarily allocated a dynamic FileMapInfo for dumping, which makes it appear we // have mapped a dynamic archive, but we actually have not. We are in a safepoint now. // Let's free it so that if class loading happens after we leave the safepoint, nothing // bad will happen.
assert(SafepointSynchronize::is_at_safepoint(), "must be");
FileMapInfo *mapinfo = FileMapInfo::dynamic_info();
assert(mapinfo != NULL && _header == mapinfo->dynamic_header(), "must be"); delete mapinfo;
assert(!DynamicArchive::is_mapped(), "must be");
_header = NULL;
}
void DynamicArchiveBuilder::sort_methods() {
InstanceKlass::disable_method_binary_search(); for (int i = 0; i < klasses()->length(); i++) {
Klass* k = klasses()->at(i); if (k->is_instance_klass()) {
sort_methods(InstanceKlass::cast(k));
}
}
}
// The address order of the copied Symbols may be different than when the original // klasses were created. Re-sort all the tables. See Method::sort_methods(). void DynamicArchiveBuilder::sort_methods(InstanceKlass* ik) const {
assert(ik != NULL, "DynamicArchiveBuilder currently doesn't support dumping the base archive"); if (MetaspaceShared::is_in_shared_metaspace(ik)) { // We have reached a supertype that's already in the base archive return;
}
if (ik->java_mirror() == NULL) { // NULL mirror means this class has already been visited and methods are already sorted return;
}
ik->remove_java_mirror();
// Method sorting may re-layout the [iv]tables, which would change the offset(s) // of the locations in an InstanceKlass that would contain pointers. Let's clear // all the existing pointer marking bits, and re-mark the pointers after sorting.
remark_pointers_for_instance_klass(ik, false);
// Make sure all supertypes have been sorted
sort_methods(ik->java_super());
Array<InstanceKlass*>* interfaces = ik->local_interfaces(); int len = interfaces->length(); for (int i = 0; i < len; i++) {
sort_methods(interfaces->at(i));
}
#ifdef ASSERT if (ik->methods() != NULL) { for (int m = 0; m < ik->methods()->length(); m++) {
Symbol* name = ik->methods()->at(m)->name();
assert(MetaspaceShared::is_in_shared_metaspace(name) || is_in_buffer_space(name), "must be");
}
} if (ik->default_methods() != NULL) { for (int m = 0; m < ik->default_methods()->length(); m++) {
Symbol* name = ik->default_methods()->at(m)->name();
assert(MetaspaceShared::is_in_shared_metaspace(name) || is_in_buffer_space(name), "must be");
}
} #endif
Method::sort_methods(ik->methods(), /*set_idnums=*/true, dynamic_dump_method_comparator); if (ik->default_methods() != NULL) {
Method::sort_methods(ik->default_methods(), /*set_idnums=*/false, dynamic_dump_method_comparator);
} if (ik->is_linked()) { // If the class has already been linked, we must relayout the i/v tables, whose order depends // on the method sorting order. // If the class is unlinked, we cannot layout the i/v tables yet. This is OK, as the // i/v tables will be initialized at runtime after bytecode verification.
ik->vtable().initialize_vtable();
ik->itable().initialize_itable();
}
// Set all the pointer marking bits after sorting.
remark_pointers_for_instance_klass(ik, true);
}
template<bool should_mark> class PointerRemarker: public MetaspaceClosure { public: virtualbool do_ref(Ref* ref, bool read_only) { if (should_mark) {
ArchivePtrMarker::mark_pointer(ref->addr());
} else {
ArchivePtrMarker::clear_pointer(ref->addr());
} returnfalse; // don't recurse
}
};
class VM_PopulateDynamicDumpSharedSpace: public VM_GC_Sync_Operation {
DynamicArchiveBuilder _builder; public:
VM_PopulateDynamicDumpSharedSpace(constchar* archive_name)
: VM_GC_Sync_Operation(), _builder(archive_name) {}
VMOp_Type type() const { return VMOp_PopulateDumpSharedSpace; } void doit() {
ResourceMark rm; if (AllowArchivingWithJavaAgent) {
warning("This archive was created with AllowArchivingWithJavaAgent. It should be used " "for testing purposes only and should not be used in a production environment");
}
FileMapInfo::check_nonempty_dir_in_shared_path_table();
void DynamicArchive::check_for_dynamic_dump() { if (DynamicDumpSharedSpaces && !UseSharedSpaces) { // This could happen if SharedArchiveFile has failed to load: // - -Xshare:off was specified // - SharedArchiveFile points to an non-existent file. // - SharedArchiveFile points to an archive that has failed CRC check // - SharedArchiveFile is not specified and the VM doesn't have a compatible default archive
#define __THEMSG " is unsupported when base CDS archive is not loaded. Run with -Xlog:cds for more info." if (RecordDynamicDumpInfo) {
vm_exit_during_initialization("-XX:+RecordDynamicDumpInfo" __THEMSG, NULL);
} else {
assert(ArchiveClassesAtExit != nullptr, "sanity");
warning("-XX:ArchiveClassesAtExit" __THEMSG);
} #undef __THEMSG
DynamicDumpSharedSpaces = false;
}
}
void DynamicArchive::prepare_for_dump_at_exit() {
EXCEPTION_MARK;
ResourceMark rm(THREAD);
MetaspaceShared::link_shared_classes(false/*not from jcmd*/, THREAD); if (HAS_PENDING_EXCEPTION) {
log_error(cds)("Dynamic dump has failed");
log_error(cds)("%s: %s", PENDING_EXCEPTION->klass()->external_name(),
java_lang_String::as_utf8_string(java_lang_Throwable::message(PENDING_EXCEPTION))); // We cannot continue to dump the archive anymore.
DynamicDumpSharedSpaces = false;
CLEAR_PENDING_EXCEPTION;
}
}
// This is called by "jcmd VM.cds dynamic_dump" void DynamicArchive::dump_for_jcmd(constchar* archive_name, TRAPS) {
assert(UseSharedSpaces && RecordDynamicDumpInfo, "already checked in arguments.cpp");
assert(ArchiveClassesAtExit == nullptr, "already checked in arguments.cpp");
assert(DynamicDumpSharedSpaces, "already checked by check_for_dynamic_dump() during VM startup");
MetaspaceShared::link_shared_classes(true/*from jcmd*/, CHECK);
dump(archive_name, THREAD);
}
bool DynamicArchive::validate(FileMapInfo* dynamic_info) {
assert(!dynamic_info->is_static(), "must be"); // Check if the recorded base archive matches with the current one
FileMapInfo* base_info = FileMapInfo::current_info();
DynamicArchiveHeader* dynamic_header = dynamic_info->dynamic_header();
// Check the header crc if (dynamic_header->base_header_crc() != base_info->crc()) {
FileMapInfo::fail_continue("Dynamic archive cannot be used: static archive header checksum verification failed."); returnfalse;
}
// Check each space's crc for (int i = 0; i < MetaspaceShared::n_regions; i++) { if (dynamic_header->base_region_crc(i) != base_info->region_crc(i)) {
FileMapInfo::fail_continue("Dynamic archive cannot be used: static archive region #%d checksum verification failed.", i); returnfalse;
}
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.