--- old/src/hotspot/share/memory/heapShared.cpp 2018-10-03 15:10:31.191997707 -0400 +++ new/src/hotspot/share/memory/heapShared.cpp 2018-10-03 15:10:29.795916690 -0400 @@ -24,23 +24,192 @@ #include "precompiled.hpp" #include "classfile/javaClasses.inline.hpp" +#include "classfile/stringTable.hpp" #include "classfile/symbolTable.hpp" #include "classfile/vmSymbols.hpp" #include "logging/log.hpp" #include "logging/logMessage.hpp" #include "logging/logStream.hpp" +#include "memory/filemap.hpp" #include "memory/heapShared.inline.hpp" #include "memory/iterator.inline.hpp" #include "memory/metadataFactory.hpp" #include "memory/metaspaceClosure.hpp" -#include "memory/metaspaceShared.inline.hpp" #include "memory/resourceArea.hpp" #include "oops/compressedOops.inline.hpp" #include "oops/oop.inline.hpp" #include "runtime/fieldDescriptor.inline.hpp" +#include "runtime/safepointVerifiers.hpp" #include "utilities/bitMap.inline.hpp" +#if INCLUDE_G1GC +#include "gc/g1/g1CollectedHeap.hpp" +#endif #if INCLUDE_CDS_JAVA_HEAP + +bool HeapShared::_open_archive_heap_region_mapped = false; +bool HeapShared::_archive_heap_region_fixed = false; + +//////////////////////////////////////////////////////////////// +// +// Java heap object archiving support +// +//////////////////////////////////////////////////////////////// +void HeapShared::fixup_mapped_heap_regions() { + FileMapInfo *mapinfo = FileMapInfo::current_info(); + mapinfo->fixup_mapped_heap_regions(); + set_archive_heap_region_fixed(); +} + +unsigned HeapShared::oop_hash(oop const& p) { + assert(!p->mark()->has_bias_pattern(), + "this object should never have been locked"); // so identity_hash won't safepoin + unsigned hash = (unsigned)p->identity_hash(); + return hash; +} + +HeapShared::ArchivedObjectCache* HeapShared::_archived_object_cache = NULL; +oop HeapShared::find_archived_heap_object(oop obj) { + assert(DumpSharedSpaces, "dump-time only"); + ArchivedObjectCache* cache = archived_object_cache(); + oop* p = cache->get(obj); + if (p != NULL) { + return *p; + } else { + return NULL; + } +} + +oop HeapShared::archive_heap_object(oop obj, Thread* THREAD) { + assert(DumpSharedSpaces, "dump-time only"); + + oop ao = find_archived_heap_object(obj); + if (ao != NULL) { + // already archived + return ao; + } + + int len = obj->size(); + if (G1CollectedHeap::heap()->is_archive_alloc_too_large(len)) { + log_debug(cds, heap)("Cannot archive, object (" PTR_FORMAT ") is too large: " SIZE_FORMAT, + p2i(obj), (size_t)obj->size()); + return NULL; + } + + // Pre-compute object identity hash at CDS dump time. + obj->identity_hash(); + + oop archived_oop = (oop)G1CollectedHeap::heap()->archive_mem_allocate(len); + if (archived_oop != NULL) { + Copy::aligned_disjoint_words((HeapWord*)obj, (HeapWord*)archived_oop, len); + MetaspaceShared::relocate_klass_ptr(archived_oop); + ArchivedObjectCache* cache = archived_object_cache(); + cache->put(obj, archived_oop); + log_debug(cds, heap)("Archived heap object " PTR_FORMAT " ==> " PTR_FORMAT, + p2i(obj), p2i(archived_oop)); + } else { + log_error(cds, heap)( + "Cannot allocate space for object " PTR_FORMAT " in archived heap region", + p2i(obj)); + vm_exit(1); + } + return archived_oop; +} + +oop HeapShared::materialize_archived_object(narrowOop v) { + assert(archive_heap_region_fixed(), + "must be called after archive heap regions are fixed"); + if (!CompressedOops::is_null(v)) { + oop obj = HeapShared::decode_from_archive(v); + return G1CollectedHeap::heap()->materialize_archived_object(obj); + } + return NULL; +} + +void HeapShared::archive_klass_objects(Thread* THREAD) { + GrowableArray* klasses = MetaspaceShared::collected_klasses(); + assert(klasses != NULL, "sanity"); + for (int i = 0; i < klasses->length(); i++) { + Klass* k = klasses->at(i); + + // archive mirror object + java_lang_Class::archive_mirror(k, CHECK); + + // archive the resolved_referenes array + if (k->is_instance_klass()) { + InstanceKlass* ik = InstanceKlass::cast(k); + ik->constants()->archive_resolved_references(THREAD); + } + } +} + +void HeapShared::archive_java_heap_objects(GrowableArray *closed, + GrowableArray *open) { + if (!is_heap_object_archiving_allowed()) { + if (log_is_enabled(Info, cds)) { + log_info(cds)( + "Archived java heap is not supported as UseG1GC, " + "UseCompressedOops and UseCompressedClassPointers are required." + "Current settings: UseG1GC=%s, UseCompressedOops=%s, UseCompressedClassPointers=%s.", + BOOL_TO_STR(UseG1GC), BOOL_TO_STR(UseCompressedOops), + BOOL_TO_STR(UseCompressedClassPointers)); + } + return; + } + + { + NoSafepointVerifier nsv; + + // Cache for recording where the archived objects are copied to + create_archived_object_cache(); + + tty->print_cr("Dumping objects to closed archive heap region ..."); + NOT_PRODUCT(StringTable::verify()); + copy_closed_archive_heap_objects(closed); + + tty->print_cr("Dumping objects to open archive heap region ..."); + copy_open_archive_heap_objects(open); + + destroy_archived_object_cache(); + } + + G1HeapVerifier::verify_archive_regions(); +} + +void HeapShared::copy_closed_archive_heap_objects( + GrowableArray * closed_archive) { + assert(is_heap_object_archiving_allowed(), "Cannot archive java heap objects"); + + Thread* THREAD = Thread::current(); + G1CollectedHeap::heap()->begin_archive_alloc_range(); + + // Archive interned string objects + StringTable::write_to_archive(); + + G1CollectedHeap::heap()->end_archive_alloc_range(closed_archive, + os::vm_allocation_granularity()); +} + +void HeapShared::copy_open_archive_heap_objects( + GrowableArray * open_archive) { + assert(is_heap_object_archiving_allowed(), "Cannot archive java heap objects"); + + Thread* THREAD = Thread::current(); + G1CollectedHeap::heap()->begin_archive_alloc_range(true /* open */); + + java_lang_Class::archive_basic_type_mirrors(THREAD); + + archive_klass_objects(THREAD); + + archive_object_subgraphs(THREAD); + + G1CollectedHeap::heap()->end_archive_alloc_range(open_archive, + os::vm_allocation_granularity()); +} + +// +// Subgraph archiving support +// KlassSubGraphInfo* HeapShared::_subgraph_info_list = NULL; int HeapShared::_num_archived_subgraph_info_records = 0; Array* HeapShared::_archived_subgraph_info_records = NULL; @@ -269,7 +438,7 @@ } void HeapShared::initialize_from_archived_subgraph(Klass* k) { - if (!MetaspaceShared::open_archive_heap_region_mapped()) { + if (!open_archive_heap_region_mapped()) { return; // nothing to do } @@ -326,8 +495,7 @@ // The object refereced by the field becomes 'known' by GC from this // point. All objects in the subgraph reachable from the object are // also 'known' by GC. - oop v = MetaspaceShared::materialize_archived_object( - entry_field_records->at(i+1)); + oop v = materialize_archived_object(entry_field_records->at(i+1)); m->obj_field_put(field_offset, v); i += 2; } @@ -362,7 +530,7 @@ template void do_oop_work(T *p) { oop obj = RawAccess<>::oop_load(p); if (!CompressedOops::is_null(obj)) { - assert(!MetaspaceShared::is_archive_object(obj), + assert(!HeapShared::is_archived_object(obj), "original objects must not point to archived objects"); size_t field_delta = pointer_delta(p, _orig_referencing_obj, sizeof(char)); @@ -381,7 +549,7 @@ oop archived = HeapShared::archive_reachable_objects_from(_level + 1, _subgraph_info, obj, THREAD); assert(archived != NULL, "VM should have exited with unarchivable objects for _level > 1"); - assert(MetaspaceShared::is_archive_object(archived), "must be"); + assert(HeapShared::is_archived_object(archived), "must be"); if (!_record_klasses_only) { // Update the reference in the archived copy of the referencing object. @@ -399,7 +567,7 @@ // (3) Record the klasses of all orig_obj and all reachable objects. oop HeapShared::archive_reachable_objects_from(int level, KlassSubGraphInfo* subgraph_info, oop orig_obj, TRAPS) { assert(orig_obj != NULL, "must be"); - assert(!MetaspaceShared::is_archive_object(orig_obj), "sanity"); + assert(!is_archived_object(orig_obj), "sanity"); // java.lang.Class instances cannot be included in an archived // object sub-graph. @@ -408,7 +576,7 @@ vm_exit(1); } - oop archived_obj = MetaspaceShared::find_archived_heap_object(orig_obj); + oop archived_obj = find_archived_heap_object(orig_obj); if (java_lang_String::is_instance(orig_obj) && archived_obj != NULL) { // To save time, don't walk strings that are already archived. They just contain // pointers to a type array, whose klass doesn't need to be recorded. @@ -425,7 +593,7 @@ bool record_klasses_only = (archived_obj != NULL); if (archived_obj == NULL) { ++_num_new_archived_objs; - archived_obj = MetaspaceShared::archive_heap_object(orig_obj, THREAD); + archived_obj = archive_heap_object(orig_obj, THREAD); if (archived_obj == NULL) { // Skip archiving the sub-graph referenced from the current entry field. ResourceMark rm; @@ -499,7 +667,7 @@ assert(k->is_shared_boot_class(), "must be boot class"); oop m = k->java_mirror(); - oop archived_m = MetaspaceShared::find_archived_heap_object(m); + oop archived_m = find_archived_heap_object(m); if (CompressedOops::is_null(archived_m)) { return; } @@ -560,7 +728,7 @@ assert(k->is_shared_boot_class(), "must be boot class"); oop m = k->java_mirror(); - oop archived_m = MetaspaceShared::find_archived_heap_object(m); + oop archived_m = find_archived_heap_object(m); if (CompressedOops::is_null(archived_m)) { return; } @@ -571,7 +739,7 @@ } void HeapShared::verify_subgraph_from(oop orig_obj) { - oop archived_obj = MetaspaceShared::find_archived_heap_object(orig_obj); + oop archived_obj = find_archived_heap_object(orig_obj); if (archived_obj == NULL) { // It's OK for the root of a subgraph to be not archived. See comments in // archive_reachable_objects_from(). @@ -598,11 +766,11 @@ set_has_been_seen_during_subgraph_recording(obj); if (is_archived) { - assert(MetaspaceShared::is_archive_object(obj), "must be"); - assert(MetaspaceShared::find_archived_heap_object(obj) == NULL, "must be"); + assert(is_archived_object(obj), "must be"); + assert(find_archived_heap_object(obj) == NULL, "must be"); } else { - assert(!MetaspaceShared::is_archive_object(obj), "must be"); - assert(MetaspaceShared::find_archived_heap_object(obj) != NULL, "must be"); + assert(!is_archived_object(obj), "must be"); + assert(find_archived_heap_object(obj) != NULL, "must be"); } VerifySharedOopClosure walker(is_archived); @@ -720,7 +888,7 @@ } } -void HeapShared::archive_static_fields(Thread* THREAD) { +void HeapShared::archive_object_subgraphs(Thread* THREAD) { // For each class X that has one or more archived fields: // [1] Dump the subgraph of each archived field // [2] Create a list of all the class of the objects that can be reached