diff --git a/src/hotspot/share/classfile/javaClasses.cpp b/src/hotspot/share/classfile/javaClasses.cpp index 0aed2e9e2ef34..de63869507312 100644 --- a/src/hotspot/share/classfile/javaClasses.cpp +++ b/src/hotspot/share/classfile/javaClasses.cpp @@ -1179,8 +1179,7 @@ oop java_lang_Class::archive_mirror(Klass* k, TRAPS) { if (!(ik->is_shared_boot_class() || ik->is_shared_platform_class() || ik->is_shared_app_class())) { // Archiving mirror for classes from non-builtin loaders is not - // supported. Clear the _java_mirror within the archived class. - k->clear_java_mirror_handle(); + // supported. return NULL; } } diff --git a/src/hotspot/share/memory/archiveBuilder.cpp b/src/hotspot/share/memory/archiveBuilder.cpp index adf3b63b08c9e..2aab63d8151eb 100644 --- a/src/hotspot/share/memory/archiveBuilder.cpp +++ b/src/hotspot/share/memory/archiveBuilder.cpp @@ -41,6 +41,7 @@ #include "utilities/hashtable.inline.hpp" ArchiveBuilder* ArchiveBuilder::_singleton = NULL; +intx ArchiveBuilder::_buffer_to_target_delta = 0; ArchiveBuilder::OtherROAllocMark::~OtherROAllocMark() { char* newtop = ArchiveBuilder::singleton()->_ro_region->top(); @@ -564,6 +565,34 @@ void ArchiveBuilder::relocate_well_known_klasses() { SystemDictionary::well_known_klasses_do(&doit); } +void ArchiveBuilder::make_klasses_shareable() { + for (int i = 0; i < klasses()->length(); i++) { + Klass* k = klasses()->at(i); + k->remove_java_mirror(); + if (k->is_objArray_klass()) { + // InstanceKlass and TypeArrayKlass will in turn call remove_unshareable_info + // on their array classes. + } else if (k->is_typeArray_klass()) { + k->remove_unshareable_info(); + } else { + assert(k->is_instance_klass(), " must be"); + InstanceKlass* ik = InstanceKlass::cast(k); + if (DynamicDumpSharedSpaces) { + // For static dump, class loader type are already set. + ik->assign_class_loader_type(); + } + + MetaspaceShared::rewrite_nofast_bytecodes_and_calculate_fingerprints(Thread::current(), ik); + ik->remove_unshareable_info(); + + if (log_is_enabled(Debug, cds, class)) { + ResourceMark rm; + log_debug(cds, class)("klasses[%4d] = " PTR_FORMAT " %s", i, p2i(to_target(ik)), ik->external_name()); + } + } + } +} + void ArchiveBuilder::print_stats(int ro_all, int rw_all, int mc_all) { _alloc_stats->print_stats(ro_all, rw_all, mc_all); } diff --git a/src/hotspot/share/memory/archiveBuilder.hpp b/src/hotspot/share/memory/archiveBuilder.hpp index 36478db314762..c00b85375bbe9 100644 --- a/src/hotspot/share/memory/archiveBuilder.hpp +++ b/src/hotspot/share/memory/archiveBuilder.hpp @@ -193,6 +193,37 @@ class ArchiveBuilder : public StackObj { _ro_region = ro_region; } +protected: + DumpRegion* _current_dump_space; + address _alloc_bottom; + + DumpRegion* current_dump_space() const { return _current_dump_space; } + +public: + void set_current_dump_space(DumpRegion* r) { _current_dump_space = r; } + + bool is_in_buffer_space(address p) const { + return (_alloc_bottom <= p && p < (address)current_dump_space()->top()); + } + + template bool is_in_target_space(T target_obj) const { + address buff_obj = address(target_obj) - _buffer_to_target_delta; + return is_in_buffer_space(buff_obj); + } + + template bool is_in_buffer_space(T obj) const { + return is_in_buffer_space(address(obj)); + } + + template T to_target_no_check(T obj) const { + return (T)(address(obj) + _buffer_to_target_delta); + } + + template T to_target(T obj) const { + assert(is_in_buffer_space(obj), "must be"); + return (T)(address(obj) + _buffer_to_target_delta); + } + public: ArchiveBuilder(DumpRegion* rw_region, DumpRegion* ro_region); ~ArchiveBuilder(); @@ -208,7 +239,7 @@ class ArchiveBuilder : public StackObj { void dump_ro_region(); void relocate_pointers(); void relocate_well_known_klasses(); - + void make_klasses_shareable(); address get_dumped_addr(address src_obj) const; // All klasses and symbols that will be copied into the archive @@ -235,6 +266,7 @@ class ArchiveBuilder : public StackObj { } void print_stats(int ro_all, int rw_all, int mc_all); + static intx _buffer_to_target_delta; }; #endif // SHARE_MEMORY_ARCHIVEBUILDER_HPP diff --git a/src/hotspot/share/memory/dynamicArchive.cpp b/src/hotspot/share/memory/dynamicArchive.cpp index 5703e6e52981b..737a663f7817e 100644 --- a/src/hotspot/share/memory/dynamicArchive.cpp +++ b/src/hotspot/share/memory/dynamicArchive.cpp @@ -44,8 +44,6 @@ class DynamicArchiveBuilder : public ArchiveBuilder { public: - static intx _buffer_to_target_delta; - DumpRegion* _current_dump_space; static size_t reserve_alignment() { return os::vm_allocation_granularity(); @@ -59,32 +57,6 @@ class DynamicArchiveBuilder : public ArchiveBuilder { ArchivePtrMarker::mark_pointer(ptr_loc); } - DumpRegion* current_dump_space() const { - return _current_dump_space; - } - - bool is_in_buffer_space(address p) const { - return (_alloc_bottom <= p && p < (address)current_dump_space()->top()); - } - - template bool is_in_target_space(T target_obj) const { - address buff_obj = address(target_obj) - _buffer_to_target_delta; - return is_in_buffer_space(buff_obj); - } - - template bool is_in_buffer_space(T obj) const { - return is_in_buffer_space(address(obj)); - } - - template T to_target_no_check(T obj) const { - return (T)(address(obj) + _buffer_to_target_delta); - } - - template T to_target(T obj) const { - assert(is_in_buffer_space(obj), "must be"); - return (T)(address(obj) + _buffer_to_target_delta); - } - template T get_dumped_addr(T obj) { return (T)ArchiveBuilder::get_dumped_addr((address)obj); } @@ -113,7 +85,6 @@ class DynamicArchiveBuilder : public ArchiveBuilder { public: DynamicArchiveHeader *_header; - address _alloc_bottom; address _last_verified_top; size_t _other_region_used_bytes; @@ -128,7 +99,7 @@ class DynamicArchiveBuilder : public ArchiveBuilder { void init_header(address addr); void release_header(); void make_trampolines(); - void make_klasses_shareable(); + void sort_methods(); void sort_methods(InstanceKlass* ik) const; void remark_pointers_for_instance_klass(InstanceKlass* k, bool should_mark) const; void relocate_buffer_to_target(); @@ -250,6 +221,7 @@ class DynamicArchiveBuilder : public ArchiveBuilder { verify_estimate_size(_estimated_hashtable_bytes, "Hashtables"); make_trampolines(); + sort_methods(); log_info(cds)("Make classes shareable"); make_klasses_shareable(); @@ -275,8 +247,6 @@ class DynamicArchiveBuilder : public ArchiveBuilder { } }; -intx DynamicArchiveBuilder::_buffer_to_target_delta; - size_t DynamicArchiveBuilder::estimate_archive_size() { // size of the symbol table and two dictionaries, plus the RunTimeSharedClassInfo's _estimated_hashtable_bytes = 0; @@ -408,35 +378,14 @@ void DynamicArchiveBuilder::make_trampolines() { guarantee(p <= mc_space->top(), "Estimate of trampoline size is insufficient"); } -void DynamicArchiveBuilder::make_klasses_shareable() { - int i, count = klasses()->length(); - +void DynamicArchiveBuilder::sort_methods() { InstanceKlass::disable_method_binary_search(); - for (i = 0; i < count; i++) { + for (int i = 0; i < klasses()->length(); i++) { Klass* k = klasses()->at(i); if (k->is_instance_klass()) { sort_methods(InstanceKlass::cast(k)); } } - - for (i = 0; i < count; i++) { - Klass* k = klasses()->at(i); - if (!k->is_instance_klass()) { - continue; - } - InstanceKlass* ik = InstanceKlass::cast(k); - ik->assign_class_loader_type(); - - MetaspaceShared::rewrite_nofast_bytecodes_and_calculate_fingerprints(Thread::current(), ik); - ik->remove_unshareable_info(); - - assert(ik->array_klasses() == NULL, "sanity"); - - if (log_is_enabled(Debug, cds, dynamic)) { - ResourceMark rm; - log_debug(cds, dynamic)("klasses[%4i] = " PTR_FORMAT " %s", i, p2i(to_target(ik)), ik->external_name()); - } - } } // The address order of the copied Symbols may be different than when the original diff --git a/src/hotspot/share/memory/heapShared.cpp b/src/hotspot/share/memory/heapShared.cpp index dfd398db1388f..905d1aef56c92 100644 --- a/src/hotspot/share/memory/heapShared.cpp +++ b/src/hotspot/share/memory/heapShared.cpp @@ -36,6 +36,7 @@ #include "logging/log.hpp" #include "logging/logMessage.hpp" #include "logging/logStream.hpp" +#include "memory/archiveBuilder.hpp" #include "memory/archiveUtils.hpp" #include "memory/filemap.hpp" #include "memory/heapShared.inline.hpp" @@ -398,7 +399,7 @@ void KlassSubGraphInfo::add_subgraph_object_klass(Klass* orig_k, Klass *relocate new(ResourceObj::C_HEAP, mtClass) GrowableArray(50, mtClass); } - assert(relocated_k->is_shared(), "must be a shared class"); + assert(ArchiveBuilder::singleton()->is_in_buffer_space(relocated_k), "must be a shared class"); if (_k == relocated_k) { // Don't add the Klass containing the sub-graph to it's own klass diff --git a/src/hotspot/share/memory/metaspaceShared.cpp b/src/hotspot/share/memory/metaspaceShared.cpp index c80e1b108b9c9..9fa221a921c87 100644 --- a/src/hotspot/share/memory/metaspaceShared.cpp +++ b/src/hotspot/share/memory/metaspaceShared.cpp @@ -544,30 +544,6 @@ GrowableArray* MetaspaceShared::collected_klasses() { return _global_klass_objects; } -static void remove_unshareable_in_classes() { - for (int i = 0; i < _global_klass_objects->length(); i++) { - Klass* k = _global_klass_objects->at(i); - if (!k->is_objArray_klass()) { - // InstanceKlass and TypeArrayKlass will in turn call remove_unshareable_info - // on their array classes. - assert(k->is_instance_klass() || k->is_typeArray_klass(), "must be"); - k->remove_unshareable_info(); - } - } -} - -static void remove_java_mirror_in_classes() { - for (int i = 0; i < _global_klass_objects->length(); i++) { - Klass* k = _global_klass_objects->at(i); - if (!k->is_objArray_klass()) { - // InstanceKlass and TypeArrayKlass will in turn call remove_unshareable_info - // on their array classes. - assert(k->is_instance_klass() || k->is_typeArray_klass(), "must be"); - k->remove_java_mirror(); - } - } -} - static void rewrite_nofast_bytecode(const methodHandle& method) { BytecodeStream bcs(method); while (!bcs.is_last_bytecode()) { @@ -587,21 +563,9 @@ static void rewrite_nofast_bytecode(const methodHandle& method) { } } -// Walk all methods in the class list to ensure that they won't be modified at -// run time. This includes: // [1] Rewrite all bytecodes as needed, so that the ConstMethod* will not be modified // at run time by RewriteBytecodes/RewriteFrequentPairs // [2] Assign a fingerprint, so one doesn't need to be assigned at run-time. -static void rewrite_nofast_bytecodes_and_calculate_fingerprints(Thread* thread) { - for (int i = 0; i < _global_klass_objects->length(); i++) { - Klass* k = _global_klass_objects->at(i); - if (k->is_instance_klass()) { - InstanceKlass* ik = InstanceKlass::cast(k); - MetaspaceShared::rewrite_nofast_bytecodes_and_calculate_fingerprints(thread, ik); - } - } -} - void MetaspaceShared::rewrite_nofast_bytecodes_and_calculate_fingerprints(Thread* thread, InstanceKlass* ik) { for (int i = 0; i < ik->methods()->length(); i++) { methodHandle m(thread, ik->methods()->at(i)); @@ -645,7 +609,10 @@ class VM_PopulateDumpSharedSpace: public VM_Operation { class StaticArchiveBuilder : public ArchiveBuilder { public: StaticArchiveBuilder(DumpRegion* rw_region, DumpRegion* ro_region) - : ArchiveBuilder(rw_region, ro_region) {} + : ArchiveBuilder(rw_region, ro_region) { + _alloc_bottom = address(SharedBaseAddress); + _buffer_to_target_delta = 0; + } virtual void iterate_roots(MetaspaceClosure* it, bool is_relocating_pointers) { FileMapInfo::metaspace_pointers_do(it, false); @@ -669,13 +636,6 @@ class StaticArchiveBuilder : public ArchiveBuilder { char* VM_PopulateDumpSharedSpace::dump_read_only_tables() { ArchiveBuilder::OtherROAllocMark mark; - log_info(cds)("Removing java_mirror ... "); - if (!HeapShared::is_heap_object_archiving_allowed()) { - Universe::clear_basic_type_mirrors(); - } - remove_java_mirror_in_classes(); - log_info(cds)("done. "); - SystemDictionaryShared::write_to_archive(); // Write the other data to the output array. @@ -765,19 +725,10 @@ void VM_PopulateDumpSharedSpace::doit() { SystemDictionaryShared::check_excluded_classes(); StaticArchiveBuilder builder(&_rw_region, &_ro_region); + builder.set_current_dump_space(&_mc_region); builder.gather_klasses_and_symbols(); _global_klass_objects = builder.klasses(); - // Ensure the ConstMethods won't be modified at run-time - log_info(cds)("Updating ConstMethods ... "); - rewrite_nofast_bytecodes_and_calculate_fingerprints(THREAD); - log_info(cds)("done. "); - - // Remove all references outside the metadata - log_info(cds)("Removing unshareable information ... "); - remove_unshareable_in_classes(); - log_info(cds)("done. "); - builder.gather_source_objs(); CppVtables::allocate_cloned_cpp_vtptrs(); @@ -786,6 +737,7 @@ void VM_PopulateDumpSharedSpace::doit() { { _mc_region.pack(&_rw_region); + builder.set_current_dump_space(&_rw_region); builder.dump_rw_region(); #if INCLUDE_CDS_JAVA_HEAP if (MetaspaceShared::use_full_module_graph()) { @@ -798,6 +750,7 @@ void VM_PopulateDumpSharedSpace::doit() { } { _rw_region.pack(&_ro_region); + builder.set_current_dump_space(&_ro_region); builder.dump_ro_region(); #if INCLUDE_CDS_JAVA_HEAP if (MetaspaceShared::use_full_module_graph()) { @@ -818,6 +771,9 @@ void VM_PopulateDumpSharedSpace::doit() { builder.relocate_well_known_klasses(); + log_info(cds)("Make classes shareable"); + builder.make_klasses_shareable(); + char* serialized_data = dump_read_only_tables(); _ro_region.pack(); @@ -871,9 +827,9 @@ void VM_PopulateDumpSharedSpace::doit() { "for testing purposes only and should not be used in a production environment"); } - // There may be other pending VM operations that operate on the InstanceKlasses, - // which will fail because InstanceKlasses::remove_unshareable_info() - // has been called. Forget these operations and exit the VM directly. + // There may be pending VM operations. We have changed some global states + // (such as SystemDictionary::_well_known_klasses) that may cause these VM operations + // to fail. For safety, forget these operations and exit the VM directly. vm_direct_exit(0); } diff --git a/src/hotspot/share/memory/universe.cpp b/src/hotspot/share/memory/universe.cpp index 69b800bc2686e..a96b1f631d3e9 100644 --- a/src/hotspot/share/memory/universe.cpp +++ b/src/hotspot/share/memory/universe.cpp @@ -185,15 +185,6 @@ void Universe::replace_mirror(BasicType t, oop new_mirror) { Universe::_mirrors[t].replace(new_mirror); } -// Not sure why CDS has to do this -void Universe::clear_basic_type_mirrors() { - for (int i = T_BOOLEAN; i < T_VOID+1; i++) { - if (!is_reference_type((BasicType)i)) { - Universe::_mirrors[i].replace(NULL); - } - } -} - void Universe::basic_type_classes_do(void f(Klass*)) { for (int i = T_BOOLEAN; i < T_LONG+1; i++) { f(_typeArrayKlassObjs[i]); @@ -245,7 +236,11 @@ void Universe::serialize(SerializeClosure* f) { _mirrors[i] = OopHandle(vm_global(), mirror_oop); } } else { - mirror_oop = _mirrors[i].resolve(); + if (HeapShared::is_heap_object_archiving_allowed()) { + mirror_oop = _mirrors[i].resolve(); + } else { + mirror_oop = NULL; + } f->do_oop(&mirror_oop); // write to archive } if (mirror_oop != NULL) { // may be null if archived heap is disabled diff --git a/src/hotspot/share/memory/universe.hpp b/src/hotspot/share/memory/universe.hpp index 42b3e635ebbd8..2925c055eeb2f 100644 --- a/src/hotspot/share/memory/universe.hpp +++ b/src/hotspot/share/memory/universe.hpp @@ -232,7 +232,6 @@ class Universe: AllStatic { static oop java_mirror(BasicType t); static void replace_mirror(BasicType t, oop obj); - static void clear_basic_type_mirrors(); static oop main_thread_group(); static void set_main_thread_group(oop group); diff --git a/src/hotspot/share/oops/constantPool.cpp b/src/hotspot/share/oops/constantPool.cpp index f76a75fba4eed..922584e6c2d05 100644 --- a/src/hotspot/share/oops/constantPool.cpp +++ b/src/hotspot/share/oops/constantPool.cpp @@ -283,7 +283,6 @@ void ConstantPool::archive_resolved_references(Thread* THREAD) { ik->is_shared_app_class())) { // Archiving resolved references for classes from non-builtin loaders // is not yet supported. - set_resolved_references(OopHandle()); return; } @@ -316,7 +315,6 @@ void ConstantPool::archive_resolved_references(Thread* THREAD) { // resolved references will be created using the normal process // when there is no archived value. _cache->set_archived_references(archived); - set_resolved_references(OopHandle()); } } @@ -396,15 +394,7 @@ void ConstantPool::remove_unshareable_info() { // at runtime. set_resolved_reference_length( resolved_references() != NULL ? resolved_references()->length() : 0); - - // If archiving heap objects is not allowed, clear the resolved references. - // Otherwise, it is cleared after the resolved references array is cached - // (see archive_resolved_references()). - // If DynamicDumpSharedSpaces is enabled, clear the resolved references also - // as java objects are not archived in the top layer. - if (!HeapShared::is_heap_object_archiving_allowed() || DynamicDumpSharedSpaces) { - set_resolved_references(OopHandle()); - } + set_resolved_references(OopHandle()); // Shared ConstantPools are in the RO region, so the _flags cannot be modified. // The _on_stack flag is used to prevent ConstantPools from deallocation during