Path: blob/master/src/hotspot/share/cds/dynamicArchive.cpp
64440 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);109110// Block concurrent class unloading from changing the _dumptime_table111MutexLocker ml(DumpTimeTable_lock, Mutex::_no_safepoint_check_flag);112SystemDictionaryShared::check_excluded_classes();113SystemDictionaryShared::cleanup_lambda_proxy_class_dictionary();114115init_header();116gather_source_objs();117reserve_buffer();118119log_info(cds, dynamic)("Copying %d klasses and %d symbols",120klasses()->length(), symbols()->length());121dump_rw_metadata();122dump_ro_metadata();123relocate_metaspaceobj_embedded_pointers();124relocate_roots();125126verify_estimate_size(_estimated_metaspaceobj_bytes, "MetaspaceObjs");127128char* serialized_data;129{130// Write the symbol table and system dictionaries to the RO space.131// Note that these tables still point to the *original* objects, so132// they would need to call DynamicArchive::original_to_target() to133// get the correct addresses.134assert(current_dump_space() == ro_region(), "Must be RO space");135SymbolTable::write_to_archive(symbols());136137ArchiveBuilder::OtherROAllocMark mark;138SystemDictionaryShared::write_to_archive(false);139140serialized_data = ro_region()->top();141WriteClosure wc(ro_region());142SymbolTable::serialize_shared_table_header(&wc, false);143SystemDictionaryShared::serialize_dictionary_headers(&wc, false);144}145146verify_estimate_size(_estimated_hashtable_bytes, "Hashtables");147148sort_methods();149150log_info(cds)("Make classes shareable");151make_klasses_shareable();152153log_info(cds)("Adjust lambda proxy class dictionary");154SystemDictionaryShared::adjust_lambda_proxy_class_dictionary();155156relocate_to_requested();157158write_archive(serialized_data);159release_header();160161assert(_num_dump_regions_used == _total_dump_regions, "must be");162verify_universe("After CDS dynamic dump");163}164165virtual void iterate_roots(MetaspaceClosure* it, bool is_relocating_pointers) {166FileMapInfo::metaspace_pointers_do(it);167SystemDictionaryShared::dumptime_classes_do(it);168}169};170171void DynamicArchiveBuilder::init_header() {172FileMapInfo* mapinfo = new FileMapInfo(false);173assert(FileMapInfo::dynamic_info() == mapinfo, "must be");174_header = mapinfo->dynamic_header();175176FileMapInfo* base_info = FileMapInfo::current_info();177_header->set_base_header_crc(base_info->crc());178for (int i = 0; i < MetaspaceShared::n_regions; i++) {179_header->set_base_region_crc(i, base_info->space_crc(i));180}181_header->populate(base_info, base_info->core_region_alignment());182}183184void DynamicArchiveBuilder::release_header() {185// We temporarily allocated a dynamic FileMapInfo for dumping, which makes it appear we186// have mapped a dynamic archive, but we actually have not. We are in a safepoint now.187// Let's free it so that if class loading happens after we leave the safepoint, nothing188// bad will happen.189assert(SafepointSynchronize::is_at_safepoint(), "must be");190FileMapInfo *mapinfo = FileMapInfo::dynamic_info();191assert(mapinfo != NULL && _header == mapinfo->dynamic_header(), "must be");192delete mapinfo;193assert(!DynamicArchive::is_mapped(), "must be");194_header = NULL;195}196197void DynamicArchiveBuilder::sort_methods() {198InstanceKlass::disable_method_binary_search();199for (int i = 0; i < klasses()->length(); i++) {200Klass* k = klasses()->at(i);201if (k->is_instance_klass()) {202sort_methods(InstanceKlass::cast(k));203}204}205}206207// The address order of the copied Symbols may be different than when the original208// klasses were created. Re-sort all the tables. See Method::sort_methods().209void DynamicArchiveBuilder::sort_methods(InstanceKlass* ik) const {210assert(ik != NULL, "DynamicArchiveBuilder currently doesn't support dumping the base archive");211if (MetaspaceShared::is_in_shared_metaspace(ik)) {212// We have reached a supertype that's already in the base archive213return;214}215216if (ik->java_mirror() == NULL) {217// NULL mirror means this class has already been visited and methods are already sorted218return;219}220ik->remove_java_mirror();221222if (log_is_enabled(Debug, cds, dynamic)) {223ResourceMark rm;224log_debug(cds, dynamic)("sorting methods for " PTR_FORMAT " (" PTR_FORMAT ") %s",225p2i(ik), p2i(to_requested(ik)), ik->external_name());226}227228// Method sorting may re-layout the [iv]tables, which would change the offset(s)229// of the locations in an InstanceKlass that would contain pointers. Let's clear230// all the existing pointer marking bits, and re-mark the pointers after sorting.231remark_pointers_for_instance_klass(ik, false);232233// Make sure all supertypes have been sorted234sort_methods(ik->java_super());235Array<InstanceKlass*>* interfaces = ik->local_interfaces();236int len = interfaces->length();237for (int i = 0; i < len; i++) {238sort_methods(interfaces->at(i));239}240241#ifdef ASSERT242if (ik->methods() != NULL) {243for (int m = 0; m < ik->methods()->length(); m++) {244Symbol* name = ik->methods()->at(m)->name();245assert(MetaspaceShared::is_in_shared_metaspace(name) || is_in_buffer_space(name), "must be");246}247}248if (ik->default_methods() != NULL) {249for (int m = 0; m < ik->default_methods()->length(); m++) {250Symbol* name = ik->default_methods()->at(m)->name();251assert(MetaspaceShared::is_in_shared_metaspace(name) || is_in_buffer_space(name), "must be");252}253}254#endif255256Method::sort_methods(ik->methods(), /*set_idnums=*/true, dynamic_dump_method_comparator);257if (ik->default_methods() != NULL) {258Method::sort_methods(ik->default_methods(), /*set_idnums=*/false, dynamic_dump_method_comparator);259}260ik->vtable().initialize_vtable();261ik->itable().initialize_itable();262263// Set all the pointer marking bits after sorting.264remark_pointers_for_instance_klass(ik, true);265}266267template<bool should_mark>268class PointerRemarker: public MetaspaceClosure {269public:270virtual bool do_ref(Ref* ref, bool read_only) {271if (should_mark) {272ArchivePtrMarker::mark_pointer(ref->addr());273} else {274ArchivePtrMarker::clear_pointer(ref->addr());275}276return false; // don't recurse277}278};279280void DynamicArchiveBuilder::remark_pointers_for_instance_klass(InstanceKlass* k, bool should_mark) const {281if (should_mark) {282PointerRemarker<true> marker;283k->metaspace_pointers_do(&marker);284marker.finish();285} else {286PointerRemarker<false> marker;287k->metaspace_pointers_do(&marker);288marker.finish();289}290}291292void DynamicArchiveBuilder::write_archive(char* serialized_data) {293Array<u8>* table = FileMapInfo::saved_shared_path_table().table();294SharedPathTable runtime_table(table, FileMapInfo::shared_path_table().size());295_header->set_shared_path_table(runtime_table);296_header->set_serialized_data(serialized_data);297298FileMapInfo* dynamic_info = FileMapInfo::dynamic_info();299assert(dynamic_info != NULL, "Sanity");300301dynamic_info->open_for_write(Arguments::GetSharedDynamicArchivePath());302ArchiveBuilder::write_archive(dynamic_info, NULL, NULL, NULL, NULL);303304address base = _requested_dynamic_archive_bottom;305address top = _requested_dynamic_archive_top;306size_t file_size = pointer_delta(top, base, sizeof(char));307308log_info(cds, dynamic)("Written dynamic archive " PTR_FORMAT " - " PTR_FORMAT309" [" SIZE_FORMAT " bytes header, " SIZE_FORMAT " bytes total]",310p2i(base), p2i(top), _header->header_size(), file_size);311312log_info(cds, dynamic)("%d klasses; %d symbols", klasses()->length(), symbols()->length());313}314315class VM_PopulateDynamicDumpSharedSpace: public VM_GC_Sync_Operation {316DynamicArchiveBuilder builder;317public:318VM_PopulateDynamicDumpSharedSpace() : VM_GC_Sync_Operation() {}319VMOp_Type type() const { return VMOp_PopulateDumpSharedSpace; }320void doit() {321ResourceMark rm;322if (SystemDictionaryShared::empty_dumptime_table()) {323log_warning(cds, dynamic)("There is no class to be included in the dynamic archive.");324return;325}326if (AllowArchivingWithJavaAgent) {327warning("This archive was created with AllowArchivingWithJavaAgent. It should be used "328"for testing purposes only and should not be used in a production environment");329}330FileMapInfo::check_nonempty_dir_in_shared_path_table();331332builder.doit();333}334};335336void DynamicArchive::prepare_for_dynamic_dumping_at_exit() {337EXCEPTION_MARK;338ResourceMark rm(THREAD);339MetaspaceShared::link_and_cleanup_shared_classes(THREAD);340if (HAS_PENDING_EXCEPTION) {341log_error(cds)("ArchiveClassesAtExit has failed");342log_error(cds)("%s: %s", PENDING_EXCEPTION->klass()->external_name(),343java_lang_String::as_utf8_string(java_lang_Throwable::message(PENDING_EXCEPTION)));344// We cannot continue to dump the archive anymore.345DynamicDumpSharedSpaces = false;346CLEAR_PENDING_EXCEPTION;347}348}349350bool DynamicArchive::_has_been_dumped_once = false;351352void DynamicArchive::dump(const char* archive_name, TRAPS) {353assert(UseSharedSpaces && RecordDynamicDumpInfo, "already checked in arguments.cpp?");354assert(ArchiveClassesAtExit == nullptr, "already checked in arguments.cpp?");355// During dynamic archive dumping, some of the data structures are overwritten so356// we cannot dump the dynamic archive again. TODO: this should be fixed.357if (has_been_dumped_once()) {358THROW_MSG(vmSymbols::java_lang_RuntimeException(),359"Dynamic dump has been done, and should only be done once");360} else {361// prevent multiple dumps.362set_has_been_dumped_once();363ArchiveClassesAtExit = archive_name;364if (Arguments::init_shared_archive_paths()) {365dump();366} else {367ArchiveClassesAtExit = nullptr;368THROW_MSG(vmSymbols::java_lang_RuntimeException(),369"Could not setup SharedDynamicArchivePath");370}371// prevent do dynamic dump at exit.372ArchiveClassesAtExit = nullptr;373if (!Arguments::init_shared_archive_paths()) {374THROW_MSG(vmSymbols::java_lang_RuntimeException(),375"Could not restore SharedDynamicArchivePath");376}377}378}379380void DynamicArchive::dump() {381if (Arguments::GetSharedDynamicArchivePath() == NULL) {382log_warning(cds, dynamic)("SharedDynamicArchivePath is not specified");383return;384}385386VM_PopulateDynamicDumpSharedSpace op;387VMThread::execute(&op);388}389390bool DynamicArchive::validate(FileMapInfo* dynamic_info) {391assert(!dynamic_info->is_static(), "must be");392// Check if the recorded base archive matches with the current one393FileMapInfo* base_info = FileMapInfo::current_info();394DynamicArchiveHeader* dynamic_header = dynamic_info->dynamic_header();395396// Check the header crc397if (dynamic_header->base_header_crc() != base_info->crc()) {398FileMapInfo::fail_continue("Dynamic archive cannot be used: static archive header checksum verification failed.");399return false;400}401402// Check each space's crc403for (int i = 0; i < MetaspaceShared::n_regions; i++) {404if (dynamic_header->base_region_crc(i) != base_info->space_crc(i)) {405FileMapInfo::fail_continue("Dynamic archive cannot be used: static archive region #%d checksum verification failed.", i);406return false;407}408}409410return true;411}412413414