Path: blob/master/src/hotspot/share/cds/dynamicArchive.cpp
41145 views
/*1* Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*22*/2324#include "precompiled.hpp"25#include "jvm.h"26#include "cds/archiveBuilder.hpp"27#include "cds/archiveUtils.inline.hpp"28#include "cds/dynamicArchive.hpp"29#include "cds/lambdaFormInvokers.hpp"30#include "cds/metaspaceShared.hpp"31#include "classfile/classLoaderData.inline.hpp"32#include "classfile/symbolTable.hpp"33#include "classfile/systemDictionaryShared.hpp"34#include "classfile/vmSymbols.hpp"35#include "gc/shared/collectedHeap.hpp"36#include "gc/shared/gcVMOperations.hpp"37#include "gc/shared/gc_globals.hpp"38#include "logging/log.hpp"39#include "memory/metaspaceClosure.hpp"40#include "memory/resourceArea.hpp"41#include "oops/klass.inline.hpp"42#include "runtime/arguments.hpp"43#include "runtime/os.hpp"44#include "runtime/sharedRuntime.hpp"45#include "runtime/vmThread.hpp"46#include "runtime/vmOperations.hpp"47#include "utilities/align.hpp"48#include "utilities/bitMap.inline.hpp"495051class DynamicArchiveBuilder : public ArchiveBuilder {52public:53void mark_pointer(address* ptr_loc) {54ArchivePtrMarker::mark_pointer(ptr_loc);55}5657template <typename T> T get_dumped_addr(T obj) {58return (T)ArchiveBuilder::get_dumped_addr((address)obj);59}6061static int dynamic_dump_method_comparator(Method* a, Method* b) {62Symbol* a_name = a->name();63Symbol* b_name = b->name();6465if (a_name == b_name) {66return 0;67}6869u4 a_offset = ArchiveBuilder::current()->any_to_offset_u4(a_name);70u4 b_offset = ArchiveBuilder::current()->any_to_offset_u4(b_name);7172if (a_offset < b_offset) {73return -1;74} else {75assert(a_offset > b_offset, "must be");76return 1;77}78}7980public:81DynamicArchiveHeader *_header;8283void init_header();84void release_header();85void sort_methods();86void sort_methods(InstanceKlass* ik) const;87void remark_pointers_for_instance_klass(InstanceKlass* k, bool should_mark) const;88void write_archive(char* serialized_data);8990public:91DynamicArchiveBuilder() : ArchiveBuilder() { }9293// Do this before and after the archive dump to see if any corruption94// is caused by dynamic dumping.95void verify_universe(const char* info) {96if (VerifyBeforeExit) {97log_info(cds)("Verify %s", info);98// Among other things, this ensures that Eden top is correct.99Universe::heap()->prepare_for_verify();100Universe::verify(info);101}102}103104void doit() {105SystemDictionaryShared::start_dumping();106107verify_universe("Before CDS dynamic dump");108DEBUG_ONLY(SystemDictionaryShared::NoClassLoadingMark nclm);109SystemDictionaryShared::check_excluded_classes();110111init_header();112gather_source_objs();113reserve_buffer();114115log_info(cds, dynamic)("Copying %d klasses and %d symbols",116klasses()->length(), symbols()->length());117dump_rw_metadata();118dump_ro_metadata();119relocate_metaspaceobj_embedded_pointers();120relocate_roots();121122verify_estimate_size(_estimated_metaspaceobj_bytes, "MetaspaceObjs");123124char* serialized_data;125{126// Write the symbol table and system dictionaries to the RO space.127// Note that these tables still point to the *original* objects, so128// they would need to call DynamicArchive::original_to_target() to129// get the correct addresses.130assert(current_dump_space() == ro_region(), "Must be RO space");131SymbolTable::write_to_archive(symbols());132133ArchiveBuilder::OtherROAllocMark mark;134SystemDictionaryShared::write_to_archive(false);135136serialized_data = ro_region()->top();137WriteClosure wc(ro_region());138SymbolTable::serialize_shared_table_header(&wc, false);139SystemDictionaryShared::serialize_dictionary_headers(&wc, false);140}141142verify_estimate_size(_estimated_hashtable_bytes, "Hashtables");143144sort_methods();145146log_info(cds)("Make classes shareable");147make_klasses_shareable();148149log_info(cds)("Adjust lambda proxy class dictionary");150SystemDictionaryShared::adjust_lambda_proxy_class_dictionary();151152relocate_to_requested();153154write_archive(serialized_data);155release_header();156157assert(_num_dump_regions_used == _total_dump_regions, "must be");158verify_universe("After CDS dynamic dump");159}160161virtual void iterate_roots(MetaspaceClosure* it, bool is_relocating_pointers) {162FileMapInfo::metaspace_pointers_do(it);163SystemDictionaryShared::dumptime_classes_do(it);164}165};166167void DynamicArchiveBuilder::init_header() {168FileMapInfo* mapinfo = new FileMapInfo(false);169assert(FileMapInfo::dynamic_info() == mapinfo, "must be");170_header = mapinfo->dynamic_header();171172FileMapInfo* base_info = FileMapInfo::current_info();173_header->set_base_header_crc(base_info->crc());174for (int i = 0; i < MetaspaceShared::n_regions; i++) {175_header->set_base_region_crc(i, base_info->space_crc(i));176}177_header->populate(base_info, base_info->core_region_alignment());178}179180void DynamicArchiveBuilder::release_header() {181// We temporarily allocated a dynamic FileMapInfo for dumping, which makes it appear we182// have mapped a dynamic archive, but we actually have not. We are in a safepoint now.183// Let's free it so that if class loading happens after we leave the safepoint, nothing184// bad will happen.185assert(SafepointSynchronize::is_at_safepoint(), "must be");186FileMapInfo *mapinfo = FileMapInfo::dynamic_info();187assert(mapinfo != NULL && _header == mapinfo->dynamic_header(), "must be");188delete mapinfo;189assert(!DynamicArchive::is_mapped(), "must be");190_header = NULL;191}192193void DynamicArchiveBuilder::sort_methods() {194InstanceKlass::disable_method_binary_search();195for (int i = 0; i < klasses()->length(); i++) {196Klass* k = klasses()->at(i);197if (k->is_instance_klass()) {198sort_methods(InstanceKlass::cast(k));199}200}201}202203// The address order of the copied Symbols may be different than when the original204// klasses were created. Re-sort all the tables. See Method::sort_methods().205void DynamicArchiveBuilder::sort_methods(InstanceKlass* ik) const {206assert(ik != NULL, "DynamicArchiveBuilder currently doesn't support dumping the base archive");207if (MetaspaceShared::is_in_shared_metaspace(ik)) {208// We have reached a supertype that's already in the base archive209return;210}211212if (ik->java_mirror() == NULL) {213// NULL mirror means this class has already been visited and methods are already sorted214return;215}216ik->remove_java_mirror();217218if (log_is_enabled(Debug, cds, dynamic)) {219ResourceMark rm;220log_debug(cds, dynamic)("sorting methods for " PTR_FORMAT " (" PTR_FORMAT ") %s",221p2i(ik), p2i(to_requested(ik)), ik->external_name());222}223224// Method sorting may re-layout the [iv]tables, which would change the offset(s)225// of the locations in an InstanceKlass that would contain pointers. Let's clear226// all the existing pointer marking bits, and re-mark the pointers after sorting.227remark_pointers_for_instance_klass(ik, false);228229// Make sure all supertypes have been sorted230sort_methods(ik->java_super());231Array<InstanceKlass*>* interfaces = ik->local_interfaces();232int len = interfaces->length();233for (int i = 0; i < len; i++) {234sort_methods(interfaces->at(i));235}236237#ifdef ASSERT238if (ik->methods() != NULL) {239for (int m = 0; m < ik->methods()->length(); m++) {240Symbol* name = ik->methods()->at(m)->name();241assert(MetaspaceShared::is_in_shared_metaspace(name) || is_in_buffer_space(name), "must be");242}243}244if (ik->default_methods() != NULL) {245for (int m = 0; m < ik->default_methods()->length(); m++) {246Symbol* name = ik->default_methods()->at(m)->name();247assert(MetaspaceShared::is_in_shared_metaspace(name) || is_in_buffer_space(name), "must be");248}249}250#endif251252Method::sort_methods(ik->methods(), /*set_idnums=*/true, dynamic_dump_method_comparator);253if (ik->default_methods() != NULL) {254Method::sort_methods(ik->default_methods(), /*set_idnums=*/false, dynamic_dump_method_comparator);255}256ik->vtable().initialize_vtable();257ik->itable().initialize_itable();258259// Set all the pointer marking bits after sorting.260remark_pointers_for_instance_klass(ik, true);261}262263template<bool should_mark>264class PointerRemarker: public MetaspaceClosure {265public:266virtual bool do_ref(Ref* ref, bool read_only) {267if (should_mark) {268ArchivePtrMarker::mark_pointer(ref->addr());269} else {270ArchivePtrMarker::clear_pointer(ref->addr());271}272return false; // don't recurse273}274};275276void DynamicArchiveBuilder::remark_pointers_for_instance_klass(InstanceKlass* k, bool should_mark) const {277if (should_mark) {278PointerRemarker<true> marker;279k->metaspace_pointers_do(&marker);280marker.finish();281} else {282PointerRemarker<false> marker;283k->metaspace_pointers_do(&marker);284marker.finish();285}286}287288void DynamicArchiveBuilder::write_archive(char* serialized_data) {289Array<u8>* table = FileMapInfo::saved_shared_path_table().table();290SharedPathTable runtime_table(table, FileMapInfo::shared_path_table().size());291_header->set_shared_path_table(runtime_table);292_header->set_serialized_data(serialized_data);293294FileMapInfo* dynamic_info = FileMapInfo::dynamic_info();295assert(dynamic_info != NULL, "Sanity");296297dynamic_info->open_for_write(Arguments::GetSharedDynamicArchivePath());298ArchiveBuilder::write_archive(dynamic_info, NULL, NULL, NULL, NULL);299300address base = _requested_dynamic_archive_bottom;301address top = _requested_dynamic_archive_top;302size_t file_size = pointer_delta(top, base, sizeof(char));303304log_info(cds, dynamic)("Written dynamic archive " PTR_FORMAT " - " PTR_FORMAT305" [" SIZE_FORMAT " bytes header, " SIZE_FORMAT " bytes total]",306p2i(base), p2i(top), _header->header_size(), file_size);307308log_info(cds, dynamic)("%d klasses; %d symbols", klasses()->length(), symbols()->length());309}310311class VM_PopulateDynamicDumpSharedSpace: public VM_GC_Sync_Operation {312DynamicArchiveBuilder builder;313public:314VM_PopulateDynamicDumpSharedSpace() : VM_GC_Sync_Operation() {}315VMOp_Type type() const { return VMOp_PopulateDumpSharedSpace; }316void doit() {317ResourceMark rm;318if (SystemDictionaryShared::empty_dumptime_table()) {319log_warning(cds, dynamic)("There is no class to be included in the dynamic archive.");320return;321}322if (AllowArchivingWithJavaAgent) {323warning("This archive was created with AllowArchivingWithJavaAgent. It should be used "324"for testing purposes only and should not be used in a production environment");325}326FileMapInfo::check_nonempty_dir_in_shared_path_table();327328builder.doit();329}330};331332void DynamicArchive::prepare_for_dynamic_dumping_at_exit() {333EXCEPTION_MARK;334ResourceMark rm(THREAD);335MetaspaceShared::link_and_cleanup_shared_classes(THREAD);336if (HAS_PENDING_EXCEPTION) {337log_error(cds)("ArchiveClassesAtExit has failed");338log_error(cds)("%s: %s", PENDING_EXCEPTION->klass()->external_name(),339java_lang_String::as_utf8_string(java_lang_Throwable::message(PENDING_EXCEPTION)));340// We cannot continue to dump the archive anymore.341DynamicDumpSharedSpaces = false;342CLEAR_PENDING_EXCEPTION;343}344}345346bool DynamicArchive::_has_been_dumped_once = false;347348void DynamicArchive::dump(const char* archive_name, TRAPS) {349assert(UseSharedSpaces && RecordDynamicDumpInfo, "already checked in arguments.cpp?");350assert(ArchiveClassesAtExit == nullptr, "already checked in arguments.cpp?");351// During dynamic archive dumping, some of the data structures are overwritten so352// we cannot dump the dynamic archive again. TODO: this should be fixed.353if (has_been_dumped_once()) {354THROW_MSG(vmSymbols::java_lang_RuntimeException(),355"Dynamic dump has been done, and should only be done once");356} else {357// prevent multiple dumps.358set_has_been_dumped_once();359ArchiveClassesAtExit = archive_name;360if (Arguments::init_shared_archive_paths()) {361dump();362} else {363ArchiveClassesAtExit = nullptr;364THROW_MSG(vmSymbols::java_lang_RuntimeException(),365"Could not setup SharedDynamicArchivePath");366}367// prevent do dynamic dump at exit.368ArchiveClassesAtExit = nullptr;369if (!Arguments::init_shared_archive_paths()) {370THROW_MSG(vmSymbols::java_lang_RuntimeException(),371"Could not restore SharedDynamicArchivePath");372}373}374}375376void DynamicArchive::dump() {377if (Arguments::GetSharedDynamicArchivePath() == NULL) {378log_warning(cds, dynamic)("SharedDynamicArchivePath is not specified");379return;380}381382VM_PopulateDynamicDumpSharedSpace op;383VMThread::execute(&op);384}385386bool DynamicArchive::validate(FileMapInfo* dynamic_info) {387assert(!dynamic_info->is_static(), "must be");388// Check if the recorded base archive matches with the current one389FileMapInfo* base_info = FileMapInfo::current_info();390DynamicArchiveHeader* dynamic_header = dynamic_info->dynamic_header();391392// Check the header crc393if (dynamic_header->base_header_crc() != base_info->crc()) {394FileMapInfo::fail_continue("Dynamic archive cannot be used: static archive header checksum verification failed.");395return false;396}397398// Check each space's crc399for (int i = 0; i < MetaspaceShared::n_regions; i++) {400if (dynamic_header->base_region_crc(i) != base_info->space_crc(i)) {401FileMapInfo::fail_continue("Dynamic archive cannot be used: static archive region #%d checksum verification failed.", i);402return false;403}404}405406return true;407}408409410