--- a/src/hotspot/share/memory/heapShared.cpp Tue Oct 09 12:36:51 2018 -0700
+++ b/src/hotspot/share/memory/heapShared.cpp Tue Oct 09 15:58:07 2018 -0400
@@ -24,25 +24,200 @@
#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;
+
address HeapShared::_narrow_oop_base;
int HeapShared::_narrow_oop_shift;
+
+////////////////////////////////////////////////////////////////
+//
+// 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<Klass*>* 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<MemRegion> *closed,
+ GrowableArray<MemRegion> *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<MemRegion> * 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<MemRegion> * 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());
+}
+
+void HeapShared::init_narrow_oop_decoding(address base, int shift) {
+ _narrow_oop_base = base;
+ _narrow_oop_shift = shift;
+}
+
+//
+// Subgraph archiving support
+//
HeapShared::DumpTimeKlassSubGraphInfoTable* HeapShared::_dump_time_subgraph_info_table = NULL;
HeapShared::RunTimeKlassSubGraphInfoTable HeapShared::_run_time_subgraph_info_table;
@@ -214,7 +389,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
}
assert(!DumpSharedSpaces, "Should not be called with DumpSharedSpaces");
@@ -274,8 +449,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;
@@ -310,7 +484,7 @@
template <class T> 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));
@@ -329,7 +503,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.
@@ -347,7 +521,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.
@@ -356,7 +530,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.
@@ -373,7 +547,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;
@@ -447,7 +621,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;
}
@@ -508,7 +682,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;
}
@@ -519,7 +693,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().
@@ -546,11 +720,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);
@@ -670,7 +844,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
@@ -767,11 +941,6 @@
return oopmap;
}
-void HeapShared::init_narrow_oop_decoding(address base, int shift) {
- _narrow_oop_base = base;
- _narrow_oop_shift = shift;
-}
-
// Patch all the embedded oop pointers inside an archived heap region,
// to be consistent with the runtime oop encoding.
class PatchEmbeddedPointers: public BitMapClosure {