8194759: Support caching class mirror objects.
authorjiangli
Fri, 02 Mar 2018 17:25:55 -0500
changeset 49329 04ed29f9ef33
parent 49328 6a86f0deb479
child 49330 e5ba028ee3f1
8194759: Support caching class mirror objects. Summary: Support archiving mirror objects for shared classes in 'open' archive java heap region. Reviewed-by: coleenp, iklam, mseledtsov, tschatzl
src/hotspot/share/classfile/dictionary.cpp
src/hotspot/share/classfile/javaClasses.cpp
src/hotspot/share/classfile/javaClasses.hpp
src/hotspot/share/classfile/stringTable.cpp
src/hotspot/share/logging/logTag.hpp
src/hotspot/share/memory/filemap.hpp
src/hotspot/share/memory/iterator.hpp
src/hotspot/share/memory/metaspaceShared.cpp
src/hotspot/share/memory/metaspaceShared.hpp
src/hotspot/share/memory/universe.cpp
src/hotspot/share/memory/universe.hpp
src/hotspot/share/oops/klass.cpp
src/hotspot/share/oops/klass.hpp
test/hotspot/jtreg/runtime/appcds/cacheObject/CheckCachedMirrorApp.java
test/hotspot/jtreg/runtime/appcds/cacheObject/CheckCachedMirrorTest.java
test/hotspot/jtreg/runtime/appcds/cacheObject/MirrorWithReferenceFieldsApp.java
test/hotspot/jtreg/runtime/appcds/cacheObject/MirrorWithReferenceFieldsTest.java
test/hotspot/jtreg/runtime/appcds/cacheObject/PrimitiveTypesApp.java
test/hotspot/jtreg/runtime/appcds/cacheObject/PrimitiveTypesTest.java
test/hotspot/jtreg/runtime/appcds/cacheObject/RedefineClassApp.java
--- a/src/hotspot/share/classfile/dictionary.cpp	Fri Mar 02 10:42:32 2018 -0800
+++ b/src/hotspot/share/classfile/dictionary.cpp	Fri Mar 02 17:25:55 2018 -0500
@@ -481,6 +481,7 @@
 void Dictionary::reorder_dictionary_for_sharing() {
 
   // Copy all the dictionary entries into a single master list.
+  assert(DumpSharedSpaces, "Should only be used at dump time");
 
   DictionaryEntry* master_list = NULL;
   for (int i = 0; i < table_size(); ++i) {
@@ -488,7 +489,7 @@
     while (p != NULL) {
       DictionaryEntry* next = p->next();
       InstanceKlass*ik = p->instance_klass();
-      if (ik->signers() != NULL) {
+      if (ik->has_signer_and_not_archived()) {
         // We cannot include signed classes in the archive because the certificates
         // used during dump time may be different than those used during
         // runtime (due to expiration, etc).
--- a/src/hotspot/share/classfile/javaClasses.cpp	Fri Mar 02 10:42:32 2018 -0800
+++ b/src/hotspot/share/classfile/javaClasses.cpp	Fri Mar 02 17:25:55 2018 -0500
@@ -36,6 +36,7 @@
 #include "logging/log.hpp"
 #include "logging/logStream.hpp"
 #include "memory/oopFactory.hpp"
+#include "memory/metaspaceShared.hpp"
 #include "memory/resourceArea.hpp"
 #include "memory/universe.inline.hpp"
 #include "oops/fieldStreams.hpp"
@@ -67,6 +68,11 @@
 #define INJECTED_FIELD_COMPUTE_OFFSET(klass, name, signature, may_be_java)    \
   klass::_##name##_offset = JavaClasses::compute_injected_offset(JavaClasses::klass##_##name##_enum);
 
+#if INCLUDE_CDS
+#define INJECTED_FIELD_SERIALIZE_OFFSET(klass, name, signature, may_be_java) \
+  f->do_u4((u4*)&_##name##_offset);
+#endif
+
 #define DECLARE_INJECTED_FIELD(klass, name, signature, may_be_java)           \
   { SystemDictionary::WK_KLASS_ENUM_NAME(klass), vmSymbols::VM_SYMBOL_ENUM_NAME(name##_name), vmSymbols::VM_SYMBOL_ENUM_NAME(signature), may_be_java },
 
@@ -170,17 +176,43 @@
   return is_instance_inlined(obj);
 }
 
+#if INCLUDE_CDS
+#define FIELD_SERIALIZE_OFFSET(offset, klass, name, signature, is_static) \
+  f->do_u4((u4*)&offset)
+
+#define FIELD_SERIALIZE_OFFSET_OPTIONAL(offset, klass, name, signature) \
+  f->do_u4((u4*)&offset)
+#endif
+
+#define FIELD_COMPUTE_OFFSET(offset, klass, name, signature, is_static) \
+  compute_offset(offset, klass, name, vmSymbols::signature(), is_static)
+
+#define FIELD_COMPUTE_OFFSET_OPTIONAL(offset, klass, name, signature) \
+  compute_optional_offset(offset, klass, name, vmSymbols::signature())
+
+#define STRING_FIELDS_DO(macro) \
+  macro(value_offset, k, vmSymbols::value_name(), byte_array_signature, false); \
+  macro(hash_offset,  k, "hash",                  int_signature,        false); \
+  macro(coder_offset, k, "coder",                 byte_signature,       false)
+
 void java_lang_String::compute_offsets() {
-  assert(!initialized, "offsets should be initialized only once");
+  if (initialized) {
+    return;
+  }
 
   InstanceKlass* k = SystemDictionary::String_klass();
-  compute_offset(value_offset,           k, vmSymbols::value_name(),  vmSymbols::byte_array_signature());
-  compute_offset(hash_offset,            k, "hash",   vmSymbols::int_signature());
-  compute_offset(coder_offset,           k, "coder",  vmSymbols::byte_signature());
+  STRING_FIELDS_DO(FIELD_COMPUTE_OFFSET);
 
   initialized = true;
 }
 
+#if INCLUDE_CDS
+void java_lang_String::serialize(SerializeClosure* f) {
+  STRING_FIELDS_DO(FIELD_SERIALIZE_OFFSET);
+  f->do_u4((u4*)&initialized);
+}
+#endif
+
 class CompactStringsFixup : public FieldClosure {
 private:
   bool _value;
@@ -731,12 +763,17 @@
         break;
       case T_OBJECT:
         {
-          #ifdef ASSERT
-          TempNewSymbol sym = SymbolTable::new_symbol("Ljava/lang/String;", CHECK);
-          assert(fd->signature() == sym, "just checking");
-          #endif
-          oop string = fd->string_initial_value(CHECK);
-          mirror()->obj_field_put(fd->offset(), string);
+          assert(fd->signature() == vmSymbols::string_signature(),
+                 "just checking");
+          if (DumpSharedSpaces && oopDesc::is_archive_object(mirror())) {
+            // Archive the String field and update the pointer.
+            oop s = mirror()->obj_field(fd->offset());
+            oop archived_s = StringTable::create_archived_string(s, CHECK);
+            mirror()->obj_field_put(fd->offset(), archived_s);
+          } else {
+            oop string = fd->string_initial_value(CHECK);
+            mirror()->obj_field_put(fd->offset(), string);
+          }
         }
         break;
       default:
@@ -764,6 +801,21 @@
       }
     }
   }
+
+  if (k->is_shared() && k->has_raw_archived_mirror()) {
+    if (MetaspaceShared::open_archive_heap_region_mapped()) {
+      oop m = k->archived_java_mirror();
+      assert(m != NULL, "archived mirror is NULL");
+      assert(oopDesc::is_archive_object(m), "must be archived mirror object");
+      Handle m_h(THREAD, m);
+      // restore_archived_mirror() clears the klass' _has_raw_archived_mirror flag
+      restore_archived_mirror(k, m_h, Handle(), Handle(), Handle(), CHECK);
+      return;
+    } else {
+      k->set_java_mirror_handle(NULL);
+      k->clear_has_raw_archived_mirror();
+    }
+  }
   create_mirror(k, Handle(), Handle(), Handle(), CHECK);
 }
 
@@ -916,6 +968,277 @@
   }
 }
 
+#if INCLUDE_CDS_JAVA_HEAP
+// Clears mirror fields. Static final fields with initial values are reloaded
+// from constant pool. The object identity hash is in the object header and is
+// not affected.
+class ResetMirrorField: public FieldClosure {
+ private:
+  Handle _m;
+
+ public:
+  ResetMirrorField(Handle mirror) : _m(mirror) {}
+
+  void do_field(fieldDescriptor* fd) {
+    assert(DumpSharedSpaces, "dump time only");
+    assert(_m.not_null(), "Mirror cannot be NULL");
+
+    if (fd->is_static() && fd->has_initial_value()) {
+      initialize_static_field(fd, _m, Thread::current());
+      return;
+    }
+
+    BasicType ft = fd->field_type();
+    switch (ft) {
+      case T_BYTE:
+        _m()->byte_field_put(fd->offset(), 0);
+        break;
+      case T_CHAR:
+        _m()->char_field_put(fd->offset(), 0);
+        break;
+      case T_DOUBLE:
+        _m()->double_field_put(fd->offset(), 0);
+        break;
+      case T_FLOAT:
+        _m()->float_field_put(fd->offset(), 0);
+        break;
+      case T_INT:
+        _m()->int_field_put(fd->offset(), 0);
+        break;
+      case T_LONG:
+        _m()->long_field_put(fd->offset(), 0);
+        break;
+      case T_SHORT:
+        _m()->short_field_put(fd->offset(), 0);
+        break;
+      case T_BOOLEAN:
+        _m()->bool_field_put(fd->offset(), false);
+        break;
+      case T_ARRAY:
+      case T_OBJECT: {
+        // It might be useful to cache the String field, but
+        // for now just clear out any reference field
+        oop o = _m()->obj_field(fd->offset());
+        _m()->obj_field_put(fd->offset(), NULL);
+        break;
+      }
+      default:
+        ShouldNotReachHere();
+        break;
+     }
+  }
+};
+
+void java_lang_Class::archive_basic_type_mirrors(TRAPS) {
+  assert(MetaspaceShared::is_heap_object_archiving_allowed(),
+         "MetaspaceShared::is_heap_object_archiving_allowed() must be true");
+
+  for (int t = 0; t <= T_VOID; t++) {
+    oop m = Universe::_mirrors[t];
+    if (m != NULL) {
+      // Update the field at _array_klass_offset to point to the relocated array klass.
+      oop archived_m = MetaspaceShared::archive_heap_object(m, THREAD);
+      Klass *ak = (Klass*)(archived_m->metadata_field(_array_klass_offset));
+      assert(ak != NULL || t == T_VOID, "should not be NULL");
+      if (ak != NULL) {
+        Klass *reloc_ak = MetaspaceShared::get_relocated_klass(ak);
+        archived_m->metadata_field_put(_array_klass_offset, reloc_ak);
+      }
+
+      // Clear the fields. Just to be safe
+      Klass *k = m->klass();
+      Handle archived_mirror_h(THREAD, archived_m);
+      ResetMirrorField reset(archived_mirror_h);
+      InstanceKlass::cast(k)->do_nonstatic_fields(&reset);
+
+      log_trace(cds, mirror)("Archived %s mirror object from " PTR_FORMAT " ==> " PTR_FORMAT,
+                             type2name((BasicType)t), p2i(Universe::_mirrors[t]), p2i(archived_m));
+
+      Universe::_mirrors[t] = archived_m;
+    }
+  }
+
+  assert(Universe::_mirrors[T_INT] != NULL &&
+         Universe::_mirrors[T_FLOAT] != NULL &&
+         Universe::_mirrors[T_DOUBLE] != NULL &&
+         Universe::_mirrors[T_BYTE] != NULL &&
+         Universe::_mirrors[T_BOOLEAN] != NULL &&
+         Universe::_mirrors[T_CHAR] != NULL &&
+         Universe::_mirrors[T_LONG] != NULL &&
+         Universe::_mirrors[T_SHORT] != NULL &&
+         Universe::_mirrors[T_VOID] != NULL, "sanity");
+
+  Universe::set_int_mirror(Universe::_mirrors[T_INT]);
+  Universe::set_float_mirror(Universe::_mirrors[T_FLOAT]);
+  Universe::set_double_mirror(Universe::_mirrors[T_DOUBLE]);
+  Universe::set_byte_mirror(Universe::_mirrors[T_BYTE]);
+  Universe::set_bool_mirror(Universe::_mirrors[T_BOOLEAN]);
+  Universe::set_char_mirror(Universe::_mirrors[T_CHAR]);
+  Universe::set_long_mirror(Universe::_mirrors[T_LONG]);
+  Universe::set_short_mirror(Universe::_mirrors[T_SHORT]);
+  Universe::set_void_mirror(Universe::_mirrors[T_VOID]);
+}
+
+//
+// After the mirror object is successfully archived, the archived
+// klass is set with _has_archived_raw_mirror flag.
+//
+// The _has_archived_raw_mirror flag is cleared at runtime when the
+// archived mirror is restored. If archived java heap data cannot
+// be used at runtime, new mirror object is created for the shared
+// class. The _has_archived_raw_mirror is cleared also during the process.
+oop java_lang_Class::archive_mirror(Klass* k, TRAPS) {
+  assert(MetaspaceShared::is_heap_object_archiving_allowed(),
+         "MetaspaceShared::is_heap_object_archiving_allowed() must be true");
+
+  // Mirror is already archived
+  if (k->has_raw_archived_mirror()) {
+    assert(k->archived_java_mirror_raw() != NULL, "no archived mirror");
+    return k->archived_java_mirror_raw();
+  }
+
+  // No mirror
+  oop mirror = k->java_mirror();
+  if (mirror == NULL) {
+    return NULL;
+  }
+
+  if (k->is_instance_klass()) {
+    InstanceKlass *ik = InstanceKlass::cast(k);
+    assert(ik->signers() == NULL && !k->has_signer_and_not_archived(),
+           "class with signer cannot be supported");
+
+    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->set_java_mirror_handle(NULL);
+      return NULL;
+    }
+  }
+
+  // Now start archiving the mirror object
+  oop archived_mirror = MetaspaceShared::archive_heap_object(mirror, THREAD);
+  if (archived_mirror == NULL) {
+    return NULL;
+  }
+
+  archived_mirror = process_archived_mirror(k, mirror, archived_mirror, THREAD);
+  if (archived_mirror == NULL) {
+    return NULL;
+  }
+
+  k->set_archived_java_mirror_raw(archived_mirror);
+
+  k->set_has_raw_archived_mirror();
+
+  ResourceMark rm;
+  log_trace(cds, mirror)("Archived %s mirror object from " PTR_FORMAT " ==> " PTR_FORMAT,
+                         k->external_name(), p2i(mirror), p2i(archived_mirror));
+
+  return archived_mirror;
+}
+
+// The process is based on create_mirror().
+oop java_lang_Class::process_archived_mirror(Klass* k, oop mirror,
+                                             oop archived_mirror,
+                                             Thread *THREAD) {
+  // Clear nonstatic fields in archived mirror. Some of the fields will be set
+  // to archived metadata and objects below.
+  Klass *c = archived_mirror->klass();
+  Handle archived_mirror_h(THREAD, archived_mirror);
+  ResetMirrorField reset(archived_mirror_h);
+  InstanceKlass::cast(c)->do_nonstatic_fields(&reset);
+
+  if (k->is_array_klass()) {
+    oop archived_comp_mirror;
+    if (k->is_typeArray_klass()) {
+      // The primitive type mirrors are already archived. Get the archived mirror.
+      oop comp_mirror = java_lang_Class::component_mirror(mirror);
+      archived_comp_mirror = MetaspaceShared::find_archived_heap_object(comp_mirror);
+      assert(archived_comp_mirror != NULL, "Must be");
+    } else {
+      assert(k->is_objArray_klass(), "Must be");
+      Klass* element_klass = ObjArrayKlass::cast(k)->element_klass();
+      assert(element_klass != NULL, "Must have an element klass");
+      archived_comp_mirror = archive_mirror(element_klass, THREAD);
+      if (archived_comp_mirror == NULL) {
+        return NULL;
+      }
+    }
+    java_lang_Class::set_component_mirror(archived_mirror, archived_comp_mirror);
+  } else {
+    assert(k->is_instance_klass(), "Must be");
+
+    // Reset local static fields in the mirror
+    InstanceKlass::cast(k)->do_local_static_fields(&reset);
+
+    java_lang_Class:set_init_lock(archived_mirror, NULL);
+
+    set_protection_domain(archived_mirror, NULL);
+  }
+
+  // clear class loader and mirror_module_field
+  set_class_loader(archived_mirror, NULL);
+  set_module(archived_mirror, NULL);
+
+  // The archived mirror's field at _klass_offset is still pointing to the original
+  // klass. Updated the field in the archived mirror to point to the relocated
+  // klass in the archive.
+  Klass *reloc_k = MetaspaceShared::get_relocated_klass(as_Klass(mirror));
+  log_debug(cds, mirror)("Relocate mirror metadata field at _klass_offset from " PTR_FORMAT " ==> " PTR_FORMAT,
+                         p2i(as_Klass(mirror)), p2i(reloc_k));
+  archived_mirror->metadata_field_put(_klass_offset, reloc_k);
+
+  // The field at _array_klass_offset is pointing to the original one dimension
+  // higher array klass if exists. Relocate the pointer.
+  Klass *arr = array_klass_acquire(mirror);
+  if (arr != NULL) {
+    Klass *reloc_arr = MetaspaceShared::get_relocated_klass(arr);
+    log_debug(cds, mirror)("Relocate mirror metadata field at _array_klass_offset from " PTR_FORMAT " ==> " PTR_FORMAT,
+                           p2i(arr), p2i(reloc_arr));
+    archived_mirror->metadata_field_put(_array_klass_offset, reloc_arr);
+  }
+  return archived_mirror;
+}
+
+// After the archived mirror object is restored, the shared klass'
+// _has_raw_archived_mirror flag is cleared
+void java_lang_Class::restore_archived_mirror(Klass *k, Handle mirror,
+                                              Handle class_loader, Handle module,
+                                              Handle protection_domain, TRAPS) {
+
+  // The java.lang.Class field offsets were archived and reloaded from archive.
+  // No need to put classes on the fixup_mirror_list before java.lang.Class
+  // is loaded.
+
+  if (!k->is_array_klass()) {
+    // - local static final fields with initial values were initialized at dump time
+
+    // create the init_lock
+    typeArrayOop r = oopFactory::new_typeArray(T_INT, 0, CHECK);
+    set_init_lock(mirror(), r);
+
+    if (protection_domain.not_null()) {
+      set_protection_domain(mirror(), protection_domain());
+    }
+  }
+
+  assert(class_loader() == k->class_loader(), "should be same");
+  if (class_loader.not_null()) {
+    set_class_loader(mirror(), class_loader());
+  }
+
+  k->set_java_mirror(mirror);
+  k->clear_has_raw_archived_mirror();
+
+  set_mirror_module_field(k, mirror, module, THREAD);
+
+  ResourceMark rm;
+  log_trace(cds, mirror)("Restored %s archived mirror " PTR_FORMAT, k->external_name(), p2i(mirror()));
+}
+#endif // INCLUDE_CDS_JAVA_HEAP
+
 void java_lang_Class::fixup_module_field(Klass* k, Handle module) {
   assert(_module_offset != 0, "must have been computed already");
   java_lang_Class::set_module(k->java_mirror(), module());
@@ -1167,15 +1490,21 @@
 bool java_lang_Class::offsets_computed = false;
 int  java_lang_Class::classRedefinedCount_offset = -1;
 
+#define CLASS_FIELDS_DO(macro) \
+  macro(classRedefinedCount_offset, k, "classRedefinedCount", int_signature,         false) ; \
+  macro(_class_loader_offset,       k, "classLoader",         classloader_signature, false); \
+  macro(_component_mirror_offset,   k, "componentType",       class_signature,       false); \
+  macro(_module_offset,             k, "module",              module_signature,      false)
+
 void java_lang_Class::compute_offsets() {
-  assert(!offsets_computed, "offsets should be initialized only once");
+  if (offsets_computed) {
+    return;
+  }
+
   offsets_computed = true;
 
   InstanceKlass* k = SystemDictionary::Class_klass();
-  compute_offset(classRedefinedCount_offset, k, "classRedefinedCount", vmSymbols::int_signature());
-  compute_offset(_class_loader_offset,       k, "classLoader", vmSymbols::classloader_signature());
-  compute_offset(_component_mirror_offset,   k, "componentType", vmSymbols::class_signature());
-  compute_offset(_module_offset,             k, "module", vmSymbols::module_signature());
+  CLASS_FIELDS_DO(FIELD_COMPUTE_OFFSET);
 
   // Init lock is a C union with component_mirror.  Only instanceKlass mirrors have
   // init_lock and only ArrayKlass mirrors have component_mirror.  Since both are oops
@@ -1185,6 +1514,17 @@
   CLASS_INJECTED_FIELDS(INJECTED_FIELD_COMPUTE_OFFSET);
 }
 
+#if INCLUDE_CDS
+void java_lang_Class::serialize(SerializeClosure* f) {
+  f->do_u4((u4*)&offsets_computed);
+  f->do_u4((u4*)&_init_lock_offset);
+
+  CLASS_FIELDS_DO(FIELD_SERIALIZE_OFFSET);
+
+  CLASS_INJECTED_FIELDS(INJECTED_FIELD_SERIALIZE_OFFSET);
+}
+#endif
+
 int java_lang_Class::classRedefinedCount(oop the_class_mirror) {
   if (classRedefinedCount_offset == -1) {
     // If we don't have an offset for it then just return -1 as a marker.
@@ -1226,28 +1566,33 @@
 int java_lang_Thread::_park_blocker_offset = 0;
 int java_lang_Thread::_park_event_offset = 0 ;
 
+#define THREAD_FIELDS_DO(macro) \
+  macro(_name_offset,          k, vmSymbols::name_name(), string_signature, false); \
+  macro(_group_offset,         k, vmSymbols::group_name(), threadgroup_signature, false); \
+  macro(_contextClassLoader_offset, k, vmSymbols::contextClassLoader_name(), classloader_signature, false); \
+  macro(_inheritedAccessControlContext_offset, k, vmSymbols::inheritedAccessControlContext_name(), accesscontrolcontext_signature, false); \
+  macro(_priority_offset,      k, vmSymbols::priority_name(), int_signature, false); \
+  macro(_daemon_offset,        k, vmSymbols::daemon_name(), bool_signature, false); \
+  macro(_eetop_offset,         k, "eetop", long_signature, false); \
+  macro(_stillborn_offset,     k, "stillborn", bool_signature, false); \
+  macro(_stackSize_offset,     k, "stackSize", long_signature, false); \
+  macro(_tid_offset,           k, "tid", long_signature, false); \
+  macro(_thread_status_offset, k, "threadStatus", int_signature, false); \
+  macro(_park_blocker_offset,  k, "parkBlocker", object_signature, false); \
+  macro(_park_event_offset,    k, "nativeParkEventPointer", long_signature, false)
 
 void java_lang_Thread::compute_offsets() {
   assert(_group_offset == 0, "offsets should be initialized only once");
 
   InstanceKlass* k = SystemDictionary::Thread_klass();
-  compute_offset(_name_offset,      k, vmSymbols::name_name(),      vmSymbols::string_signature());
-  compute_offset(_group_offset,     k, vmSymbols::group_name(),     vmSymbols::threadgroup_signature());
-  compute_offset(_contextClassLoader_offset, k, vmSymbols::contextClassLoader_name(),
-                 vmSymbols::classloader_signature());
-  compute_offset(_inheritedAccessControlContext_offset, k, vmSymbols::inheritedAccessControlContext_name(),
-                 vmSymbols::accesscontrolcontext_signature());
-  compute_offset(_priority_offset,  k, vmSymbols::priority_name(),  vmSymbols::int_signature());
-  compute_offset(_daemon_offset,    k, vmSymbols::daemon_name(),    vmSymbols::bool_signature());
-  compute_offset(_eetop_offset,     k, "eetop", vmSymbols::long_signature());
-  compute_offset(_stillborn_offset, k, "stillborn", vmSymbols::bool_signature());
-  compute_offset(_stackSize_offset, k, "stackSize", vmSymbols::long_signature());
-  compute_offset(_tid_offset,       k, "tid", vmSymbols::long_signature());
-  compute_offset(_thread_status_offset, k, "threadStatus", vmSymbols::int_signature());
-  compute_offset(_park_blocker_offset,  k, "parkBlocker", vmSymbols::object_signature());
-  compute_offset(_park_event_offset,    k, "nativeParkEventPointer", vmSymbols::long_signature());
-}
-
+  THREAD_FIELDS_DO(FIELD_COMPUTE_OFFSET);
+}
+
+#if INCLUDE_CDS
+void java_lang_Thread::serialize(SerializeClosure* f) {
+  THREAD_FIELDS_DO(FIELD_SERIALIZE_OFFSET);
+}
+#endif
 
 JavaThread* java_lang_Thread::thread(oop java_thread) {
   return (JavaThread*)java_thread->address_field(_eetop_offset);
@@ -1477,32 +1822,47 @@
   return java_thread_group->bool_field(_daemon_offset) != 0;
 }
 
+#define THREADGROUP_FIELDS_DO(macro) \
+  macro(_parent_offset,      k, vmSymbols::parent_name(),      threadgroup_signature,       false); \
+  macro(_name_offset,        k, vmSymbols::name_name(),        string_signature,            false); \
+  macro(_threads_offset,     k, vmSymbols::threads_name(),     thread_array_signature,      false); \
+  macro(_groups_offset,      k, vmSymbols::groups_name(),      threadgroup_array_signature, false); \
+  macro(_maxPriority_offset, k, vmSymbols::maxPriority_name(), int_signature,               false); \
+  macro(_destroyed_offset,   k, vmSymbols::destroyed_name(),   bool_signature,              false); \
+  macro(_daemon_offset,      k, vmSymbols::daemon_name(),      bool_signature,              false); \
+  macro(_nthreads_offset,    k, vmSymbols::nthreads_name(),    int_signature,               false); \
+  macro(_ngroups_offset,     k, vmSymbols::ngroups_name(),     int_signature,               false)
+
 void java_lang_ThreadGroup::compute_offsets() {
   assert(_parent_offset == 0, "offsets should be initialized only once");
 
   InstanceKlass* k = SystemDictionary::ThreadGroup_klass();
-
-  compute_offset(_parent_offset,      k, vmSymbols::parent_name(),      vmSymbols::threadgroup_signature());
-  compute_offset(_name_offset,        k, vmSymbols::name_name(),        vmSymbols::string_signature());
-  compute_offset(_threads_offset,     k, vmSymbols::threads_name(),     vmSymbols::thread_array_signature());
-  compute_offset(_groups_offset,      k, vmSymbols::groups_name(),      vmSymbols::threadgroup_array_signature());
-  compute_offset(_maxPriority_offset, k, vmSymbols::maxPriority_name(), vmSymbols::int_signature());
-  compute_offset(_destroyed_offset,   k, vmSymbols::destroyed_name(),   vmSymbols::bool_signature());
-  compute_offset(_daemon_offset,      k, vmSymbols::daemon_name(),      vmSymbols::bool_signature());
-  compute_offset(_nthreads_offset,    k, vmSymbols::nthreads_name(),    vmSymbols::int_signature());
-  compute_offset(_ngroups_offset,     k, vmSymbols::ngroups_name(),     vmSymbols::int_signature());
-}
-
+  THREADGROUP_FIELDS_DO(FIELD_COMPUTE_OFFSET);
+}
+
+#if INCLUDE_CDS
+void java_lang_ThreadGroup::serialize(SerializeClosure* f) {
+  THREADGROUP_FIELDS_DO(FIELD_SERIALIZE_OFFSET);
+}
+#endif
+
+#define THROWABLE_FIELDS_DO(macro) \
+  macro(backtrace_offset,     k, "backtrace",     object_signature,                  false); \
+  macro(detailMessage_offset, k, "detailMessage", string_signature,                  false); \
+  macro(stackTrace_offset,    k, "stackTrace",    java_lang_StackTraceElement_array, false); \
+  macro(depth_offset,         k, "depth",         int_signature,                     false); \
+  macro(static_unassigned_stacktrace_offset, k, "UNASSIGNED_STACK", java_lang_StackTraceElement_array, true)
 
 void java_lang_Throwable::compute_offsets() {
   InstanceKlass* k = SystemDictionary::Throwable_klass();
-  compute_offset(backtrace_offset,     k, "backtrace", vmSymbols::object_signature());
-  compute_offset(detailMessage_offset, k, "detailMessage", vmSymbols::string_signature());
-  compute_offset(stackTrace_offset,    k, "stackTrace",    vmSymbols::java_lang_StackTraceElement_array());
-  compute_offset(depth_offset,         k, "depth", vmSymbols::int_signature());
-  compute_offset(static_unassigned_stacktrace_offset, k, "UNASSIGNED_STACK", vmSymbols::java_lang_StackTraceElement_array(),
-                 /*is_static*/true);
-}
+  THROWABLE_FIELDS_DO(FIELD_COMPUTE_OFFSET);
+}
+
+#if INCLUDE_CDS
+void java_lang_Throwable::serialize(SerializeClosure* f) {
+  THROWABLE_FIELDS_DO(FIELD_SERIALIZE_OFFSET);
+}
+#endif
 
 oop java_lang_Throwable::unassigned_stacktrace() {
   InstanceKlass* ik = SystemDictionary::Throwable_klass();
@@ -2268,25 +2628,53 @@
   java_lang_StackTraceElement::fill_in(stack_trace_element, holder, method, version, bci, name, CHECK);
 }
 
+#define STACKFRAMEINFO_FIELDS_DO(macro) \
+  macro(_memberName_offset,     k, "memberName",  object_signature, false); \
+  macro(_bci_offset,            k, "bci",         short_signature,  false)
+
 void java_lang_StackFrameInfo::compute_offsets() {
   InstanceKlass* k = SystemDictionary::StackFrameInfo_klass();
-  compute_offset(_memberName_offset,     k, "memberName",  vmSymbols::object_signature());
-  compute_offset(_bci_offset,            k, "bci",         vmSymbols::short_signature());
+  STACKFRAMEINFO_FIELDS_DO(FIELD_COMPUTE_OFFSET);
   STACKFRAMEINFO_INJECTED_FIELDS(INJECTED_FIELD_COMPUTE_OFFSET);
 }
 
+#if INCLUDE_CDS
+void java_lang_StackFrameInfo::serialize(SerializeClosure* f) {
+  STACKFRAMEINFO_FIELDS_DO(FIELD_SERIALIZE_OFFSET);
+  STACKFRAMEINFO_INJECTED_FIELDS(INJECTED_FIELD_SERIALIZE_OFFSET);
+}
+#endif
+
+#define LIVESTACKFRAMEINFO_FIELDS_DO(macro) \
+  macro(_monitors_offset,   k, "monitors",    object_array_signature, false); \
+  macro(_locals_offset,     k, "locals",      object_array_signature, false); \
+  macro(_operands_offset,   k, "operands",    object_array_signature, false); \
+  macro(_mode_offset,       k, "mode",        int_signature,          false)
+
 void java_lang_LiveStackFrameInfo::compute_offsets() {
   InstanceKlass* k = SystemDictionary::LiveStackFrameInfo_klass();
-  compute_offset(_monitors_offset,   k, "monitors",    vmSymbols::object_array_signature());
-  compute_offset(_locals_offset,     k, "locals",      vmSymbols::object_array_signature());
-  compute_offset(_operands_offset,   k, "operands",    vmSymbols::object_array_signature());
-  compute_offset(_mode_offset,       k, "mode",        vmSymbols::int_signature());
-}
+  LIVESTACKFRAMEINFO_FIELDS_DO(FIELD_COMPUTE_OFFSET);
+}
+
+#if INCLUDE_CDS
+void java_lang_LiveStackFrameInfo::serialize(SerializeClosure* f) {
+  LIVESTACKFRAMEINFO_FIELDS_DO(FIELD_SERIALIZE_OFFSET);
+}
+#endif
+
+#define ACCESSIBLEOBJECT_FIELDS_DO(macro) \
+  macro(override_offset, k, "override", bool_signature, false)
 
 void java_lang_reflect_AccessibleObject::compute_offsets() {
   InstanceKlass* k = SystemDictionary::reflect_AccessibleObject_klass();
-  compute_offset(override_offset, k, "override", vmSymbols::bool_signature());
-}
+  ACCESSIBLEOBJECT_FIELDS_DO(FIELD_COMPUTE_OFFSET);
+}
+
+#if INCLUDE_CDS
+void java_lang_reflect_AccessibleObject::serialize(SerializeClosure* f) {
+  ACCESSIBLEOBJECT_FIELDS_DO(FIELD_SERIALIZE_OFFSET);
+}
+#endif
 
 jboolean java_lang_reflect_AccessibleObject::override(oop reflect) {
   assert(Universe::is_fully_initialized(), "Need to find another solution to the reflection problem");
@@ -2298,27 +2686,36 @@
   reflect->bool_field_put(override_offset, (int) value);
 }
 
+#define METHOD_FIELDS_DO(macro) \
+  macro(clazz_offset,          k, vmSymbols::clazz_name(),          class_signature,       false); \
+  macro(name_offset,           k, vmSymbols::name_name(),           string_signature,      false); \
+  macro(returnType_offset,     k, vmSymbols::returnType_name(),     class_signature,       false); \
+  macro(parameterTypes_offset, k, vmSymbols::parameterTypes_name(), class_array_signature, false); \
+  macro(exceptionTypes_offset, k, vmSymbols::exceptionTypes_name(), class_array_signature, false); \
+  macro(slot_offset,           k, vmSymbols::slot_name(),           int_signature,         false); \
+  macro(modifiers_offset,      k, vmSymbols::modifiers_name(),      int_signature,         false); \
+  macro##_OPTIONAL(signature_offset,             k, vmSymbols::signature_name(),             string_signature); \
+  macro##_OPTIONAL(annotations_offset,           k, vmSymbols::annotations_name(),           byte_array_signature); \
+  macro##_OPTIONAL(parameter_annotations_offset, k, vmSymbols::parameter_annotations_name(), byte_array_signature); \
+  macro##_OPTIONAL(annotation_default_offset,    k, vmSymbols::annotation_default_name(),    byte_array_signature); \
+  macro##_OPTIONAL(type_annotations_offset,      k, vmSymbols::type_annotations_name(),      byte_array_signature)
+
 void java_lang_reflect_Method::compute_offsets() {
   InstanceKlass* k = SystemDictionary::reflect_Method_klass();
-  compute_offset(clazz_offset,          k, vmSymbols::clazz_name(),          vmSymbols::class_signature());
-  compute_offset(name_offset,           k, vmSymbols::name_name(),           vmSymbols::string_signature());
-  compute_offset(returnType_offset,     k, vmSymbols::returnType_name(),     vmSymbols::class_signature());
-  compute_offset(parameterTypes_offset, k, vmSymbols::parameterTypes_name(), vmSymbols::class_array_signature());
-  compute_offset(exceptionTypes_offset, k, vmSymbols::exceptionTypes_name(), vmSymbols::class_array_signature());
-  compute_offset(slot_offset,           k, vmSymbols::slot_name(),           vmSymbols::int_signature());
-  compute_offset(modifiers_offset,      k, vmSymbols::modifiers_name(),      vmSymbols::int_signature());
   // The generic signature and annotations fields are only present in 1.5
   signature_offset = -1;
   annotations_offset = -1;
   parameter_annotations_offset = -1;
   annotation_default_offset = -1;
   type_annotations_offset = -1;
-  compute_optional_offset(signature_offset,             k, vmSymbols::signature_name(),             vmSymbols::string_signature());
-  compute_optional_offset(annotations_offset,           k, vmSymbols::annotations_name(),           vmSymbols::byte_array_signature());
-  compute_optional_offset(parameter_annotations_offset, k, vmSymbols::parameter_annotations_name(), vmSymbols::byte_array_signature());
-  compute_optional_offset(annotation_default_offset,    k, vmSymbols::annotation_default_name(),    vmSymbols::byte_array_signature());
-  compute_optional_offset(type_annotations_offset,      k, vmSymbols::type_annotations_name(),      vmSymbols::byte_array_signature());
-}
+  METHOD_FIELDS_DO(FIELD_COMPUTE_OFFSET);
+}
+
+#if INCLUDE_CDS
+void java_lang_reflect_Method::serialize(SerializeClosure* f) {
+  METHOD_FIELDS_DO(FIELD_SERIALIZE_OFFSET);
+}
+#endif
 
 Handle java_lang_reflect_Method::create(TRAPS) {
   assert(Universe::is_fully_initialized(), "Need to find another solution to the reflection problem");
@@ -2479,23 +2876,33 @@
   method->obj_field_put(type_annotations_offset, value);
 }
 
+#define CONSTRUCTOR_FIELDS_DO(macro) \
+  macro(clazz_offset,          k, vmSymbols::clazz_name(),          class_signature,       false); \
+  macro(parameterTypes_offset, k, vmSymbols::parameterTypes_name(), class_array_signature, false); \
+  macro(exceptionTypes_offset, k, vmSymbols::exceptionTypes_name(), class_array_signature, false); \
+  macro(slot_offset,           k, vmSymbols::slot_name(),           int_signature,         false); \
+  macro(modifiers_offset,      k, vmSymbols::modifiers_name(),      int_signature,         false); \
+  macro##_OPTIONAL(signature_offset,             k, vmSymbols::signature_name(),             string_signature); \
+  macro##_OPTIONAL(annotations_offset,           k, vmSymbols::annotations_name(),           byte_array_signature); \
+  macro##_OPTIONAL(parameter_annotations_offset, k, vmSymbols::parameter_annotations_name(), byte_array_signature); \
+  macro##_OPTIONAL(type_annotations_offset,      k, vmSymbols::type_annotations_name(),      byte_array_signature)
+
+
 void java_lang_reflect_Constructor::compute_offsets() {
   InstanceKlass* k = SystemDictionary::reflect_Constructor_klass();
-  compute_offset(clazz_offset,          k, vmSymbols::clazz_name(),          vmSymbols::class_signature());
-  compute_offset(parameterTypes_offset, k, vmSymbols::parameterTypes_name(), vmSymbols::class_array_signature());
-  compute_offset(exceptionTypes_offset, k, vmSymbols::exceptionTypes_name(), vmSymbols::class_array_signature());
-  compute_offset(slot_offset,           k, vmSymbols::slot_name(),           vmSymbols::int_signature());
-  compute_offset(modifiers_offset,      k, vmSymbols::modifiers_name(),      vmSymbols::int_signature());
   // The generic signature and annotations fields are only present in 1.5
   signature_offset = -1;
   annotations_offset = -1;
   parameter_annotations_offset = -1;
   type_annotations_offset = -1;
-  compute_optional_offset(signature_offset,             k, vmSymbols::signature_name(),             vmSymbols::string_signature());
-  compute_optional_offset(annotations_offset,           k, vmSymbols::annotations_name(),           vmSymbols::byte_array_signature());
-  compute_optional_offset(parameter_annotations_offset, k, vmSymbols::parameter_annotations_name(), vmSymbols::byte_array_signature());
-  compute_optional_offset(type_annotations_offset,      k, vmSymbols::type_annotations_name(),      vmSymbols::byte_array_signature());
-}
+  CONSTRUCTOR_FIELDS_DO(FIELD_COMPUTE_OFFSET);
+}
+
+#if INCLUDE_CDS
+void java_lang_reflect_Constructor::serialize(SerializeClosure* f) {
+  CONSTRUCTOR_FIELDS_DO(FIELD_SERIALIZE_OFFSET);
+}
+#endif
 
 Handle java_lang_reflect_Constructor::create(TRAPS) {
   assert(Universe::is_fully_initialized(), "Need to find another solution to the reflection problem");
@@ -2621,21 +3028,30 @@
   constructor->obj_field_put(type_annotations_offset, value);
 }
 
+#define FIELD_FIELDS_DO(macro) \
+  macro(clazz_offset,     k, vmSymbols::clazz_name(),     class_signature,  false); \
+  macro(name_offset,      k, vmSymbols::name_name(),      string_signature, false); \
+  macro(type_offset,      k, vmSymbols::type_name(),      class_signature,  false); \
+  macro(slot_offset,      k, vmSymbols::slot_name(),      int_signature,    false); \
+  macro(modifiers_offset, k, vmSymbols::modifiers_name(), int_signature,    false); \
+  macro##_OPTIONAL(signature_offset,        k, vmSymbols::signature_name(), string_signature); \
+  macro##_OPTIONAL(annotations_offset,      k, vmSymbols::annotations_name(),  byte_array_signature); \
+  macro##_OPTIONAL(type_annotations_offset, k, vmSymbols::type_annotations_name(),  byte_array_signature)
+
 void java_lang_reflect_Field::compute_offsets() {
   InstanceKlass* k = SystemDictionary::reflect_Field_klass();
-  compute_offset(clazz_offset,     k, vmSymbols::clazz_name(),     vmSymbols::class_signature());
-  compute_offset(name_offset,      k, vmSymbols::name_name(),      vmSymbols::string_signature());
-  compute_offset(type_offset,      k, vmSymbols::type_name(),      vmSymbols::class_signature());
-  compute_offset(slot_offset,      k, vmSymbols::slot_name(),      vmSymbols::int_signature());
-  compute_offset(modifiers_offset, k, vmSymbols::modifiers_name(), vmSymbols::int_signature());
   // The generic signature and annotations fields are only present in 1.5
   signature_offset = -1;
   annotations_offset = -1;
   type_annotations_offset = -1;
-  compute_optional_offset(signature_offset, k, vmSymbols::signature_name(), vmSymbols::string_signature());
-  compute_optional_offset(annotations_offset,  k, vmSymbols::annotations_name(),  vmSymbols::byte_array_signature());
-  compute_optional_offset(type_annotations_offset,  k, vmSymbols::type_annotations_name(),  vmSymbols::byte_array_signature());
-}
+  FIELD_FIELDS_DO(FIELD_COMPUTE_OFFSET);
+}
+
+#if INCLUDE_CDS
+void java_lang_reflect_Field::serialize(SerializeClosure* f) {
+  FIELD_FIELDS_DO(FIELD_SERIALIZE_OFFSET);
+}
+#endif
 
 Handle java_lang_reflect_Field::create(TRAPS) {
   assert(Universe::is_fully_initialized(), "Need to find another solution to the reflection problem");
@@ -2745,19 +3161,37 @@
   field->obj_field_put(type_annotations_offset, value);
 }
 
+#define CONSTANTPOOL_FIELDS_DO(macro) \
+  macro(_oop_offset, k, "constantPoolOop", object_signature, false)
+
 void reflect_ConstantPool::compute_offsets() {
   InstanceKlass* k = SystemDictionary::reflect_ConstantPool_klass();
   // The field is called ConstantPool* in the sun.reflect.ConstantPool class.
-  compute_offset(_oop_offset, k, "constantPoolOop", vmSymbols::object_signature());
-}
+  CONSTANTPOOL_FIELDS_DO(FIELD_COMPUTE_OFFSET);
+}
+
+#if INCLUDE_CDS
+void reflect_ConstantPool::serialize(SerializeClosure* f) {
+  CONSTANTPOOL_FIELDS_DO(FIELD_SERIALIZE_OFFSET);
+}
+#endif
+
+#define PARAMETER_FIELDS_DO(macro) \
+  macro(name_offset,        k, vmSymbols::name_name(),        string_signature, false); \
+  macro(modifiers_offset,   k, vmSymbols::modifiers_name(),   int_signature,    false); \
+  macro(index_offset,       k, vmSymbols::index_name(),       int_signature,    false); \
+  macro(executable_offset,  k, vmSymbols::executable_name(),  executable_signature, false)
 
 void java_lang_reflect_Parameter::compute_offsets() {
   InstanceKlass* k = SystemDictionary::reflect_Parameter_klass();
-  compute_offset(name_offset,        k, vmSymbols::name_name(),        vmSymbols::string_signature());
-  compute_offset(modifiers_offset,   k, vmSymbols::modifiers_name(),   vmSymbols::int_signature());
-  compute_offset(index_offset,       k, vmSymbols::index_name(),       vmSymbols::int_signature());
-  compute_offset(executable_offset,  k, vmSymbols::executable_name(),  vmSymbols::executable_signature());
-}
+  PARAMETER_FIELDS_DO(FIELD_COMPUTE_OFFSET);
+}
+
+#if INCLUDE_CDS
+void java_lang_reflect_Parameter::serialize(SerializeClosure* f) {
+  PARAMETER_FIELDS_DO(FIELD_SERIALIZE_OFFSET);
+}
+#endif
 
 Handle java_lang_reflect_Parameter::create(TRAPS) {
   assert(Universe::is_fully_initialized(), "Need to find another solution to the reflection problem");
@@ -2829,13 +3263,22 @@
   return jlmh;
 }
 
+#define MODULE_FIELDS_DO(macro) \
+  macro(loader_offset,  k, vmSymbols::loader_name(),  classloader_signature, false); \
+  macro(name_offset,    k, vmSymbols::name_name(),    string_signature,      false)
+
 void java_lang_Module::compute_offsets() {
   InstanceKlass* k = SystemDictionary::Module_klass();
-  compute_offset(loader_offset,  k, vmSymbols::loader_name(),  vmSymbols::classloader_signature());
-  compute_offset(name_offset,    k, vmSymbols::name_name(),    vmSymbols::string_signature());
+  MODULE_FIELDS_DO(FIELD_COMPUTE_OFFSET);
   MODULE_INJECTED_FIELDS(INJECTED_FIELD_COMPUTE_OFFSET);
 }
 
+#if INCLUDE_CDS
+void java_lang_Module::serialize(SerializeClosure* f) {
+  MODULE_FIELDS_DO(FIELD_SERIALIZE_OFFSET);
+  MODULE_INJECTED_FIELDS(INJECTED_FIELD_SERIALIZE_OFFSET);
+}
+#endif
 
 oop java_lang_Module::loader(oop module) {
   assert(Universe::is_fully_initialized(), "Need to find another solution to the reflection problem");
@@ -2912,10 +3355,19 @@
   return InstanceKlass::cast(k)->constants();
 }
 
+#define UNSAFESTATICFIELDACCESSORIMPL_FIELDS_DO(macro) \
+  macro(_base_offset, k, "base", object_signature, false)
+
 void reflect_UnsafeStaticFieldAccessorImpl::compute_offsets() {
   InstanceKlass* k = SystemDictionary::reflect_UnsafeStaticFieldAccessorImpl_klass();
-  compute_offset(_base_offset, k, "base", vmSymbols::object_signature());
-}
+  UNSAFESTATICFIELDACCESSORIMPL_FIELDS_DO(FIELD_COMPUTE_OFFSET);
+}
+
+#if INCLUDE_CDS
+void reflect_UnsafeStaticFieldAccessorImpl::serialize(SerializeClosure* f) {
+  UNSAFESTATICFIELDACCESSORIMPL_FIELDS_DO(FIELD_SERIALIZE_OFFSET);
+}
+#endif
 
 oop java_lang_boxing_object::initialize_and_allocate(BasicType type, TRAPS) {
   Klass* k = SystemDictionary::box_klass(type);
@@ -3074,11 +3526,20 @@
 // Support for java_lang_ref_SoftReference
 //
 
+#define SOFTREFERENCE_FIELDS_DO(macro) \
+  macro(timestamp_offset,    k, "timestamp", long_signature, false); \
+  macro(static_clock_offset, k, "clock",     long_signature, true)
+
 void java_lang_ref_SoftReference::compute_offsets() {
   InstanceKlass* k = SystemDictionary::SoftReference_klass();
-  compute_offset(timestamp_offset,    k, "timestamp", vmSymbols::long_signature());
-  compute_offset(static_clock_offset, k, "clock",     vmSymbols::long_signature(), true);
-}
+  SOFTREFERENCE_FIELDS_DO(FIELD_COMPUTE_OFFSET);
+}
+
+#if INCLUDE_CDS
+void java_lang_ref_SoftReference::serialize(SerializeClosure* f) {
+  SOFTREFERENCE_FIELDS_DO(FIELD_SERIALIZE_OFFSET);
+}
+#endif
 
 jlong java_lang_ref_SoftReference::timestamp(oop ref) {
   return ref->long_field(timestamp_offset);
@@ -3107,10 +3568,19 @@
   return dmh->obj_field(member_offset_in_bytes());
 }
 
+#define DIRECTMETHODHANDLE_FIELDS_DO(macro) \
+  macro(_member_offset, k, "member", java_lang_invoke_MemberName_signature, false)
+
 void java_lang_invoke_DirectMethodHandle::compute_offsets() {
   InstanceKlass* k = SystemDictionary::DirectMethodHandle_klass();
-  compute_offset(_member_offset, k, "member", vmSymbols::java_lang_invoke_MemberName_signature());
-}
+  DIRECTMETHODHANDLE_FIELDS_DO(FIELD_COMPUTE_OFFSET);
+}
+
+#if INCLUDE_CDS
+void java_lang_invoke_DirectMethodHandle::serialize(SerializeClosure* f) {
+  DIRECTMETHODHANDLE_FIELDS_DO(FIELD_SERIALIZE_OFFSET);
+}
+#endif
 
 // Support for java_lang_invoke_MethodHandle
 
@@ -3129,33 +3599,67 @@
 
 int java_lang_invoke_LambdaForm::_vmentry_offset;
 
+#define METHODHANDLE_FIELDS_DO(macro) \
+  macro(_type_offset, k, vmSymbols::type_name(), java_lang_invoke_MethodType_signature, false); \
+  macro(_form_offset, k, "form",                 java_lang_invoke_LambdaForm_signature, false)
+
 void java_lang_invoke_MethodHandle::compute_offsets() {
   InstanceKlass* k = SystemDictionary::MethodHandle_klass();
-  compute_offset(_type_offset, k, vmSymbols::type_name(), vmSymbols::java_lang_invoke_MethodType_signature());
-  compute_offset(_form_offset, k, "form", vmSymbols::java_lang_invoke_LambdaForm_signature());
-}
+  METHODHANDLE_FIELDS_DO(FIELD_COMPUTE_OFFSET);
+}
+
+#if INCLUDE_CDS
+void java_lang_invoke_MethodHandle::serialize(SerializeClosure* f) {
+  METHODHANDLE_FIELDS_DO(FIELD_SERIALIZE_OFFSET);
+}
+#endif
+
+#define MEMBERNAME_FIELDS_DO(macro) \
+  macro(_clazz_offset,   k, vmSymbols::clazz_name(),   class_signature,  false); \
+  macro(_name_offset,    k, vmSymbols::name_name(),    string_signature, false); \
+  macro(_type_offset,    k, vmSymbols::type_name(),    object_signature, false); \
+  macro(_flags_offset,   k, vmSymbols::flags_name(),   int_signature,    false); \
+  macro(_method_offset,  k, vmSymbols::method_name(),  java_lang_invoke_ResolvedMethodName_signature, false)
 
 void java_lang_invoke_MemberName::compute_offsets() {
   InstanceKlass* k = SystemDictionary::MemberName_klass();
-  compute_offset(_clazz_offset,   k, vmSymbols::clazz_name(),   vmSymbols::class_signature());
-  compute_offset(_name_offset,    k, vmSymbols::name_name(),    vmSymbols::string_signature());
-  compute_offset(_type_offset,    k, vmSymbols::type_name(),    vmSymbols::object_signature());
-  compute_offset(_flags_offset,   k, vmSymbols::flags_name(),   vmSymbols::int_signature());
-  compute_offset(_method_offset,  k, vmSymbols::method_name(),  vmSymbols::java_lang_invoke_ResolvedMethodName_signature());
+  MEMBERNAME_FIELDS_DO(FIELD_COMPUTE_OFFSET);
   MEMBERNAME_INJECTED_FIELDS(INJECTED_FIELD_COMPUTE_OFFSET);
 }
 
+#if INCLUDE_CDS
+void java_lang_invoke_MemberName::serialize(SerializeClosure* f) {
+  MEMBERNAME_FIELDS_DO(FIELD_SERIALIZE_OFFSET);
+  MEMBERNAME_INJECTED_FIELDS(INJECTED_FIELD_SERIALIZE_OFFSET);
+}
+#endif
+
 void java_lang_invoke_ResolvedMethodName::compute_offsets() {
   InstanceKlass* k = SystemDictionary::ResolvedMethodName_klass();
   assert(k != NULL, "jdk mismatch");
   RESOLVEDMETHOD_INJECTED_FIELDS(INJECTED_FIELD_COMPUTE_OFFSET);
 }
 
+#if INCLUDE_CDS
+void java_lang_invoke_ResolvedMethodName::serialize(SerializeClosure* f) {
+  RESOLVEDMETHOD_INJECTED_FIELDS(INJECTED_FIELD_SERIALIZE_OFFSET);
+}
+#endif
+
+#define LAMBDAFORM_FIELDS_DO(macro) \
+  macro(_vmentry_offset, k, "vmentry", java_lang_invoke_MemberName_signature, false)
+
 void java_lang_invoke_LambdaForm::compute_offsets() {
   InstanceKlass* k = SystemDictionary::LambdaForm_klass();
   assert (k != NULL, "jdk mismatch");
-  compute_offset(_vmentry_offset, k, "vmentry", vmSymbols::java_lang_invoke_MemberName_signature());
-}
+  LAMBDAFORM_FIELDS_DO(FIELD_COMPUTE_OFFSET);
+}
+
+#if INCLUDE_CDS
+void java_lang_invoke_LambdaForm::serialize(SerializeClosure* f) {
+  LAMBDAFORM_FIELDS_DO(FIELD_SERIALIZE_OFFSET);
+}
+#endif
 
 bool java_lang_invoke_LambdaForm::is_instance(oop obj) {
   return obj != NULL && is_subclass(obj->klass());
@@ -3294,11 +3798,20 @@
 int java_lang_invoke_MethodType::_rtype_offset;
 int java_lang_invoke_MethodType::_ptypes_offset;
 
+#define METHODTYPE_FIELDS_DO(macro) \
+  macro(_rtype_offset,  k, "rtype",  class_signature,       false); \
+  macro(_ptypes_offset, k, "ptypes", class_array_signature, false)
+
 void java_lang_invoke_MethodType::compute_offsets() {
   InstanceKlass* k = SystemDictionary::MethodType_klass();
-  compute_offset(_rtype_offset,  k, "rtype",  vmSymbols::class_signature());
-  compute_offset(_ptypes_offset, k, "ptypes", vmSymbols::class_array_signature());
-}
+  METHODTYPE_FIELDS_DO(FIELD_COMPUTE_OFFSET);
+}
+
+#if INCLUDE_CDS
+void java_lang_invoke_MethodType::serialize(SerializeClosure* f) {
+  METHODTYPE_FIELDS_DO(FIELD_SERIALIZE_OFFSET);
+}
+#endif
 
 void java_lang_invoke_MethodType::print_signature(oop mt, outputStream* st) {
   st->print("(");
@@ -3379,12 +3892,20 @@
 int java_lang_invoke_CallSite::_target_offset;
 int java_lang_invoke_CallSite::_context_offset;
 
+#define CALLSITE_FIELDS_DO(macro) \
+  macro(_target_offset,  k, "target", java_lang_invoke_MethodHandle_signature, false); \
+  macro(_context_offset, k, "context", java_lang_invoke_MethodHandleNatives_CallSiteContext_signature, false)
+
 void java_lang_invoke_CallSite::compute_offsets() {
   InstanceKlass* k = SystemDictionary::CallSite_klass();
-  compute_offset(_target_offset,  k, "target", vmSymbols::java_lang_invoke_MethodHandle_signature());
-  compute_offset(_context_offset, k, "context",
-                 vmSymbols::java_lang_invoke_MethodHandleNatives_CallSiteContext_signature());
-}
+  CALLSITE_FIELDS_DO(FIELD_COMPUTE_OFFSET);
+}
+
+#if INCLUDE_CDS
+void java_lang_invoke_CallSite::serialize(SerializeClosure* f) {
+  CALLSITE_FIELDS_DO(FIELD_SERIALIZE_OFFSET);
+}
+#endif
 
 oop java_lang_invoke_CallSite::context(oop call_site) {
   assert(java_lang_invoke_CallSite::is_instance(call_site), "");
@@ -3402,6 +3923,12 @@
   CALLSITECONTEXT_INJECTED_FIELDS(INJECTED_FIELD_COMPUTE_OFFSET);
 }
 
+#if INCLUDE_CDS
+void java_lang_invoke_MethodHandleNatives_CallSiteContext::serialize(SerializeClosure* f) {
+  CALLSITECONTEXT_INJECTED_FIELDS(INJECTED_FIELD_SERIALIZE_OFFSET);
+}
+#endif
+
 DependencyContext java_lang_invoke_MethodHandleNatives_CallSiteContext::vmdependencies(oop call_site) {
   assert(java_lang_invoke_MethodHandleNatives_CallSiteContext::is_instance(call_site), "");
   intptr_t* vmdeps_addr = (intptr_t*)call_site->field_addr(_vmdependencies_offset);
@@ -3416,16 +3943,23 @@
 int java_security_AccessControlContext::_isPrivileged_offset = 0;
 int java_security_AccessControlContext::_isAuthorized_offset = -1;
 
+#define ACCESSCONTROLCONTEXT_FIELDS_DO(macro) \
+  macro(_context_offset,           k, "context",      protectiondomain_signature, false); \
+  macro(_privilegedContext_offset, k, "privilegedContext", accesscontrolcontext_signature, false); \
+  macro(_isPrivileged_offset,      k, "isPrivileged", bool_signature, false); \
+  macro(_isAuthorized_offset,      k, "isAuthorized", bool_signature, false)
+
 void java_security_AccessControlContext::compute_offsets() {
   assert(_isPrivileged_offset == 0, "offsets should be initialized only once");
   InstanceKlass* k = SystemDictionary::AccessControlContext_klass();
-
-  compute_offset(_context_offset,           k, "context",      vmSymbols::protectiondomain_signature());
-  compute_offset(_privilegedContext_offset, k, "privilegedContext", vmSymbols::accesscontrolcontext_signature());
-  compute_offset(_isPrivileged_offset,      k, "isPrivileged", vmSymbols::bool_signature());
-  compute_offset(_isAuthorized_offset,      k, "isAuthorized", vmSymbols::bool_signature());
-}
-
+  ACCESSCONTROLCONTEXT_FIELDS_DO(FIELD_COMPUTE_OFFSET);
+}
+
+#if INCLUDE_CDS
+void java_security_AccessControlContext::serialize(SerializeClosure* f) {
+  ACCESSCONTROLCONTEXT_FIELDS_DO(FIELD_SERIALIZE_OFFSET);
+}
+#endif
 
 bool java_security_AccessControlContext::is_authorized(Handle context) {
   assert(context.not_null() && context->klass() == SystemDictionary::AccessControlContext_klass(), "Invalid type");
@@ -3469,25 +4003,29 @@
   return HeapAccess<>::atomic_cmpxchg_at(new_data, loader, _loader_data_offset, expected_data);
 }
 
+#define CLASSLOADER_FIELDS_DO(macro) \
+  macro(parallelCapable_offset, k1, "parallelLockMap",      concurrenthashmap_signature, false); \
+  macro(name_offset,            k1, vmSymbols::name_name(), string_signature, false); \
+  macro(unnamedModule_offset,   k1, "unnamedModule",        module_signature, false); \
+  macro(parent_offset,          k1, "parent",               classloader_signature, false)
+
 void java_lang_ClassLoader::compute_offsets() {
   assert(!offsets_computed, "offsets should be initialized only once");
   offsets_computed = true;
 
   InstanceKlass* k1 = SystemDictionary::ClassLoader_klass();
-  compute_offset(parallelCapable_offset,
-    k1, "parallelLockMap", vmSymbols::concurrenthashmap_signature());
-
-  compute_offset(name_offset,
-    k1, vmSymbols::name_name(), vmSymbols::string_signature());
-
-  compute_offset(unnamedModule_offset,
-    k1, "unnamedModule", vmSymbols::module_signature());
-
-  compute_offset(parent_offset, k1, "parent", vmSymbols::classloader_signature());
+  CLASSLOADER_FIELDS_DO(FIELD_COMPUTE_OFFSET);
 
   CLASSLOADER_INJECTED_FIELDS(INJECTED_FIELD_COMPUTE_OFFSET);
 }
 
+#if INCLUDE_CDS
+void java_lang_ClassLoader::serialize(SerializeClosure* f) {
+  CLASSLOADER_FIELDS_DO(FIELD_SERIALIZE_OFFSET);
+  CLASSLOADER_INJECTED_FIELDS(INJECTED_FIELD_SERIALIZE_OFFSET);
+}
+#endif
+
 oop java_lang_ClassLoader::parent(oop loader) {
   assert(is_instance(loader), "loader must be oop");
   return loader->obj_field(parent_offset);
@@ -3571,13 +4109,22 @@
 
 // Support for java_lang_System
 //
+#define SYSTEM_FIELDS_DO(macro) \
+  macro(static_in_offset,  k, "in",  input_stream_signature, true); \
+  macro(static_out_offset, k, "out", print_stream_signature, true); \
+  macro(static_err_offset, k, "err", print_stream_signature, true); \
+  macro(static_security_offset, k, "security", security_manager_signature, true)
+
 void java_lang_System::compute_offsets() {
   InstanceKlass* k = SystemDictionary::System_klass();
-  compute_offset(static_in_offset,  k, "in",  vmSymbols::input_stream_signature(), true);
-  compute_offset(static_out_offset, k, "out", vmSymbols::print_stream_signature(), true);
-  compute_offset(static_err_offset, k, "err", vmSymbols::print_stream_signature(), true);
-  compute_offset(static_security_offset, k, "security", vmSymbols::security_manager_signature(), true);
-}
+  SYSTEM_FIELDS_DO(FIELD_COMPUTE_OFFSET);
+}
+
+#if INCLUDE_CDS
+void java_lang_System::serialize(SerializeClosure* f) {
+   SYSTEM_FIELDS_DO(FIELD_SERIALIZE_OFFSET);
+}
+#endif
 
 int java_lang_System::in_offset_in_bytes() { return static_in_offset; }
 int java_lang_System::out_offset_in_bytes() { return static_out_offset; }
@@ -3683,19 +4230,27 @@
 int reflect_ConstantPool::_oop_offset;
 int reflect_UnsafeStaticFieldAccessorImpl::_base_offset;
 
+#define STACKTRACEELEMENT_FIELDS_DO(macro) \
+  macro(declaringClassObject_offset,  k, "declaringClassObject", class_signature, false); \
+  macro(classLoaderName_offset, k, "classLoaderName", string_signature, false); \
+  macro(moduleName_offset,      k, "moduleName",      string_signature, false); \
+  macro(moduleVersion_offset,   k, "moduleVersion",   string_signature, false); \
+  macro(declaringClass_offset,  k, "declaringClass",  string_signature, false); \
+  macro(methodName_offset,      k, "methodName",      string_signature, false); \
+  macro(fileName_offset,        k, "fileName",        string_signature, false); \
+  macro(lineNumber_offset,      k, "lineNumber",      int_signature,    false)
 
 // Support for java_lang_StackTraceElement
 void java_lang_StackTraceElement::compute_offsets() {
   InstanceKlass* k = SystemDictionary::StackTraceElement_klass();
-  compute_offset(declaringClassObject_offset,  k, "declaringClassObject", vmSymbols::class_signature());
-  compute_offset(classLoaderName_offset, k, "classLoaderName", vmSymbols::string_signature());
-  compute_offset(moduleName_offset,      k, "moduleName",      vmSymbols::string_signature());
-  compute_offset(moduleVersion_offset,   k, "moduleVersion",   vmSymbols::string_signature());
-  compute_offset(declaringClass_offset,  k, "declaringClass",  vmSymbols::string_signature());
-  compute_offset(methodName_offset,      k, "methodName",      vmSymbols::string_signature());
-  compute_offset(fileName_offset,        k, "fileName",        vmSymbols::string_signature());
-  compute_offset(lineNumber_offset,      k, "lineNumber",      vmSymbols::int_signature());
-}
+  STACKTRACEELEMENT_FIELDS_DO(FIELD_COMPUTE_OFFSET);
+}
+
+#if INCLUDE_CDS
+void java_lang_StackTraceElement::serialize(SerializeClosure* f) {
+  STACKTRACEELEMENT_FIELDS_DO(FIELD_SERIALIZE_OFFSET);
+}
+#endif
 
 void java_lang_StackTraceElement::set_fileName(oop element, oop value) {
   element->obj_field_put(fileName_offset, value);
@@ -3754,16 +4309,23 @@
 }
 
 // Support for java Assertions - java_lang_AssertionStatusDirectives.
+#define ASSERTIONSTATUSDIRECTIVES_FIELDS_DO(macro) \
+  macro(classes_offset,        k, "classes",        string_array_signature, false); \
+  macro(classEnabled_offset,   k, "classEnabled",   bool_array_signature, false); \
+  macro(packages_offset,       k, "packages",       string_array_signature, false); \
+  macro(packageEnabled_offset, k, "packageEnabled", bool_array_signature,   false); \
+  macro(deflt_offset,          k, "deflt",          bool_signature,         false)
 
 void java_lang_AssertionStatusDirectives::compute_offsets() {
   InstanceKlass* k = SystemDictionary::AssertionStatusDirectives_klass();
-  compute_offset(classes_offset,        k, "classes",        vmSymbols::string_array_signature());
-  compute_offset(classEnabled_offset,   k, "classEnabled",   vmSymbols::bool_array_signature());
-  compute_offset(packages_offset,       k, "packages",       vmSymbols::string_array_signature());
-  compute_offset(packageEnabled_offset, k, "packageEnabled", vmSymbols::bool_array_signature());
-  compute_offset(deflt_offset,          k, "deflt",          vmSymbols::bool_signature());
-}
-
+  ASSERTIONSTATUSDIRECTIVES_FIELDS_DO(FIELD_COMPUTE_OFFSET);
+}
+
+#if INCLUDE_CDS
+void java_lang_AssertionStatusDirectives::serialize(SerializeClosure* f) {
+  ASSERTIONSTATUSDIRECTIVES_FIELDS_DO(FIELD_SERIALIZE_OFFSET);
+}
+#endif
 
 void java_lang_AssertionStatusDirectives::set_classes(oop o, oop val) {
   o->obj_field_put(classes_offset, val);
@@ -3791,12 +4353,20 @@
   return _limit_offset;
 }
 
+#define BUFFER_FIELDS_DO(macro) \
+  macro(_limit_offset, k, "limit", int_signature, false)
 
 void java_nio_Buffer::compute_offsets() {
   InstanceKlass* k = SystemDictionary::nio_Buffer_klass();
   assert(k != NULL, "must be loaded in 1.4+");
-  compute_offset(_limit_offset, k, "limit", vmSymbols::int_signature());
-}
+  BUFFER_FIELDS_DO(FIELD_COMPUTE_OFFSET);
+}
+
+#if INCLUDE_CDS
+void java_nio_Buffer::serialize(SerializeClosure* f) {
+  BUFFER_FIELDS_DO(FIELD_SERIALIZE_OFFSET);
+}
+#endif
 
 void java_util_concurrent_locks_AbstractOwnableSynchronizer::initialize(TRAPS) {
   if (_owner_offset != 0) return;
@@ -3835,6 +4405,10 @@
 
 // Compute non-hard-coded field offsets of all the classes in this file
 void JavaClasses::compute_offsets() {
+  if (UseSharedSpaces) {
+    return; // field offsets are loaded from archive
+  }
+
   // java_lang_Class::compute_offsets was called earlier in bootstrap
   java_lang_System::compute_offsets();
   java_lang_ClassLoader::compute_offsets();
--- a/src/hotspot/share/classfile/javaClasses.hpp	Fri Mar 02 10:42:32 2018 -0800
+++ b/src/hotspot/share/classfile/javaClasses.hpp	Fri Mar 02 17:25:55 2018 -0500
@@ -71,6 +71,7 @@
   };
 
   static void compute_offsets();
+  static void serialize(SerializeClosure* f) NOT_CDS_RETURN;
 
   // Instance creation
   static Handle create_from_unicode(jchar* unicode, int len, TRAPS);
@@ -222,6 +223,15 @@
   static void fixup_mirror(Klass* k, TRAPS);
   static oop  create_basic_type_mirror(const char* basic_type_name, BasicType type, TRAPS);
 
+  // Archiving
+  static void serialize(SerializeClosure* f) NOT_CDS_RETURN;
+  static void archive_basic_type_mirrors(TRAPS) NOT_CDS_JAVA_HEAP_RETURN;
+  static oop  archive_mirror(Klass* k, TRAPS) NOT_CDS_JAVA_HEAP_RETURN_(NULL);
+  static oop  process_archived_mirror(Klass* k, oop mirror, oop archived_mirror, Thread *THREAD)
+                                      NOT_CDS_JAVA_HEAP_RETURN_(NULL);
+  static void restore_archived_mirror(Klass *k, Handle mirror, Handle class_loader, Handle module,
+                                      Handle protection_domain, TRAPS) NOT_CDS_JAVA_HEAP_RETURN;
+
   static void fixup_module_field(Klass* k, Handle module);
 
   // Conversion
@@ -306,6 +316,8 @@
   static void compute_offsets();
 
  public:
+  static void serialize(SerializeClosure* f) NOT_CDS_RETURN;
+
   // Instance creation
   static oop create();
   // Returns the JavaThread associated with the thread obj
@@ -406,6 +418,8 @@
   static void compute_offsets();
 
  public:
+  static void serialize(SerializeClosure* f) NOT_CDS_RETURN;
+
   // parent ThreadGroup
   static oop  parent(oop java_thread_group);
   // name
@@ -485,6 +499,7 @@
   static void print_stack_usage(Handle stream);
 
   static void compute_offsets();
+  static void serialize(SerializeClosure* f) NOT_CDS_RETURN;
 
   // Allocate space for backtrace (created but stack trace not filled in)
   static void allocate_backtrace(Handle throwable, TRAPS);
@@ -515,6 +530,8 @@
   static void compute_offsets();
 
  public:
+  static void serialize(SerializeClosure* f) NOT_CDS_RETURN;
+
   // Accessors
   static jboolean override(oop reflect);
   static void set_override(oop reflect, jboolean value);
@@ -546,6 +563,8 @@
   static void compute_offsets();
 
  public:
+  static void serialize(SerializeClosure* f) NOT_CDS_RETURN;
+
   // Allocation
   static Handle create(TRAPS);
 
@@ -615,6 +634,8 @@
   static void compute_offsets();
 
  public:
+  static void serialize(SerializeClosure* f) NOT_CDS_RETURN;
+
   // Allocation
   static Handle create(TRAPS);
 
@@ -673,6 +694,8 @@
   static void compute_offsets();
 
  public:
+  static void serialize(SerializeClosure* f) NOT_CDS_RETURN;
+
   // Allocation
   static Handle create(TRAPS);
 
@@ -728,6 +751,8 @@
   static void compute_offsets();
 
  public:
+  static void serialize(SerializeClosure* f) NOT_CDS_RETURN;
+
   // Allocation
   static Handle create(TRAPS);
 
@@ -758,6 +783,8 @@
     static void compute_offsets();
 
   public:
+    static void serialize(SerializeClosure* f) NOT_CDS_RETURN;
+
     // Allocation
     static Handle create(Handle loader, Handle module_name, TRAPS);
 
@@ -787,6 +814,8 @@
   static void compute_offsets();
 
  public:
+  static void serialize(SerializeClosure* f) NOT_CDS_RETURN;
+
   // Allocation
   static Handle create(TRAPS);
 
@@ -809,6 +838,8 @@
   static void compute_offsets();
 
  public:
+  static void serialize(SerializeClosure* f) NOT_CDS_RETURN;
+
   static int base_offset() {
     return _base_offset;
   }
@@ -910,6 +941,7 @@
   static void set_clock(jlong value);
 
   static void compute_offsets();
+  static void serialize(SerializeClosure* f) NOT_CDS_RETURN;
 };
 
 // Interface to java.lang.invoke.MethodHandle objects
@@ -926,6 +958,8 @@
   static void compute_offsets();
 
  public:
+  static void serialize(SerializeClosure* f) NOT_CDS_RETURN;
+
   // Accessors
   static oop            type(oop mh);
   static void       set_type(oop mh, oop mtype);
@@ -955,6 +989,8 @@
   static void compute_offsets();
 
  public:
+  static void serialize(SerializeClosure* f) NOT_CDS_RETURN;
+
   // Accessors
   static oop  member(oop mh);
 
@@ -980,6 +1016,8 @@
   static void compute_offsets();
 
  public:
+  static void serialize(SerializeClosure* f) NOT_CDS_RETURN;
+
   // Accessors
   static oop            vmentry(oop lform);
   static void       set_vmentry(oop lform, oop invoker);
@@ -1011,6 +1049,8 @@
 
   static void compute_offsets();
  public:
+  static void serialize(SerializeClosure* f) NOT_CDS_RETURN;
+
   static int vmtarget_offset_in_bytes() { return _vmtarget_offset; }
 
   static Method* vmtarget(oop resolved_method);
@@ -1048,6 +1088,7 @@
   static void compute_offsets();
 
  public:
+  static void serialize(SerializeClosure* f) NOT_CDS_RETURN;
   // Accessors
   static oop            clazz(oop mname);
   static void       set_clazz(oop mname, oop clazz);
@@ -1112,6 +1153,7 @@
   static void compute_offsets();
 
  public:
+  static void serialize(SerializeClosure* f) NOT_CDS_RETURN;
   // Accessors
   static oop            rtype(oop mt);
   static objArrayOop    ptypes(oop mt);
@@ -1147,6 +1189,7 @@
   static void compute_offsets();
 
 public:
+  static void serialize(SerializeClosure* f) NOT_CDS_RETURN;
   // Accessors
   static oop              target(          oop site);
   static void         set_target(          oop site, oop target);
@@ -1180,6 +1223,7 @@
   static void compute_offsets();
 
 public:
+  static void serialize(SerializeClosure* f) NOT_CDS_RETURN;
   // Accessors
   static DependencyContext vmdependencies(oop context);
 
@@ -1203,6 +1247,7 @@
 
   static void compute_offsets();
  public:
+  static void serialize(SerializeClosure* f) NOT_CDS_RETURN;
   static oop create(objArrayHandle context, bool isPrivileged, Handle privileged_context, TRAPS);
 
   static bool is_authorized(Handle context);
@@ -1228,6 +1273,7 @@
 
  public:
   static void compute_offsets();
+  static void serialize(SerializeClosure* f) NOT_CDS_RETURN;
 
   static ClassLoaderData* loader_data(oop loader);
   static ClassLoaderData* cmpxchg_loader_data(ClassLoaderData* new_data, oop loader, ClassLoaderData* expected_data);
@@ -1279,6 +1325,7 @@
   static bool has_security_manager();
 
   static void compute_offsets();
+  static void serialize(SerializeClosure* f) NOT_CDS_RETURN;
 
   // Debugging
   friend class JavaClasses;
@@ -1316,6 +1363,7 @@
                       int version, int bci, Symbol* name, TRAPS);
 
   static void compute_offsets();
+  static void serialize(SerializeClosure* f) NOT_CDS_RETURN;
 
   // Debugging
   friend class JavaClasses;
@@ -1359,6 +1407,7 @@
   static void set_version(oop info, short value);
 
   static void compute_offsets();
+  static void serialize(SerializeClosure* f) NOT_CDS_RETURN;
 
   static void to_stack_trace_element(Handle stackFrame, Handle stack_trace_element, TRAPS);
 
@@ -1380,6 +1429,7 @@
   static void set_mode(oop info, int value);
 
   static void compute_offsets();
+  static void serialize(SerializeClosure* f) NOT_CDS_RETURN;
 
   // Debugging
   friend class JavaClasses;
@@ -1404,6 +1454,7 @@
   static void set_deflt(oop obj, bool val);
 
   static void compute_offsets();
+  static void serialize(SerializeClosure* f) NOT_CDS_RETURN;
 
   // Debugging
   friend class JavaClasses;
@@ -1417,6 +1468,7 @@
  public:
   static int  limit_offset();
   static void compute_offsets();
+  static void serialize(SerializeClosure* f) NOT_CDS_RETURN;
 };
 
 class java_util_concurrent_locks_AbstractOwnableSynchronizer : AllStatic {
--- a/src/hotspot/share/classfile/stringTable.cpp	Fri Mar 02 10:42:32 2018 -0800
+++ b/src/hotspot/share/classfile/stringTable.cpp	Fri Mar 02 17:25:55 2018 -0500
@@ -703,7 +703,6 @@
   assert(MetaspaceShared::is_heap_object_archiving_allowed(), "must be");
 
   Thread* THREAD = Thread::current();
-  G1CollectedHeap::heap()->begin_archive_alloc_range();
   for (int i = 0; i < the_table()->table_size(); ++i) {
     HashtableEntry<oop, mtSymbol>* bucket = the_table()->bucket(i);
     for ( ; bucket != NULL; bucket = bucket->next()) {
@@ -727,7 +726,6 @@
     }
   }
 
-  G1CollectedHeap::heap()->end_archive_alloc_range(string_space, os::vm_allocation_granularity());
   return true;
 }
 
--- a/src/hotspot/share/logging/logTag.hpp	Fri Mar 02 10:42:32 2018 -0800
+++ b/src/hotspot/share/logging/logTag.hpp	Fri Mar 02 17:25:55 2018 -0500
@@ -148,6 +148,7 @@
   LOG_TAG(update) \
   LOG_TAG(unload) /* Trace unloading of classes */ \
   LOG_TAG(unshareable) \
+  LOG_TAG(mirror) \
   LOG_TAG(verification) \
   LOG_TAG(verify) \
   LOG_TAG(vmoperation) \
--- a/src/hotspot/share/memory/filemap.hpp	Fri Mar 02 10:42:32 2018 -0800
+++ b/src/hotspot/share/memory/filemap.hpp	Fri Mar 02 17:25:55 2018 -0500
@@ -125,14 +125,13 @@
     size_t  _cds_i2i_entry_code_buffers_size;
     size_t  _core_spaces_size;        // number of bytes allocated by the core spaces
                                       // (mc, md, ro, rw and od).
-
     struct space_info {
       int    _crc;           // crc checksum of the current space
       size_t _file_offset;   // sizeof(this) rounded to vm page size
       union {
         char*  _base;        // copy-on-write base address
         intx   _offset;      // offset from the compressed oop encoding base, only used
-                             // by string space
+                             // by archive heap space
       } _addr;
       size_t _used;          // for setting space top on read
       bool   _read_only;     // read only space?
--- a/src/hotspot/share/memory/iterator.hpp	Fri Mar 02 10:42:32 2018 -0800
+++ b/src/hotspot/share/memory/iterator.hpp	Fri Mar 02 17:25:55 2018 -0500
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -344,6 +344,9 @@
   // correct length.
   virtual void do_tag(int tag) = 0;
 
+  // Read/write the oop
+  virtual void do_oop(oop* o) = 0;
+
   bool writing() {
     return !reading();
   }
--- a/src/hotspot/share/memory/metaspaceShared.cpp	Fri Mar 02 10:42:32 2018 -0800
+++ b/src/hotspot/share/memory/metaspaceShared.cpp	Fri Mar 02 17:25:55 2018 -0500
@@ -375,9 +375,45 @@
   StringTable::serialize(soc);
   soc->do_tag(--tag);
 
+  serialize_well_known_classes(soc);
+  soc->do_tag(--tag);
+
   soc->do_tag(666);
 }
 
+void MetaspaceShared::serialize_well_known_classes(SerializeClosure* soc) {
+  java_lang_Class::serialize(soc);
+  java_lang_String::serialize(soc);
+  java_lang_System::serialize(soc);
+  java_lang_ClassLoader::serialize(soc);
+  java_lang_Throwable::serialize(soc);
+  java_lang_Thread::serialize(soc);
+  java_lang_ThreadGroup::serialize(soc);
+  java_lang_AssertionStatusDirectives::serialize(soc);
+  java_lang_ref_SoftReference::serialize(soc);
+  java_lang_invoke_MethodHandle::serialize(soc);
+  java_lang_invoke_DirectMethodHandle::serialize(soc);
+  java_lang_invoke_MemberName::serialize(soc);
+  java_lang_invoke_ResolvedMethodName::serialize(soc);
+  java_lang_invoke_LambdaForm::serialize(soc);
+  java_lang_invoke_MethodType::serialize(soc);
+  java_lang_invoke_CallSite::serialize(soc);
+  java_lang_invoke_MethodHandleNatives_CallSiteContext::serialize(soc);
+  java_security_AccessControlContext::serialize(soc);
+  java_lang_reflect_AccessibleObject::serialize(soc);
+  java_lang_reflect_Method::serialize(soc);
+  java_lang_reflect_Constructor::serialize(soc);
+  java_lang_reflect_Field::serialize(soc);
+  java_nio_Buffer::serialize(soc);
+  reflect_ConstantPool::serialize(soc);
+  reflect_UnsafeStaticFieldAccessorImpl::serialize(soc);
+  java_lang_reflect_Parameter::serialize(soc);
+  java_lang_Module::serialize(soc);
+  java_lang_StackTraceElement::serialize(soc);
+  java_lang_StackFrameInfo::serialize(soc);
+  java_lang_LiveStackFrameInfo::serialize(soc);
+}
+
 address MetaspaceShared::cds_i2i_entry_code_buffers(size_t total_size) {
   if (DumpSharedSpaces) {
     if (_cds_i2i_entry_code_buffers == NULL) {
@@ -415,7 +451,12 @@
 class CollectClassesClosure : public KlassClosure {
   void do_klass(Klass* k) {
     if (!(k->is_instance_klass() && InstanceKlass::cast(k)->is_in_error_state())) {
-      _global_klass_objects->append_if_missing(k);
+      if (k->is_instance_klass() && InstanceKlass::cast(k)->signers() != NULL) {
+        // Mark any class with signers and don't add to the _global_klass_objects
+        k->set_has_signer_and_not_archived();
+      } else {
+        _global_klass_objects->append_if_missing(k);
+      }
     }
     if (k->is_array_klass()) {
       // Add in the array classes too
@@ -452,6 +493,19 @@
   }
 }
 
+static void clear_basic_type_mirrors() {
+  assert(!MetaspaceShared::is_heap_object_archiving_allowed(), "Sanity");
+  Universe::set_int_mirror(NULL);
+  Universe::set_float_mirror(NULL);
+  Universe::set_double_mirror(NULL);
+  Universe::set_byte_mirror(NULL);
+  Universe::set_bool_mirror(NULL);
+  Universe::set_char_mirror(NULL);
+  Universe::set_long_mirror(NULL);
+  Universe::set_short_mirror(NULL);
+  Universe::set_void_mirror(NULL);
+}
+
 static void rewrite_nofast_bytecode(Method* method) {
   BytecodeStream bcs(method);
   while (!bcs.is_last_bytecode()) {
@@ -775,6 +829,17 @@
     _dump_region->append_intptr_t((intptr_t)tag);
   }
 
+  void do_oop(oop* o) {
+    if (*o == NULL) {
+      _dump_region->append_intptr_t(0);
+    } else {
+      assert(MetaspaceShared::is_heap_object_archiving_allowed(),
+             "Archiving heap object is not allowed");
+      _dump_region->append_intptr_t(
+        (intptr_t)oopDesc::encode_heap_oop_not_null(*o));
+    }
+  }
+
   void do_region(u_char* start, size_t size) {
     assert((intptr_t)start % sizeof(intptr_t) == 0, "bad alignment");
     assert(size % sizeof(intptr_t) == 0, "bad size");
@@ -935,7 +1000,7 @@
 
 class VM_PopulateDumpSharedSpace: public VM_Operation {
 private:
-  GrowableArray<MemRegion> *_string_regions;
+  GrowableArray<MemRegion> *_closed_archive_heap_regions;
   GrowableArray<MemRegion> *_open_archive_heap_regions;
 
   void dump_java_heap_objects() NOT_CDS_JAVA_HEAP_RETURN;
@@ -1193,6 +1258,7 @@
   }
 
   static Klass* get_relocated_klass(Klass* orig_klass) {
+    assert(DumpSharedSpaces, "dump time only");
     address* pp = _new_loc_table->get((address)orig_klass);
     assert(pp != NULL, "must be");
     Klass* klass = (Klass*)(*pp);
@@ -1222,7 +1288,11 @@
   // Reorder the system dictionary. Moving the symbols affects
   // how the hash table indices are calculated.
   SystemDictionary::reorder_dictionary_for_sharing();
+
   tty->print("Removing java_mirror ... ");
+  if (!MetaspaceShared::is_heap_object_archiving_allowed()) {
+    clear_basic_type_mirrors();
+  }
   remove_java_mirror_in_classes();
   tty->print_cr("done. ");
   NOT_PRODUCT(SystemDictionary::verify();)
@@ -1312,7 +1382,7 @@
   dump_symbols();
 
   // Dump supported java heap objects
-  _string_regions = NULL;
+  _closed_archive_heap_regions = NULL;
   _open_archive_heap_regions = NULL;
   dump_java_heap_objects();
 
@@ -1375,7 +1445,7 @@
     write_region(mapinfo, MetaspaceShared::od, &_od_region, /*read_only=*/true, /*allow_exec=*/false);
 
     _total_string_region_size = mapinfo->write_archive_heap_regions(
-                                        _string_regions,
+                                        _closed_archive_heap_regions,
                                         MetaspaceShared::first_string,
                                         MetaspaceShared::max_strings);
     _total_open_archive_region_size = mapinfo->write_archive_heap_regions(
@@ -1424,7 +1494,7 @@
   _ro_region.print(total_reserved);
   _md_region.print(total_reserved);
   _od_region.print(total_reserved);
-  print_heap_region_stats(_string_regions, "st", total_reserved);
+  print_heap_region_stats(_closed_archive_heap_regions, "st", total_reserved);
   print_heap_region_stats(_open_archive_heap_regions, "oa", total_reserved);
 
   tty->print_cr("total    : " SIZE_FORMAT_W(9) " [100.0%% of total] out of " SIZE_FORMAT_W(9) " bytes [%5.1f%% used]",
@@ -1452,6 +1522,11 @@
   o->set_klass(k);
 }
 
+Klass* MetaspaceShared::get_relocated_klass(Klass *k) {
+  assert(DumpSharedSpaces, "sanity");
+  return ArchiveCompactor::get_relocated_klass(k);
+}
+
 class LinkSharedClassesClosure : public KlassClosure {
   Thread* THREAD;
   bool    _made_progress;
@@ -1693,11 +1768,11 @@
     // Cache for recording where the archived objects are copied to
     MetaspaceShared::create_archive_object_cache();
 
-    tty->print_cr("Dumping String objects to closed archive heap region ...");
+    tty->print_cr("Dumping objects to closed archive heap region ...");
     NOT_PRODUCT(StringTable::verify());
-    // The string space has maximum two regions. See FileMapInfo::write_archive_heap_regions() for details.
-    _string_regions = new GrowableArray<MemRegion>(2);
-    StringTable::write_to_archive(_string_regions);
+    // The closed space has maximum two regions. See FileMapInfo::write_archive_heap_regions() for details.
+    _closed_archive_heap_regions = new GrowableArray<MemRegion>(2);
+    MetaspaceShared::dump_closed_archive_heap_objects(_closed_archive_heap_regions);
 
     tty->print_cr("Dumping objects to open archive heap region ...");
     _open_archive_heap_regions = new GrowableArray<MemRegion>(2);
@@ -1709,6 +1784,20 @@
   G1HeapVerifier::verify_archive_regions();
 }
 
+void MetaspaceShared::dump_closed_archive_heap_objects(
+                                    GrowableArray<MemRegion> * closed_archive) {
+  assert(is_heap_object_archiving_allowed(), "Cannot dump java heap objects");
+
+  Thread* THREAD = Thread::current();
+  G1CollectedHeap::heap()->begin_archive_alloc_range();
+
+  // Archive interned string objects
+  StringTable::write_to_archive(closed_archive);
+
+  G1CollectedHeap::heap()->end_archive_alloc_range(closed_archive,
+                                                   os::vm_allocation_granularity());
+}
+
 void MetaspaceShared::dump_open_archive_heap_objects(
                                     GrowableArray<MemRegion> * open_archive) {
   assert(UseG1GC, "Only support G1 GC");
@@ -1718,21 +1807,33 @@
   Thread* THREAD = Thread::current();
   G1CollectedHeap::heap()->begin_archive_alloc_range(true /* open */);
 
-  MetaspaceShared::archive_resolved_constants(THREAD);
+  java_lang_Class::archive_basic_type_mirrors(THREAD);
+
+  MetaspaceShared::archive_klass_objects(THREAD);
 
   G1CollectedHeap::heap()->end_archive_alloc_range(open_archive,
                                                    os::vm_allocation_granularity());
 }
 
 MetaspaceShared::ArchivedObjectCache* MetaspaceShared::_archive_object_cache = NULL;
+oop MetaspaceShared::find_archived_heap_object(oop obj) {
+  assert(DumpSharedSpaces, "dump-time only");
+  ArchivedObjectCache* cache = MetaspaceShared::archive_object_cache();
+  oop* p = cache->get(obj);
+  if (p != NULL) {
+    return *p;
+  } else {
+    return NULL;
+  }
+}
+
 oop MetaspaceShared::archive_heap_object(oop obj, Thread* THREAD) {
   assert(DumpSharedSpaces, "dump-time only");
 
-  ArchivedObjectCache* cache = MetaspaceShared::archive_object_cache();
-  oop* p = cache->get(obj);
-  if (p != NULL) {
+  oop ao = find_archived_heap_object(obj);
+  if (ao != NULL) {
     // already archived
-    return *p;
+    return ao;
   }
 
   int len = obj->size();
@@ -1745,15 +1846,23 @@
   if (archived_oop != NULL) {
     Copy::aligned_disjoint_words((HeapWord*)obj, (HeapWord*)archived_oop, len);
     relocate_klass_ptr(archived_oop);
+    ArchivedObjectCache* cache = MetaspaceShared::archive_object_cache();
     cache->put(obj, archived_oop);
   }
+  log_debug(cds)("Archived heap object " PTR_FORMAT " ==> " PTR_FORMAT,
+                 p2i(obj), p2i(archived_oop));
   return archived_oop;
 }
 
-void MetaspaceShared::archive_resolved_constants(Thread* THREAD) {
+void MetaspaceShared::archive_klass_objects(Thread* THREAD) {
   int i;
   for (i = 0; i < _global_klass_objects->length(); i++) {
     Klass* k = _global_klass_objects->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);
@@ -1802,6 +1911,19 @@
     FileMapInfo::assert_mark(tag == old_tag);
   }
 
+  void do_oop(oop *p) {
+    narrowOop o = (narrowOop)nextPtr();
+    if (o == 0 || !MetaspaceShared::open_archive_heap_region_mapped()) {
+      p = NULL;
+    } else {
+      assert(MetaspaceShared::is_heap_object_archiving_allowed(),
+             "Archived heap object is not allowed");
+      assert(MetaspaceShared::open_archive_heap_region_mapped(),
+             "Open archive heap region is not mapped");
+      RootAccess<IN_ARCHIVE_ROOT>::oop_store(p, oopDesc::decode_heap_oop_not_null(o));
+    }
+  }
+
   void do_region(u_char* start, size_t size) {
     assert((intptr_t)start % sizeof(intptr_t) == 0, "bad alignment");
     assert(size % sizeof(intptr_t) == 0, "bad size");
--- a/src/hotspot/share/memory/metaspaceShared.hpp	Fri Mar 02 10:42:32 2018 -0800
+++ b/src/hotspot/share/memory/metaspaceShared.hpp	Fri Mar 02 17:25:55 2018 -0500
@@ -113,8 +113,9 @@
   static ArchivedObjectCache* archive_object_cache() {
     return _archive_object_cache;
   }
+  static oop find_archived_heap_object(oop obj);
   static oop archive_heap_object(oop obj, Thread* THREAD);
-  static void archive_resolved_constants(Thread* THREAD);
+  static void archive_klass_objects(Thread* THREAD);
 #endif
   static bool is_heap_object_archiving_allowed() {
     CDS_JAVA_HEAP_ONLY(return (UseG1GC && UseCompressedOops && UseCompressedClassPointers);)
@@ -128,6 +129,8 @@
   }
   static void fixup_mapped_heap_regions() NOT_CDS_JAVA_HEAP_RETURN;
 
+  static void dump_closed_archive_heap_objects(GrowableArray<MemRegion> * closed_archive) NOT_CDS_JAVA_HEAP_RETURN;
+
   static void dump_open_archive_heap_objects(GrowableArray<MemRegion> * open_archive) NOT_CDS_JAVA_HEAP_RETURN;
   static void set_open_archive_heap_region_mapped() {
     CDS_JAVA_HEAP_ONLY(_open_archive_heap_region_mapped = true);
@@ -199,7 +202,8 @@
   static void zero_cpp_vtable_clones_for_writing();
   static void patch_cpp_vtable_pointers();
   static bool is_valid_shared_method(const Method* m) NOT_CDS_RETURN_(false);
-  static void serialize(SerializeClosure* sc);
+  static void serialize(SerializeClosure* sc) NOT_CDS_RETURN;
+  static void serialize_well_known_classes(SerializeClosure* soc) NOT_CDS_RETURN;
 
   static MetaspaceSharedStats* stats() {
     return &_stats;
@@ -248,5 +252,7 @@
     return _cds_i2i_entry_code_buffers_size;
   }
   static void relocate_klass_ptr(oop o);
+
+  static Klass* get_relocated_klass(Klass *k);
 };
 #endif // SHARE_VM_MEMORY_METASPACESHARED_HPP
--- a/src/hotspot/share/memory/universe.cpp	Fri Mar 02 10:42:32 2018 -0800
+++ b/src/hotspot/share/memory/universe.cpp	Fri Mar 02 17:25:55 2018 -0500
@@ -247,7 +247,7 @@
   _do_stack_walk_cache->metaspace_pointers_do(it);
 }
 
-// Serialize metadata in and out of CDS archive, not oops.
+// Serialize metadata and pointers to primitive type mirrors in and out of CDS archive
 void Universe::serialize(SerializeClosure* f, bool do_all) {
 
   f->do_ptr((void**)&_boolArrayKlassObj);
@@ -271,6 +271,20 @@
     }
   }
 
+#if INCLUDE_CDS_JAVA_HEAP
+  // The mirrors are NULL if MetaspaceShared::is_heap_object_archiving_allowed
+  // is false.
+  f->do_oop(&_int_mirror);
+  f->do_oop(&_float_mirror);
+  f->do_oop(&_double_mirror);
+  f->do_oop(&_byte_mirror);
+  f->do_oop(&_bool_mirror);
+  f->do_oop(&_char_mirror);
+  f->do_oop(&_long_mirror);
+  f->do_oop(&_short_mirror);
+  f->do_oop(&_void_mirror);
+#endif
+
   f->do_ptr((void**)&_the_array_interfaces_array);
   f->do_ptr((void**)&_the_empty_int_array);
   f->do_ptr((void**)&_the_empty_short_array);
@@ -453,25 +467,38 @@
 }
 
 void Universe::initialize_basic_type_mirrors(TRAPS) {
-    assert(_int_mirror==NULL, "basic type mirrors already initialized");
-    _int_mirror     =
-      java_lang_Class::create_basic_type_mirror("int",    T_INT, CHECK);
-    _float_mirror   =
-      java_lang_Class::create_basic_type_mirror("float",  T_FLOAT,   CHECK);
-    _double_mirror  =
-      java_lang_Class::create_basic_type_mirror("double", T_DOUBLE,  CHECK);
-    _byte_mirror    =
-      java_lang_Class::create_basic_type_mirror("byte",   T_BYTE, CHECK);
-    _bool_mirror    =
-      java_lang_Class::create_basic_type_mirror("boolean",T_BOOLEAN, CHECK);
-    _char_mirror    =
-      java_lang_Class::create_basic_type_mirror("char",   T_CHAR, CHECK);
-    _long_mirror    =
-      java_lang_Class::create_basic_type_mirror("long",   T_LONG, CHECK);
-    _short_mirror   =
-      java_lang_Class::create_basic_type_mirror("short",  T_SHORT,   CHECK);
-    _void_mirror    =
-      java_lang_Class::create_basic_type_mirror("void",   T_VOID, CHECK);
+#if INCLUDE_CDS_JAVA_HEAP
+    if (UseSharedSpaces &&
+        MetaspaceShared::open_archive_heap_region_mapped() &&
+        _int_mirror != NULL) {
+      assert(MetaspaceShared::is_heap_object_archiving_allowed(), "Sanity");
+      assert(_float_mirror != NULL && _double_mirror != NULL &&
+             _byte_mirror  != NULL && _byte_mirror   != NULL &&
+             _bool_mirror  != NULL && _char_mirror   != NULL &&
+             _long_mirror  != NULL && _short_mirror  != NULL &&
+             _void_mirror  != NULL, "Sanity");
+    } else
+#endif
+    {
+      _int_mirror     =
+        java_lang_Class::create_basic_type_mirror("int",    T_INT, CHECK);
+      _float_mirror   =
+        java_lang_Class::create_basic_type_mirror("float",  T_FLOAT,   CHECK);
+      _double_mirror  =
+        java_lang_Class::create_basic_type_mirror("double", T_DOUBLE,  CHECK);
+      _byte_mirror    =
+        java_lang_Class::create_basic_type_mirror("byte",   T_BYTE, CHECK);
+      _bool_mirror    =
+        java_lang_Class::create_basic_type_mirror("boolean",T_BOOLEAN, CHECK);
+      _char_mirror    =
+        java_lang_Class::create_basic_type_mirror("char",   T_CHAR, CHECK);
+      _long_mirror    =
+        java_lang_Class::create_basic_type_mirror("long",   T_LONG, CHECK);
+      _short_mirror   =
+        java_lang_Class::create_basic_type_mirror("short",  T_SHORT,   CHECK);
+      _void_mirror    =
+        java_lang_Class::create_basic_type_mirror("void",   T_VOID, CHECK);
+    }
 
     _mirrors[T_INT]     = _int_mirror;
     _mirrors[T_FLOAT]   = _float_mirror;
--- a/src/hotspot/share/memory/universe.hpp	Fri Mar 02 10:42:32 2018 -0800
+++ b/src/hotspot/share/memory/universe.hpp	Fri Mar 02 17:25:55 2018 -0500
@@ -294,6 +294,16 @@
   static oop short_mirror()                 { return check_mirror(_short_mirror); }
   static oop void_mirror()                  { return check_mirror(_void_mirror); }
 
+  static void set_int_mirror(oop m)         { _int_mirror = m;    }
+  static void set_float_mirror(oop m)       { _float_mirror = m;  }
+  static void set_double_mirror(oop m)      { _double_mirror = m; }
+  static void set_byte_mirror(oop m)        { _byte_mirror = m;   }
+  static void set_bool_mirror(oop m)        { _bool_mirror = m;   }
+  static void set_char_mirror(oop m)        { _char_mirror = m;   }
+  static void set_long_mirror(oop m)        { _long_mirror = m;   }
+  static void set_short_mirror(oop m)       { _short_mirror = m;  }
+  static void set_void_mirror(oop m)        { _void_mirror = m;   }
+
   // table of same
   static oop _mirrors[T_VOID+1];
 
--- a/src/hotspot/share/oops/klass.cpp	Fri Mar 02 10:42:32 2018 -0800
+++ b/src/hotspot/share/oops/klass.cpp	Fri Mar 02 17:25:55 2018 -0500
@@ -183,7 +183,8 @@
 Klass::Klass() : _prototype_header(markOopDesc::prototype()),
                  _shared_class_path_index(-1),
                  _java_mirror(NULL) {
-
+  CDS_ONLY(_shared_class_flags = 0;)
+  CDS_JAVA_HEAP_ONLY(_archived_mirror = 0;)
   _primary_supers[0] = this;
   set_super_check_offset(in_bytes(primary_supers_offset()));
 }
@@ -519,29 +520,71 @@
     loader_data->add_class(this);
   }
 
-  // Recreate the class mirror.
+  Handle loader(THREAD, loader_data->class_loader());
+  ModuleEntry* module_entry = NULL;
+  Klass* k = this;
+  if (k->is_objArray_klass()) {
+    k = ObjArrayKlass::cast(k)->bottom_klass();
+  }
+  // Obtain klass' module.
+  if (k->is_instance_klass()) {
+    InstanceKlass* ik = (InstanceKlass*) k;
+    module_entry = ik->module();
+  } else {
+    module_entry = ModuleEntryTable::javabase_moduleEntry();
+  }
+  // Obtain java.lang.Module, if available
+  Handle module_handle(THREAD, ((module_entry != NULL) ? module_entry->module() : (oop)NULL));
+
+  if (this->has_raw_archived_mirror()) {
+    log_debug(cds, mirror)("%s has raw archived mirror", external_name());
+    if (MetaspaceShared::open_archive_heap_region_mapped()) {
+      oop m = archived_java_mirror();
+      log_debug(cds, mirror)("Archived mirror is: " PTR_FORMAT, p2i(m));
+      if (m != NULL) {
+        // mirror is archived, restore
+        assert(oopDesc::is_archive_object(m), "must be archived mirror object");
+        Handle m_h(THREAD, m);
+        java_lang_Class::restore_archived_mirror(this, m_h, loader, module_handle, protection_domain, CHECK);
+        return;
+      }
+    }
+
+    // No archived mirror data
+    _java_mirror = NULL;
+    this->clear_has_raw_archived_mirror();
+  }
+
   // Only recreate it if not present.  A previous attempt to restore may have
   // gotten an OOM later but keep the mirror if it was created.
   if (java_mirror() == NULL) {
-    Handle loader(THREAD, loader_data->class_loader());
-    ModuleEntry* module_entry = NULL;
-    Klass* k = this;
-    if (k->is_objArray_klass()) {
-      k = ObjArrayKlass::cast(k)->bottom_klass();
-    }
-    // Obtain klass' module.
-    if (k->is_instance_klass()) {
-      InstanceKlass* ik = (InstanceKlass*) k;
-      module_entry = ik->module();
-    } else {
-      module_entry = ModuleEntryTable::javabase_moduleEntry();
-    }
-    // Obtain java.lang.Module, if available
-    Handle module_handle(THREAD, ((module_entry != NULL) ? module_entry->module() : (oop)NULL));
+    log_trace(cds, mirror)("Recreate mirror for %s", external_name());
     java_lang_Class::create_mirror(this, loader, module_handle, protection_domain, CHECK);
   }
 }
 
+#if INCLUDE_CDS_JAVA_HEAP
+// Used at CDS dump time to access the archived mirror. No GC barrier.
+oop Klass::archived_java_mirror_raw() {
+  assert(DumpSharedSpaces, "called only during runtime");
+  assert(has_raw_archived_mirror(), "must have raw archived mirror");
+  return oopDesc::decode_heap_oop(_archived_mirror);
+}
+
+// Used at CDS runtime to get the archived mirror from shared class. Uses GC barrier.
+oop Klass::archived_java_mirror() {
+  assert(UseSharedSpaces, "UseSharedSpaces expected.");
+  assert(has_raw_archived_mirror(), "must have raw archived mirror");
+  return RootAccess<IN_ARCHIVE_ROOT>::oop_load(&_archived_mirror);
+}
+
+// No GC barrier
+void Klass::set_archived_java_mirror_raw(oop m) {
+  assert(DumpSharedSpaces, "called only during runtime");
+  _archived_mirror = oopDesc::encode_heap_oop(m);
+}
+#endif // INCLUDE_CDS_JAVA_HEAP
+
 Klass* Klass::array_klass_or_null(int rank) {
   EXCEPTION_MARK;
   // No exception can be thrown by array_klass_impl when called with or_null == true.
--- a/src/hotspot/share/oops/klass.hpp	Fri Mar 02 10:42:32 2018 -0800
+++ b/src/hotspot/share/oops/klass.hpp	Fri Mar 02 17:25:55 2018 -0500
@@ -156,6 +156,18 @@
   // -1.
   jshort _shared_class_path_index;
 
+#if INCLUDE_CDS
+  // Flags of the current shared class.
+  u2     _shared_class_flags;
+  enum {
+    _has_raw_archived_mirror = 1,
+    _has_signer_and_not_archived = 1 << 2
+  };
+#endif
+  // The _archived_mirror is set at CDS dump time pointing to the cached mirror
+  // in the open archive heap region when archiving java object is supported.
+  CDS_JAVA_HEAP_ONLY(narrowOop _archived_mirror);
+
   friend class SharedClassUtil;
 protected:
 
@@ -229,11 +241,17 @@
   oop java_mirror() const;
   void set_java_mirror(Handle m);
 
+  oop archived_java_mirror_raw() NOT_CDS_JAVA_HEAP_RETURN_(NULL); // no GC barrier
+  oop archived_java_mirror() NOT_CDS_JAVA_HEAP_RETURN_(NULL);     // accessor with GC barrier
+  void set_archived_java_mirror_raw(oop m) NOT_CDS_JAVA_HEAP_RETURN; // no GC barrier
+
   // Temporary mirror switch used by RedefineClasses
   // Both mirrors are on the ClassLoaderData::_handles list already so no
   // barriers are needed.
   void set_java_mirror_handle(OopHandle mirror) { _java_mirror = mirror; }
-  OopHandle java_mirror_handle() const          { return _java_mirror; }
+  OopHandle java_mirror_handle() const          {
+    return _java_mirror;
+  }
 
   // modifier flags
   jint modifier_flags() const          { return _modifier_flags; }
@@ -267,6 +285,26 @@
     _shared_class_path_index = index;
   };
 
+  void set_has_raw_archived_mirror() {
+    CDS_ONLY(_shared_class_flags |= _has_raw_archived_mirror;)
+  }
+  void clear_has_raw_archived_mirror() {
+    CDS_ONLY(_shared_class_flags &= ~_has_raw_archived_mirror;)
+  }
+  bool has_raw_archived_mirror() const {
+    CDS_ONLY(return (_shared_class_flags & _has_raw_archived_mirror) != 0;)
+    NOT_CDS(return false;)
+  }
+#if INCLUDE_CDS
+  void set_has_signer_and_not_archived() {
+    _shared_class_flags |= _has_signer_and_not_archived;
+  }
+  bool has_signer_and_not_archived() const {
+    assert(DumpSharedSpaces, "dump time only");
+    return (_shared_class_flags & _has_signer_and_not_archived) != 0;
+  }
+#endif // INCLUDE_CDS
+
   // Obtain the module or package for this class
   virtual ModuleEntry* module() const = 0;
   virtual PackageEntry* package() const = 0;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/appcds/cacheObject/CheckCachedMirrorApp.java	Fri Mar 02 17:25:55 2018 -0500
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+import java.io.File;
+import java.net.URL;
+import java.net.URLClassLoader;
+import sun.hotspot.WhiteBox;
+
+//
+// Test class mirror objects are cached when open archive heap objects are mapped:
+//  - Well-known shared library classes:
+//      java.lang.Object
+//      java.lang.String
+//  - Shared application class loaded by the system class loader
+//  - Shared application class loaded user defined class loader
+//
+public class CheckCachedMirrorApp {
+    static WhiteBox wb;
+    public static void main(String args[]) throws Exception {
+        String path = args[0];
+        URL url = new File(path).toURI().toURL();
+        URL[] urls = new URL[] {url};
+
+        URLClassLoader loader = new URLClassLoader(urls);
+        Class hello = loader.loadClass("Hello");
+        System.out.println("Loaded " + hello + " from " + url + " using loader " + loader);
+
+        wb = WhiteBox.getWhiteBox();
+
+        if (!wb.areOpenArchiveHeapObjectsMapped()) {
+            System.out.println("Archived open_archive_heap objects are not mapped.");
+            System.out.println("This may happen during normal operation. Test Skipped.");
+            return;
+        }
+
+        // Well-known shared library classes
+        Class object_class = Object.class;
+        checkMirror(object_class, true);
+        Class string_class = String.class;
+        checkMirror(string_class, true);
+
+        // Shared app class
+        Class app_class = CheckCachedMirrorApp.class;
+        checkMirror(app_class, true);
+
+        // Hello is shared class and loaded by the 'loader' defined in current app.
+        // It should not have cached resolved_references.
+        Class class_with_user_defined_loader = hello;
+        checkMirror(class_with_user_defined_loader, false);
+    }
+
+    static void checkMirror(Class c, boolean mirrorShouldBeArchived) {
+        System.out.print("Check cached mirror for " + c);
+        if (wb.isSharedClass(c)) {
+            // Check if the Class object is cached
+            if (mirrorShouldBeArchived && wb.isShared(c)) {
+                System.out.println(c + " mirror is cached. Expected.");
+            } else if (!mirrorShouldBeArchived && !wb.isShared(c)) {
+                System.out.println(c + " mirror is not cached. Expected.");
+            } else if (mirrorShouldBeArchived && !wb.isShared(c)) {
+                throw new RuntimeException(
+                    "FAILED. " + c + " mirror is not cached.");
+            } else {
+                throw new RuntimeException(
+                    "FAILED. " + c + " mirror should not be cached.");
+            }
+        } else {
+          System.out.println("Class " + c + "is not shared, skipping the check for mirror");
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/appcds/cacheObject/CheckCachedMirrorTest.java	Fri Mar 02 17:25:55 2018 -0500
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+/*
+ * @test
+ * @summary Test archived mirror
+ * @requires vm.cds.archived.java.heap
+ * @requires vm.cds.custom.loaders
+ * @library /test/lib /test/hotspot/jtreg/runtime/appcds
+ * @modules java.base/jdk.internal.misc
+ * @modules java.management
+ *          jdk.jartool/sun.tools.jar
+ * @build sun.hotspot.WhiteBox
+ * @compile CheckCachedMirrorApp.java
+ * @compile ../test-classes/Hello.java
+ * @run driver ClassFileInstaller -jar app.jar CheckCachedMirrorApp
+ * @run driver ClassFileInstaller -jar hello.jar Hello
+ * @run driver ClassFileInstaller -jar WhiteBox.jar sun.hotspot.WhiteBox
+ * @run main CheckCachedMirrorTest
+ */
+
+import jdk.test.lib.process.OutputAnalyzer;
+import sun.hotspot.WhiteBox;
+
+public class CheckCachedMirrorTest {
+    public static void main(String[] args) throws Exception {
+        String wbJar = ClassFileInstaller.getJarPath("WhiteBox.jar");
+        String use_whitebox_jar = "-Xbootclasspath/a:" + wbJar;
+        String appJar = ClassFileInstaller.getJarPath("app.jar");
+        String helloJarPath = ClassFileInstaller.getJarPath("hello.jar");
+
+        String classlist[] = new String[] {
+            "CheckCachedMirrorApp",            // built-in app loader
+            "java/lang/Object id: 1",          // boot loader
+            "Hello id: 2 super: 1 source: " + helloJarPath // custom loader
+        };
+
+        TestCommon.testDump(appJar, classlist, use_whitebox_jar);
+        OutputAnalyzer output = TestCommon.exec(appJar, use_whitebox_jar,
+                                                "-XX:+UnlockDiagnosticVMOptions",
+                                                "-XX:+WhiteBoxAPI",
+                                                "-Xlog:cds=debug",
+                                                "CheckCachedMirrorApp",
+                                                helloJarPath);
+        TestCommon.checkExec(output);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/appcds/cacheObject/MirrorWithReferenceFieldsApp.java	Fri Mar 02 17:25:55 2018 -0500
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+import java.io.File;
+import java.net.URL;
+import sun.hotspot.WhiteBox;
+
+//
+// - Test static final String field with initial value in cached mirror should be also archived.
+// - GC should not crash when reference fields in cached mirror are updated at runtime
+//     - Reference fields are updated to point to runtime created objects
+//     - Reference fields are nullified
+//
+public class MirrorWithReferenceFieldsApp {
+
+    // Static String field with initial value
+    static final String archived_field = "abc";
+
+    // Static object field
+    static Object non_archived_field_1;
+
+    // Instance field
+    Integer non_archived_field_2;
+
+    public MirrorWithReferenceFieldsApp() {
+        non_archived_field_1 = new Object();
+        non_archived_field_2 = new Integer(1);
+    }
+
+    public static void main(String args[]) throws Exception {
+        WhiteBox wb = WhiteBox.getWhiteBox();
+
+        if (!wb.areOpenArchiveHeapObjectsMapped()) {
+            System.out.println("Archived open_archive_heap objects are not mapped.");
+            System.out.println("This may happen during normal operation. Test Skipped.");
+            return;
+        }
+
+        MirrorWithReferenceFieldsApp m = new MirrorWithReferenceFieldsApp();
+        m.test(wb);
+    }
+
+    public void test(WhiteBox wb) {
+        Class c = MirrorWithReferenceFieldsApp.class;
+        if (wb.isSharedClass(c)) {
+            // Check if the Class object is cached
+            if (wb.isShared(c)) {
+                System.out.println(c + " mirror is cached. Expected.");
+            } else {
+                throw new RuntimeException(
+                    "FAILED. " + c + " mirror should be cached.");
+            }
+
+            // Check fields
+
+            if (wb.isShared(archived_field)) {
+                System.out.println("archived_field is archived as excepted");
+            } else {
+                throw new RuntimeException(
+                    "FAILED. archived_field is not archived.");
+            }
+
+            // GC should not crash
+            System.gc();
+            System.gc();
+            System.gc();
+
+            non_archived_field_1 = null;
+            non_archived_field_2 = null;
+
+            System.gc();
+            System.gc();
+            System.gc();
+
+            System.out.println("Done.");
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/appcds/cacheObject/MirrorWithReferenceFieldsTest.java	Fri Mar 02 17:25:55 2018 -0500
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+/*
+ * @test
+ * @summary Test archived mirror with reference fields
+ * @requires vm.cds.archived.java.heap
+ * @library /test/lib /test/hotspot/jtreg/runtime/appcds
+ * @modules java.base/jdk.internal.misc
+ * @modules java.management
+ *          jdk.jartool/sun.tools.jar
+ * @build sun.hotspot.WhiteBox
+ * @compile MirrorWithReferenceFieldsApp.java
+ * @run driver ClassFileInstaller -jar app.jar MirrorWithReferenceFieldsApp
+ * @run driver ClassFileInstaller -jar WhiteBox.jar sun.hotspot.WhiteBox
+ * @run main MirrorWithReferenceFieldsTest
+ */
+
+import jdk.test.lib.process.OutputAnalyzer;
+import sun.hotspot.WhiteBox;
+
+public class MirrorWithReferenceFieldsTest {
+    public static void main(String[] args) throws Exception {
+        String wbJar = ClassFileInstaller.getJarPath("WhiteBox.jar");
+        String use_whitebox_jar = "-Xbootclasspath/a:" + wbJar;
+        String appJar = ClassFileInstaller.getJarPath("app.jar");
+
+        String classlist[] = new String[] {
+            "MirrorWithReferenceFieldsApp",
+        };
+
+        TestCommon.testDump(appJar, classlist, use_whitebox_jar);
+        OutputAnalyzer output = TestCommon.exec(appJar, use_whitebox_jar,
+                                                "-XX:+UnlockDiagnosticVMOptions",
+                                                "-XX:+WhiteBoxAPI",
+                                                "-XX:+VerifyAfterGC",
+                                                "MirrorWithReferenceFieldsApp");
+        try {
+            TestCommon.checkExec(output, "Done");
+        } catch (Exception e) {
+            output.shouldContain("Archived open_archive_heap objects are not mapped");
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/appcds/cacheObject/PrimitiveTypesApp.java	Fri Mar 02 17:25:55 2018 -0500
@@ -0,0 +1,205 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+import java.lang.reflect.Field;
+import sun.hotspot.WhiteBox;
+
+//
+// Test primitive type class mirror objects are cached when open archive heap
+// objects are mapped.
+//
+public class PrimitiveTypesApp {
+    public static void main(String[] args) {
+        WhiteBox wb = WhiteBox.getWhiteBox();
+        if (!wb.areOpenArchiveHeapObjectsMapped()) {
+            System.out.println("Archived open_archive_heap objects are not mapped.");
+            System.out.println("This may happen during normal operation. Test Skipped.");
+            return;
+        }
+
+        FieldsTest ft = new FieldsTest();
+        ft.testBoolean(wb);
+        ft.testByte(wb);
+        ft.testChar(wb);
+        ft.testInt(wb);
+        ft.testShort(wb);
+        ft.testLong(wb);
+        ft.testFloat(wb);
+        ft.testDouble(wb);
+    }
+}
+
+class FieldsTest {
+    public boolean f_boolean;
+    public byte f_byte;
+    public char f_char;
+    public int f_int;
+    public short f_short;
+    public long f_long;
+    public float f_float;
+    public double f_double;
+
+    FieldsTest() {
+        f_byte = 1;
+        f_boolean = false;
+        f_char = 'a';
+        f_int = 1;
+        f_short = 100;
+        f_long = 2018L;
+        f_float = 1.0f;
+        f_double = 2.5;
+    }
+
+    void testBoolean(WhiteBox wb) {
+        try {
+            Field f = this.getClass().getDeclaredField("f_boolean");
+            f.setBoolean(this, true);
+            if (!f_boolean) {
+                throw new RuntimeException("FAILED. Field f_boolean has unexpected value: " + f_boolean);
+            }
+            checkPrimitiveType(wb, f, Boolean.TYPE);
+        } catch (NoSuchFieldException nsfe) {
+            throw new RuntimeException(nsfe);
+        } catch (IllegalAccessException iae) {
+            throw new RuntimeException(iae);
+        }
+    }
+
+    void testByte(WhiteBox wb) {
+        try {
+            Field f = this.getClass().getDeclaredField("f_byte");
+            f.setByte(this, (byte)9);
+            if (f_byte != (byte)9) {
+                throw new RuntimeException("FAILED. Field f_byte has unexpected value: " + f_byte);
+            }
+            checkPrimitiveType(wb, f, Byte.TYPE);
+        } catch (NoSuchFieldException nsfe) {
+            throw new RuntimeException(nsfe);
+        } catch (IllegalAccessException iae) {
+            throw new RuntimeException(iae);
+        }
+    }
+
+    void testChar(WhiteBox wb) {
+        try {
+            Field f = this.getClass().getDeclaredField("f_char");
+            f.setChar(this, 'b');
+            if (f_char != 'b') {
+                throw new RuntimeException("FAILED. Field f_char has unexpected value: " + f_char);
+            }
+            checkPrimitiveType(wb, f, Character.TYPE);
+        } catch (NoSuchFieldException nsfe) {
+            throw new RuntimeException(nsfe);
+        } catch (IllegalAccessException iae) {
+            throw new RuntimeException(iae);
+        }
+    }
+
+    void testInt(WhiteBox wb) {
+        try {
+            Field f = this.getClass().getDeclaredField("f_int");
+            f.setInt(this, 9999);
+            if (f_int != 9999) {
+                throw new RuntimeException("FAILED. Field f_int has unexpected value: " + f_int);
+            }
+            checkPrimitiveType(wb, f, Integer.TYPE);
+        } catch (NoSuchFieldException nsfe) {
+            throw new RuntimeException(nsfe);
+        } catch (IllegalAccessException iae) {
+            throw new RuntimeException(iae);
+        }
+    }
+
+    void testShort(WhiteBox wb) {
+        try {
+            Field f = this.getClass().getDeclaredField("f_short");
+            f.setShort(this, (short)99);
+            if (f_short != 99) {
+                throw new RuntimeException("FAILED. Field f_short has unexpected value: " + f_short);
+            }
+            checkPrimitiveType(wb, f, Short.TYPE);
+        } catch (NoSuchFieldException nsfe) {
+            throw new RuntimeException(nsfe);
+        } catch (IllegalAccessException iae) {
+            throw new RuntimeException(iae);
+        }
+    }
+
+    void testLong(WhiteBox wb) {
+        try {
+            Field f = this.getClass().getDeclaredField("f_long");
+            f.setLong(this, 99L);
+            if (f_long != 99L) {
+                throw new RuntimeException("FAILED. Field f_long has unexpected value: " + f_long);
+            }
+            checkPrimitiveType(wb, f, Long.TYPE);
+        } catch (NoSuchFieldException nsfe) {
+            throw new RuntimeException(nsfe);
+        } catch (IllegalAccessException iae) {
+            throw new RuntimeException(iae);
+        }
+    }
+
+    void testFloat(WhiteBox wb) {
+        try {
+            Field f = this.getClass().getDeclaredField("f_float");
+            f.setFloat(this, 9.9f);
+            if (f_float != 9.9f) {
+                throw new RuntimeException("FAILED. Field f_float has unexpected value: " + f_float);
+            }
+            checkPrimitiveType(wb, f, Float.TYPE);
+        } catch (NoSuchFieldException nsfe) {
+            throw new RuntimeException(nsfe);
+        } catch (IllegalAccessException iae) {
+            throw new RuntimeException(iae);
+        }
+    }
+
+    void testDouble(WhiteBox wb) {
+        try {
+            Field f = this.getClass().getDeclaredField("f_double");
+            f.setDouble(this, 9.9);
+            if (f_double != 9.9) {
+                throw new RuntimeException("FAILED. Field f_double has unexpected value: " + f_double);
+            }
+            checkPrimitiveType(wb, f, Double.TYPE);
+        } catch (NoSuchFieldException nsfe) {
+            throw new RuntimeException(nsfe);
+        } catch (IllegalAccessException iae) {
+            throw new RuntimeException(iae);
+        }
+    }
+
+    void checkPrimitiveType(WhiteBox wb, Field f, Class t) {
+        Class c = f.getType();
+        if (!(c.isPrimitive() && c == t)) {
+            throw new RuntimeException("FAILED. " + c + " is not primitive type " + t);
+        }
+        if (wb.isShared(c)) {
+            System.out.println(c + " is cached, expected");
+        } else {
+            throw new RuntimeException("FAILED. " + c + " is not cached.");
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/appcds/cacheObject/PrimitiveTypesTest.java	Fri Mar 02 17:25:55 2018 -0500
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+/*
+ * @test
+ * @summary Test archived primitive type mirrors
+ * @requires vm.cds.archived.java.heap
+ * @library /test/lib /test/hotspot/jtreg/runtime/appcds
+ * @modules java.base/jdk.internal.misc
+ * @modules java.management
+ *          jdk.jartool/sun.tools.jar
+ * @build sun.hotspot.WhiteBox
+ * @compile PrimitiveTypesApp.java
+ * @run driver ClassFileInstaller -jar app.jar PrimitiveTypesApp FieldsTest
+ * @run driver ClassFileInstaller -jar WhiteBox.jar sun.hotspot.WhiteBox
+ * @run main PrimitiveTypesTest
+ */
+
+import jdk.test.lib.process.OutputAnalyzer;
+import sun.hotspot.WhiteBox;
+
+public class PrimitiveTypesTest {
+    public static void main(String[] args) throws Exception {
+        String wbJar = ClassFileInstaller.getJarPath("WhiteBox.jar");
+        String use_whitebox_jar = "-Xbootclasspath/a:" + wbJar;
+        String appJar = ClassFileInstaller.getJarPath("app.jar");
+
+        String classlist[] = new String[] {
+            "PrimitiveTypesApp",
+            "FieldsTest"
+        };
+
+        TestCommon.testDump(appJar, classlist, use_whitebox_jar);
+        OutputAnalyzer output = TestCommon.exec(appJar, use_whitebox_jar,
+                                                "-XX:+UnlockDiagnosticVMOptions",
+                                                "-XX:+WhiteBoxAPI",
+                                                "-XX:+VerifyAfterGC",
+                                                "PrimitiveTypesApp");
+        TestCommon.checkExec(output);
+    }
+}
--- a/test/hotspot/jtreg/runtime/appcds/cacheObject/RedefineClassApp.java	Fri Mar 02 10:42:32 2018 -0800
+++ b/test/hotspot/jtreg/runtime/appcds/cacheObject/RedefineClassApp.java	Fri Mar 02 17:25:55 2018 -0500
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -89,6 +89,16 @@
         doTest(group, new Foo(), jar);
     }
 
+    static void checkArchivedMirrorObject(Class klass) {
+        if (wb.areOpenArchiveHeapObjectsMapped()) {
+            if (!wb.isShared(klass)) {
+                failed ++;
+                System.out.println("FAILED. " + klass + " mirror object is not archived");
+                return;
+            }
+        }
+    }
+
     static void doTest(String group, Intf object, File jar) throws Throwable {
         numTests ++;
 
@@ -101,6 +111,9 @@
         System.out.println("Test is shared           = " + wb.isSharedClass(klass));
         System.out.println("++++++++++++++++++++++++++");
 
+        // Check archived mirror object before redefine
+        checkArchivedMirrorObject(klass);
+
         // Call get() before redefine. All strings in archived classes are shared.
         String res = object.get();
         System.out.println("get() returns " + res);
@@ -144,6 +157,9 @@
         System.gc();
         System.gc();
 
+        // Check archived mirror object after redefine and GC
+        checkArchivedMirrorObject(klass);
+
         System.out.println("++++++++++++++++++++++++++++++++++++++++++++++++ (done)\n\n");
     }
 }