src/hotspot/share/memory/heapShared.cpp
changeset 52062 8dbf1a13af49
parent 52047 7bc8b456e5ac
child 52319 625f6c742392
--- 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 {