8186842: Use Java class loaders for creating the CDS archive
authorccheung
Mon, 28 Aug 2017 15:34:04 -0700
changeset 47103 a993ec29ec75
parent 47098 e704f55561c3
child 47104 6bdc0c9c44af
8186842: Use Java class loaders for creating the CDS archive Reviewed-by: coleenp, jiangli, iklam, mseledtsov Contributed-by: calvin.cheung@oracle.com, ioi.lam@oracle.com
hotspot/src/cpu/sparc/vm/templateTable_sparc.cpp
hotspot/src/share/vm/classfile/classLoader.cpp
hotspot/src/share/vm/classfile/classLoader.hpp
hotspot/src/share/vm/classfile/classLoaderExt.hpp
hotspot/src/share/vm/classfile/dictionary.cpp
hotspot/src/share/vm/classfile/dictionary.hpp
hotspot/src/share/vm/classfile/klassFactory.cpp
hotspot/src/share/vm/classfile/stringTable.cpp
hotspot/src/share/vm/classfile/systemDictionary.cpp
hotspot/src/share/vm/classfile/systemDictionary.hpp
hotspot/src/share/vm/interpreter/rewriter.cpp
hotspot/src/share/vm/logging/logTag.hpp
hotspot/src/share/vm/memory/metaspaceClosure.hpp
hotspot/src/share/vm/memory/metaspaceShared.cpp
hotspot/src/share/vm/oops/arrayKlass.cpp
hotspot/src/share/vm/oops/arrayKlass.hpp
hotspot/src/share/vm/oops/constantPool.cpp
hotspot/src/share/vm/oops/cpCache.cpp
hotspot/src/share/vm/oops/cpCache.hpp
hotspot/src/share/vm/oops/instanceKlass.cpp
hotspot/src/share/vm/oops/instanceKlass.hpp
hotspot/src/share/vm/oops/klass.cpp
hotspot/src/share/vm/oops/klass.hpp
hotspot/src/share/vm/oops/method.cpp
hotspot/src/share/vm/runtime/arguments.cpp
hotspot/src/share/vm/runtime/arguments.hpp
hotspot/src/share/vm/runtime/arguments_ext.hpp
hotspot/src/share/vm/runtime/javaCalls.cpp
hotspot/src/share/vm/runtime/thread.cpp
hotspot/src/share/vm/utilities/exceptions.cpp
hotspot/test/runtime/SharedArchiveFile/BootAppendTests.java
hotspot/test/runtime/SharedArchiveFile/NonBootLoaderClasses.java
hotspot/test/runtime/modules/PatchModule/PatchModuleCDS.java
--- a/hotspot/src/cpu/sparc/vm/templateTable_sparc.cpp	Wed Aug 30 19:18:22 2017 -0400
+++ b/hotspot/src/cpu/sparc/vm/templateTable_sparc.cpp	Mon Aug 28 15:34:04 2017 -0700
@@ -2928,7 +2928,7 @@
   __ br(Assembler::zero, false, Assembler::pt, notFinal);
   __ delayed()->and3(Rret, 0xFF, G4_scratch);      // gets number of parameters
 
-  if (RewriteBytecodes && !UseSharedSpaces) {
+  if (RewriteBytecodes && !UseSharedSpaces && !DumpSharedSpaces) {
     patch_bytecode(Bytecodes::_fast_invokevfinal, Rscratch, Rtemp);
   }
 
--- a/hotspot/src/share/vm/classfile/classLoader.cpp	Wed Aug 30 19:18:22 2017 -0400
+++ b/hotspot/src/share/vm/classfile/classLoader.cpp	Mon Aug 28 15:34:04 2017 -0700
@@ -147,6 +147,7 @@
 ClassPathEntry* ClassLoader::_first_append_entry = NULL;
 ClassPathEntry* ClassLoader::_last_append_entry  = NULL;
 int             ClassLoader::_num_entries        = 0;
+int             ClassLoader::_num_boot_entries   = -1;
 #if INCLUDE_CDS
 GrowableArray<char*>* ClassLoader::_boot_modules_array = NULL;
 GrowableArray<char*>* ClassLoader::_platform_modules_array = NULL;
@@ -242,7 +243,7 @@
 
 // Given a fully qualified class name, find its defining package in the class loader's
 // package entry table.
-static PackageEntry* get_package_entry(const char* class_name, ClassLoaderData* loader_data, TRAPS) {
+PackageEntry* ClassLoader::get_package_entry(const char* class_name, ClassLoaderData* loader_data, TRAPS) {
   ResourceMark rm(THREAD);
   const char *pkg_name = ClassLoader::package_from_name(class_name);
   if (pkg_name == NULL) {
@@ -509,7 +510,7 @@
 #endif
 
       } else {
-        PackageEntry* package_entry = get_package_entry(name, ClassLoaderData::the_null_class_loader_data(), CHECK_NULL);
+        PackageEntry* package_entry = ClassLoader::get_package_entry(name, ClassLoaderData::the_null_class_loader_data(), CHECK_NULL);
         if (package_entry != NULL) {
           ResourceMark rm;
           // Get the module name
@@ -540,6 +541,13 @@
   return NULL;
 }
 
+JImageLocationRef ClassLoader::jimage_find_resource(JImageFile* jf,
+                                                    const char* module_name,
+                                                    const char* file_name,
+                                                    jlong &size) {
+  return ((*JImageFindResource)(jf, module_name, get_jimage_version_string(), file_name, &size));
+}
+
 #ifndef PRODUCT
 bool ctw_visitor(JImageFile* jimage,
         const char* module_name, const char* version, const char* package,
@@ -1459,9 +1467,6 @@
   // This would include:
   //   [--patch-module=<module>=<file>(<pathsep><file>)*]; [jimage | exploded module build]
   //
-  // DumpSharedSpaces and search_append_only are mutually exclusive and cannot
-  // be true at the same time.
-  assert(!(DumpSharedSpaces && search_append_only), "DumpSharedSpaces and search_append_only are both true");
 
   // Load Attempt #1: --patch-module
   // Determine the class' defining module.  If it appears in the _patch_mod_entries,
@@ -1507,6 +1512,11 @@
 
     e = _first_append_entry;
     while (e != NULL) {
+      if (DumpSharedSpaces && classpath_index >= _num_boot_entries) {
+        // Do not load any class from the app classpath using the boot loader. Let
+        // the built-in app class laoder load them.
+        break;
+      }
       stream = e->open_stream(file_name, CHECK_NULL);
       if (!context.check(stream, classpath_index)) {
         return NULL;
@@ -1520,9 +1530,6 @@
   }
 
   if (NULL == stream) {
-    if (DumpSharedSpaces) {
-      tty->print_cr("Preload Warning: Cannot find %s", class_name);
-    }
     return NULL;
   }
 
@@ -1548,6 +1555,100 @@
   return context.record_result(name, e, classpath_index, result, THREAD);
 }
 
+#if INCLUDE_CDS
+static char* skip_uri_protocol(char* source) {
+  if (strncmp(source, "file:", 5) == 0) {
+    // file: protocol path could start with file:/ or file:///
+    // locate the char after all the forward slashes
+    int offset = 5;
+    while (*(source + offset) == '/') {
+        offset++;
+    }
+    source += offset;
+  // for non-windows platforms, move back one char as the path begins with a '/'
+#ifndef _WINDOWS
+    source -= 1;
+#endif
+  } else if (strncmp(source, "jrt:/", 5) == 0) {
+    source += 5;
+  }
+  return source;
+}
+
+void ClassLoader::record_shared_class_loader_type(InstanceKlass* ik, const ClassFileStream* stream) {
+  assert(DumpSharedSpaces, "sanity");
+  assert(stream != NULL, "sanity");
+
+  if (ik->is_anonymous()) {
+    // We do not archive anonymous classes.
+    return;
+  }
+
+  if (stream->source() == NULL) {
+    if (ik->class_loader() == NULL) {
+      // JFR classes
+      ik->set_shared_classpath_index(0);
+      ik->set_class_loader_type(ClassLoader::BOOT_LOADER);
+    }
+    return;
+  }
+
+  assert(has_jrt_entry(), "CDS dumping does not support exploded JDK build");
+
+  ModuleEntry* module = ik->module();
+  ClassPathEntry* e = NULL;
+  int classpath_index = 0;
+
+  // Check if the class is from the runtime image
+  if (module != NULL && (module->location() != NULL) &&
+      (module->location()->starts_with("jrt:"))) {
+    e = _jrt_entry;
+    classpath_index = 0;
+  } else {
+    classpath_index = 1;
+    ResourceMark rm;
+    char* canonical_path = NEW_RESOURCE_ARRAY(char, JVM_MAXPATHLEN);
+    for (e = _first_append_entry; e != NULL; e = e->next()) {
+      if (get_canonical_path(e->name(), canonical_path, JVM_MAXPATHLEN)) {
+        char* src = (char*)stream->source();
+        // save the path from the file: protocol or the module name from the jrt: protocol
+        // if no protocol prefix is found, src is the same as stream->source() after the following call
+        src = skip_uri_protocol(src);
+        if (strcmp(canonical_path, os::native_path((char*)src)) == 0) {
+          break;
+        }
+        classpath_index ++;
+      }
+    }
+    if (e == NULL) {
+      assert(ik->shared_classpath_index() < 0,
+        "must be a class from a custom jar which isn't in the class path or boot class path");
+      return;
+    }
+  }
+
+  if (classpath_index < _num_boot_entries) {
+    // ik is either:
+    // 1) a boot class loaded from the runtime image during vm initialization (classpath_index = 0); or
+    // 2) a user's class from -Xbootclasspath/a (classpath_index > 0)
+    // In the second case, the classpath_index, classloader_type will be recorded via
+    // context.record_result() in ClassLoader::load_class(Symbol* name, bool search_append_only, TRAPS).
+    if (classpath_index > 0) {
+      return;
+    }
+  }
+
+  ResourceMark rm;
+  const char* const class_name = ik->name()->as_C_string();
+  const char* const file_name = file_name_for_class_name(class_name,
+                                                         ik->name()->utf8_length());
+  assert(file_name != NULL, "invariant");
+  Thread* THREAD = Thread::current();
+  ClassLoaderExt::Context context(class_name, file_name, CATCH);
+  context.record_result(ik->name(), e, classpath_index, ik, THREAD);
+}
+#endif // INCLUDE_CDS
+
 // Initialize the class loader's access to methods in libzip.  Parse and
 // process the boot classpath into a list ClassPathEntry objects.  Once
 // this list has been created, it must not change order (see class PackageInfo)
@@ -1632,6 +1733,7 @@
 #if INCLUDE_CDS
 void ClassLoader::initialize_shared_path() {
   if (DumpSharedSpaces) {
+    _num_boot_entries = _num_entries;
     ClassLoaderExt::setup_search_paths();
     _shared_paths_misc_info->write_jint(0); // see comments in SharedPathsMiscInfo::check()
   }
--- a/hotspot/src/share/vm/classfile/classLoader.hpp	Wed Aug 30 19:18:22 2017 -0400
+++ b/hotspot/src/share/vm/classfile/classLoader.hpp	Mon Aug 28 15:34:04 2017 -0700
@@ -25,6 +25,7 @@
 #ifndef SHARE_VM_CLASSFILE_CLASSLOADER_HPP
 #define SHARE_VM_CLASSFILE_CLASSLOADER_HPP
 
+#include "classfile/jimage.hpp"
 #include "runtime/orderAccess.hpp"
 #include "runtime/perfData.hpp"
 #include "utilities/exceptions.hpp"
@@ -47,6 +48,7 @@
 
 class JImageFile;
 class ClassFileStream;
+class PackageEntry;
 
 class ClassPathEntry : public CHeapObj<mtClass> {
 private:
@@ -103,7 +105,6 @@
   jlong pos;                    /* position of LOC header (if negative) or data */
 } jzentry;
 
-
 class ClassPathZipEntry: public ClassPathEntry {
  enum {
    _unknown = 0,
@@ -249,6 +250,10 @@
   //       the entries on the _first_append_entry linked list.
   static int _num_entries;
 
+  // number of entries in the boot class path including the
+  // java runtime image
+  static int _num_boot_entries;
+
   // Array of module names associated with the boot class loader
   CDS_ONLY(static GrowableArray<char*>* _boot_modules_array;)
 
@@ -289,6 +294,7 @@
   static bool get_canonical_path(const char* orig, char* out, int len);
   static const char* file_name_for_class_name(const char* class_name,
                                               int class_name_len);
+  static PackageEntry* get_package_entry(const char* class_name, ClassLoaderData* loader_data, TRAPS);
 
  public:
   static jboolean decompress(void *in, u8 inSize, void *out, u8 outSize, char **pmsg);
@@ -436,7 +442,10 @@
   static void initialize_module_loader_map(JImageFile* jimage);
   static s2 classloader_type(Symbol* class_name, ClassPathEntry* e,
                              int classpath_index, TRAPS);
+  static void record_shared_class_loader_type(InstanceKlass* ik, const ClassFileStream* stream);
 #endif
+  static JImageLocationRef jimage_find_resource(JImageFile* jf, const char* module_name,
+                                                const char* file_name, jlong &size);
 
   static void  trace_class_path(const char* msg, const char* name = NULL);
 
--- a/hotspot/src/share/vm/classfile/classLoaderExt.hpp	Wed Aug 30 19:18:22 2017 -0400
+++ b/hotspot/src/share/vm/classfile/classLoaderExt.hpp	Mon Aug 28 15:34:04 2017 -0700
@@ -26,6 +26,7 @@
 #define SHARE_VM_CLASSFILE_CLASSLOADEREXT_HPP
 
 #include "classfile/classLoader.hpp"
+#include "classfile/systemDictionary.hpp"
 #include "oops/instanceKlass.hpp"
 #include "runtime/handles.hpp"
 
@@ -56,8 +57,15 @@
       if (ClassLoader::add_package(_file_name, classpath_index, THREAD)) {
 #if INCLUDE_CDS
         if (DumpSharedSpaces) {
-          s2 classloader_type = ClassLoader::classloader_type(
-                          class_name, e, classpath_index, CHECK_(result));
+          oop loader = result->class_loader();
+          s2 classloader_type = ClassLoader::BOOT_LOADER;
+          if (SystemDictionary::is_system_class_loader(loader)) {
+            classloader_type = ClassLoader::APP_LOADER;
+            ClassLoaderExt::set_has_app_classes();
+          } else if (SystemDictionary::is_platform_class_loader(loader)) {
+            classloader_type = ClassLoader::PLATFORM_LOADER;
+            ClassLoaderExt::set_has_platform_classes();
+          }
           result->set_shared_classpath_index(classpath_index);
           result->set_class_loader_type(classloader_type);
         }
@@ -82,6 +90,13 @@
    return true;
  }
   static Klass* load_one_class(ClassListParser* parser, TRAPS);
+#if INCLUDE_CDS
+  static void set_has_app_classes() {}
+  static void set_has_platform_classes() {}
+  static char* read_manifest(ClassPathEntry* entry, jint *manifest_size, TRAPS) {
+    return NULL;
+  }
+#endif
 };
 
 #endif // SHARE_VM_CLASSFILE_CLASSLOADEREXT_HPP
--- a/hotspot/src/share/vm/classfile/dictionary.cpp	Wed Aug 30 19:18:22 2017 -0400
+++ b/hotspot/src/share/vm/classfile/dictionary.cpp	Mon Aug 28 15:34:04 2017 -0700
@@ -366,11 +366,21 @@
   for (int i = 0; i < table_size(); ++i) {
     DictionaryEntry* p = bucket(i);
     while (p != NULL) {
-      DictionaryEntry* tmp;
-      tmp = p->next();
-      p->set_next(master_list);
-      master_list = p;
-      p = tmp;
+      DictionaryEntry* next = p->next();
+      InstanceKlass*ik = p->instance_klass();
+      // 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).
+      if (ik->signers() != NULL) {
+        ResourceMark rm;
+        tty->print_cr("Preload Warning: Skipping %s from signed JAR",
+                       ik->name()->as_C_string());
+        free_entry(p);
+      } else {
+        p->set_next(master_list);
+        master_list = p;
+      }
+      p = next;
     }
     set_entry(i, NULL);
   }
--- a/hotspot/src/share/vm/classfile/dictionary.hpp	Wed Aug 30 19:18:22 2017 -0400
+++ b/hotspot/src/share/vm/classfile/dictionary.hpp	Mon Aug 28 15:34:04 2017 -0700
@@ -49,21 +49,6 @@
   DictionaryEntry* get_entry(int index, unsigned int hash, Symbol* name);
 
 protected:
-  DictionaryEntry* bucket(int i) const {
-    return (DictionaryEntry*)Hashtable<InstanceKlass*, mtClass>::bucket(i);
-  }
-
-  // The following method is not MT-safe and must be done under lock.
-  DictionaryEntry** bucket_addr(int i) {
-    return (DictionaryEntry**)Hashtable<InstanceKlass*, mtClass>::bucket_addr(i);
-  }
-
-  void add_entry(int index, DictionaryEntry* new_entry) {
-    Hashtable<InstanceKlass*, mtClass>::add_entry(index, (HashtableEntry<InstanceKlass*, mtClass>*)new_entry);
-  }
-
-  void free_entry(DictionaryEntry* entry);
-
   static size_t entry_size();
 public:
   Dictionary(ClassLoaderData* loader_data, int table_size);
@@ -107,6 +92,24 @@
 
   void print_on(outputStream* st) const;
   void verify();
+  DictionaryEntry* bucket(int i) const {
+    return (DictionaryEntry*)Hashtable<InstanceKlass*, mtClass>::bucket(i);
+  }
+
+  // The following method is not MT-safe and must be done under lock.
+  DictionaryEntry** bucket_addr(int i) {
+    return (DictionaryEntry**)Hashtable<InstanceKlass*, mtClass>::bucket_addr(i);
+  }
+
+  void add_entry(int index, DictionaryEntry* new_entry) {
+    Hashtable<InstanceKlass*, mtClass>::add_entry(index, (HashtableEntry<InstanceKlass*, mtClass>*)new_entry);
+  }
+
+  void unlink_entry(DictionaryEntry* entry) {
+    Hashtable<InstanceKlass*, mtClass>::unlink_entry((HashtableEntry<InstanceKlass*, mtClass>*)entry);
+  }
+
+  void free_entry(DictionaryEntry* entry);
 };
 
 // An entry in the class loader data dictionaries, this describes a class as
@@ -254,10 +257,6 @@
 class SymbolPropertyTable : public Hashtable<Symbol*, mtSymbol> {
   friend class VMStructs;
 private:
-  SymbolPropertyEntry* bucket(int i) {
-    return (SymbolPropertyEntry*) Hashtable<Symbol*, mtSymbol>::bucket(i);
-  }
-
   // The following method is not MT-safe and must be done under lock.
   SymbolPropertyEntry** bucket_addr(int i) {
     return (SymbolPropertyEntry**) Hashtable<Symbol*, mtSymbol>::bucket_addr(i);
@@ -311,5 +310,9 @@
   void methods_do(void f(Method*));
 
   void verify();
+
+  SymbolPropertyEntry* bucket(int i) {
+    return (SymbolPropertyEntry*) Hashtable<Symbol*, mtSymbol>::bucket(i);
+  }
 };
 #endif // SHARE_VM_CLASSFILE_DICTIONARY_HPP
--- a/hotspot/src/share/vm/classfile/klassFactory.cpp	Wed Aug 30 19:18:22 2017 -0400
+++ b/hotspot/src/share/vm/classfile/klassFactory.cpp	Mon Aug 28 15:34:04 2017 -0700
@@ -70,11 +70,25 @@
       ClassLoaderData* loader_data =
         ClassLoaderData::class_loader_data(class_loader());
       int path_index = ik->shared_classpath_index();
-      SharedClassPathEntry* ent =
-        (SharedClassPathEntry*)FileMapInfo::shared_classpath(path_index);
+      const char* pathname;
+      if (path_index < 0) {
+        // shared classes loaded by user defined class loader
+        // do not have shared_classpath_index
+        ModuleEntry* mod_entry = ik->module();
+        if (mod_entry != NULL && (mod_entry->location() != NULL)) {
+          ResourceMark rm;
+          pathname = (const char*)(mod_entry->location()->as_C_string());
+        } else {
+          pathname = "";
+        }
+      } else {
+        SharedClassPathEntry* ent =
+          (SharedClassPathEntry*)FileMapInfo::shared_classpath(path_index);
+        pathname = ent == NULL ? NULL : ent->name();
+      }
       ClassFileStream* stream = new ClassFileStream(ptr,
                                                     end_ptr - ptr,
-                                                    ent == NULL ? NULL : ent->name(),
+                                                    pathname,
                                                     ClassFileStream::verify);
       ClassFileParser parser(stream,
                              class_name,
@@ -215,8 +229,10 @@
 
   TRACE_KLASS_CREATION(result, parser, THREAD);
 
-#if INCLUDE_CDS && INCLUDE_JVMTI
+#if INCLUDE_CDS
   if (DumpSharedSpaces) {
+    ClassLoader::record_shared_class_loader_type(result, stream);
+#if INCLUDE_JVMTI
     assert(cached_class_file == NULL, "Sanity");
     // Archive the class stream data into the optional data section
     JvmtiCachedClassFileData *p;
@@ -233,8 +249,9 @@
     p->length = len;
     memcpy(p->data, bytes, len);
     result->set_archived_class_data(p);
+#endif // INCLUDE_JVMTI
   }
-#endif
+#endif // INCLUDE_CDS
 
   return result;
 }
--- a/hotspot/src/share/vm/classfile/stringTable.cpp	Wed Aug 30 19:18:22 2017 -0400
+++ b/hotspot/src/share/vm/classfile/stringTable.cpp	Mon Aug 28 15:34:04 2017 -0700
@@ -729,7 +729,6 @@
   }
 
   G1CollectedHeap::heap()->end_archive_alloc_range(string_space, os::vm_allocation_granularity());
-  assert(string_space->length() <= 2, "sanity");
   return true;
 }
 
--- a/hotspot/src/share/vm/classfile/systemDictionary.cpp	Wed Aug 30 19:18:22 2017 -0400
+++ b/hotspot/src/share/vm/classfile/systemDictionary.cpp	Mon Aug 28 15:34:04 2017 -0700
@@ -66,6 +66,7 @@
 #include "prims/resolvedMethodTable.hpp"
 #include "prims/methodHandles.hpp"
 #include "runtime/arguments.hpp"
+#include "runtime/arguments_ext.hpp"
 #include "runtime/biasedLocking.hpp"
 #include "runtime/fieldType.hpp"
 #include "runtime/handles.inline.hpp"
@@ -869,7 +870,7 @@
             // during compilations.
             MutexLocker mu(Compile_lock, THREAD);
             update_dictionary(d_index, d_hash, p_index, p_hash,
-                              k, class_loader, THREAD);
+              k, class_loader, THREAD);
           }
 
           if (JvmtiExport::should_post_class_load()) {
@@ -1006,7 +1007,6 @@
     // Create a new CLD for anonymous class, that uses the same class loader
     // as the host_klass
     guarantee(host_klass->class_loader() == class_loader(), "should be the same");
-    guarantee(!DumpSharedSpaces, "must not create anonymous classes when dumping");
     loader_data = ClassLoaderData::anonymous_class_loader_data(class_loader(), CHECK_NULL);
   } else {
     loader_data = ClassLoaderData::class_loader_data(class_loader());
@@ -1075,6 +1075,15 @@
                                                      Handle protection_domain,
                                                      ClassFileStream* st,
                                                      TRAPS) {
+#if INCLUDE_CDS
+  ResourceMark rm(THREAD);
+  if (DumpSharedSpaces && !class_loader.is_null() &&
+      !ArgumentsExt::using_AppCDS() && strcmp(class_name->as_C_string(), "Unnamed") != 0) {
+    // If AppCDS is not enabled, don't define the class at dump time (except for the "Unnamed"
+    // class, which is used by MethodHandles).
+    THROW_MSG_NULL(vmSymbols::java_lang_ClassNotFoundException(), class_name->as_C_string());
+  }
+#endif
 
   HandleMark hm(THREAD);
 
@@ -1101,11 +1110,13 @@
  InstanceKlass* k = NULL;
 
 #if INCLUDE_CDS
-  k = SystemDictionaryShared::lookup_from_stream(class_name,
-                                                 class_loader,
-                                                 protection_domain,
-                                                 st,
-                                                 CHECK_NULL);
+  if (!DumpSharedSpaces) {
+    k = SystemDictionaryShared::lookup_from_stream(class_name,
+                                                   class_loader,
+                                                   protection_domain,
+                                                   st,
+                                                   CHECK_NULL);
+  }
 #endif
 
   if (k == NULL) {
@@ -1214,6 +1225,16 @@
          "Cannot use sharing if java.base is patched");
   ResourceMark rm;
   int path_index = ik->shared_classpath_index();
+  ClassLoaderData* loader_data = class_loader_data(class_loader);
+  if (path_index < 0) {
+    // path_index < 0 indicates that the class is intended for a custom loader
+    // and should not be loaded by boot/platform/app loaders
+    if (loader_data->is_builtin_class_loader_data()) {
+      return false;
+    } else {
+      return true;
+    }
+  }
   SharedClassPathEntry* ent =
             (SharedClassPathEntry*)FileMapInfo::shared_classpath(path_index);
   if (!Universe::is_module_initialized()) {
@@ -1227,7 +1248,6 @@
   PackageEntry* pkg_entry = NULL;
   ModuleEntry* mod_entry = NULL;
   const char* pkg_string = NULL;
-  ClassLoaderData* loader_data = class_loader_data(class_loader);
   pkg_name = InstanceKlass::package_from_name(class_name, CHECK_false);
   if (pkg_name != NULL) {
     pkg_string = pkg_name->as_C_string();
@@ -1400,6 +1420,18 @@
   }
   return ik;
 }
+
+void SystemDictionary::clear_invoke_method_table() {
+  SymbolPropertyEntry* spe = NULL;
+  for (int index = 0; index < _invoke_method_table->table_size(); index++) {
+    SymbolPropertyEntry* p = _invoke_method_table->bucket(index);
+    while (p != NULL) {
+      spe = p;
+      p = p->next();
+      _invoke_method_table->free_entry(spe);
+    }
+  }
+}
 #endif // INCLUDE_CDS
 
 InstanceKlass* SystemDictionary::load_instance_class(Symbol* class_name, Handle class_loader, TRAPS) {
@@ -1446,7 +1478,6 @@
         }
       }
     } else {
-      assert(!DumpSharedSpaces, "Archive dumped after module system initialization");
       // After the module system has been initialized, check if the class'
       // package is in a module defined to the boot loader.
       if (pkg_name == NULL || pkg_entry == NULL || pkg_entry->in_unnamed_module()) {
@@ -1965,8 +1996,19 @@
   invoke_method_table()->methods_do(f);
 }
 
+class RemoveClassesClosure : public CLDClosure {
+  public:
+    void do_cld(ClassLoaderData* cld) {
+      if (cld->is_system_class_loader_data() || cld->is_platform_class_loader_data()) {
+        cld->dictionary()->remove_classes_in_error_state();
+      }
+    }
+};
+
 void SystemDictionary::remove_classes_in_error_state() {
   ClassLoaderData::the_null_class_loader_data()->dictionary()->remove_classes_in_error_state();
+  RemoveClassesClosure rcc;
+  ClassLoaderDataGraph::cld_do(&rcc);
 }
 
 // ----------------------------------------------------------------------------
@@ -2907,6 +2949,56 @@
   }
 }
 
+class CombineDictionariesClosure : public CLDClosure {
+  private:
+    Dictionary* _master_dictionary;
+  public:
+    CombineDictionariesClosure(Dictionary* master_dictionary) :
+      _master_dictionary(master_dictionary) {}
+    void do_cld(ClassLoaderData* cld) {
+      ResourceMark rm;
+      if (cld->is_system_class_loader_data() || cld->is_platform_class_loader_data()) {
+        for (int i = 0; i < cld->dictionary()->table_size(); ++i) {
+          Dictionary* curr_dictionary = cld->dictionary();
+          DictionaryEntry* p = curr_dictionary->bucket(i);
+          while (p != NULL) {
+            Symbol* name = p->instance_klass()->name();
+            unsigned int d_hash = _master_dictionary->compute_hash(name);
+            int d_index = _master_dictionary->hash_to_index(d_hash);
+            DictionaryEntry* next = p->next();
+            if (p->literal()->class_loader_data() != cld) {
+              // This is an initiating class loader entry; don't use it
+              log_trace(cds)("Skipping initiating cl entry: %s", name->as_C_string());
+              curr_dictionary->free_entry(p);
+            } else {
+              log_trace(cds)("Moved to boot dictionary: %s", name->as_C_string());
+              curr_dictionary->unlink_entry(p);
+              p->set_pd_set(NULL); // pd_set is runtime only information and will be reconstructed.
+              _master_dictionary->add_entry(d_index, p);
+            }
+            p = next;
+          }
+          *curr_dictionary->bucket_addr(i) = NULL;
+        }
+      }
+    }
+};
+
+// Combining platform and system loader dictionaries into boot loader dictionaries.
+// During run time, we only have one shared dictionary.
+void SystemDictionary::combine_shared_dictionaries() {
+  assert(DumpSharedSpaces, "dump time only");
+  Dictionary* master_dictionary = ClassLoaderData::the_null_class_loader_data()->dictionary();
+  CombineDictionariesClosure cdc(master_dictionary);
+  ClassLoaderDataGraph::cld_do(&cdc);
+
+  // These tables are no longer valid or necessary. Keeping them around will
+  // cause SystemDictionary::verify() to fail. Let's empty them.
+  _placeholders        = new PlaceholderTable(_placeholder_table_size);
+  _loader_constraints  = new LoaderConstraintTable(_loader_constraint_size);
+
+  NOT_PRODUCT(SystemDictionary::verify());
+}
 
 // caller needs ResourceMark
 const char* SystemDictionary::loader_name(const oop loader) {
--- a/hotspot/src/share/vm/classfile/systemDictionary.hpp	Wed Aug 30 19:18:22 2017 -0400
+++ b/hotspot/src/share/vm/classfile/systemDictionary.hpp	Mon Aug 28 15:34:04 2017 -0700
@@ -385,6 +385,7 @@
 public:
   // Sharing support.
   static void reorder_dictionary_for_sharing();
+  static void combine_shared_dictionaries();
   static size_t count_bytes_for_buckets();
   static size_t count_bytes_for_table();
   static void copy_buckets(char* top, char* end);
@@ -643,6 +644,7 @@
                                           TRAPS);
   static bool is_system_class_loader(oop class_loader);
   static bool is_platform_class_loader(oop class_loader);
+  static void clear_invoke_method_table();
 
 protected:
   static InstanceKlass* find_shared_class(Symbol* class_name);
--- a/hotspot/src/share/vm/interpreter/rewriter.cpp	Wed Aug 30 19:18:22 2017 -0400
+++ b/hotspot/src/share/vm/interpreter/rewriter.cpp	Mon Aug 28 15:34:04 2017 -0700
@@ -109,6 +109,11 @@
     MetadataFactory::free_metadata(loader_data, cache);
     _pool->set_cache(NULL);  // so the verifier isn't confused
   }
+
+  DEBUG_ONLY(
+  if (DumpSharedSpaces) {
+    cache->verify_just_initialized();
+  })
 }
 
 
--- a/hotspot/src/share/vm/logging/logTag.hpp	Wed Aug 30 19:18:22 2017 -0400
+++ b/hotspot/src/share/vm/logging/logTag.hpp	Mon Aug 28 15:34:04 2017 -0700
@@ -140,6 +140,7 @@
   LOG_TAG(timer) \
   LOG_TAG(update) \
   LOG_TAG(unload) /* Trace unloading of classes */ \
+  LOG_TAG(unshareable) \
   LOG_TAG(verification) \
   LOG_TAG(verify) \
   LOG_TAG(vmoperation) \
--- a/hotspot/src/share/vm/memory/metaspaceClosure.hpp	Wed Aug 30 19:18:22 2017 -0400
+++ b/hotspot/src/share/vm/memory/metaspaceClosure.hpp	Mon Aug 28 15:34:04 2017 -0700
@@ -275,7 +275,8 @@
       address, bool,
       UniqueMetaspaceClosure::my_hash,   // solaris compiler doesn't like: primitive_hash<address>
       UniqueMetaspaceClosure::my_equals, // solaris compiler doesn't like: primitive_equals<address>
-    16384> _has_been_visited;
+      15889,                             // prime number
+      ResourceObj::C_HEAP> _has_been_visited;
 };
 
 #endif // SHARE_VM_MEMORY_METASPACE_ITERATOR_HPP
--- a/hotspot/src/share/vm/memory/metaspaceShared.cpp	Wed Aug 30 19:18:22 2017 -0400
+++ b/hotspot/src/share/vm/memory/metaspaceShared.cpp	Mon Aug 28 15:34:04 2017 -0700
@@ -374,25 +374,63 @@
 // Global object for holding classes that have been loaded.  Since this
 // is run at a safepoint just before exit, this is the entire set of classes.
 static GrowableArray<Klass*>* _global_klass_objects;
+
+static void collect_array_classes(Klass* k) {
+  _global_klass_objects->append_if_missing(k);
+  if (k->is_array_klass()) {
+    // Add in the array classes too
+    ArrayKlass* ak = ArrayKlass::cast(k);
+    Klass* h = ak->higher_dimension();
+    if (h != NULL) {
+      h->array_klasses_do(collect_array_classes);
+    }
+  }
+}
+
 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_array_klass()) {
+      // Add in the array classes too
+      ArrayKlass* ak = ArrayKlass::cast(k);
+      Klass* h = ak->higher_dimension();
+      if (h != NULL) {
+        h->array_klasses_do(collect_array_classes);
+      }
+    }
   }
 };
 
 static void remove_unshareable_in_classes() {
   for (int i = 0; i < _global_klass_objects->length(); i++) {
     Klass* k = _global_klass_objects->at(i);
-    k->remove_unshareable_info();
+    if (!k->is_objArray_klass()) {
+      // InstanceKlass and TypeArrayKlass will in turn call remove_unshareable_info
+      // on their array classes.
+      assert(k->is_instance_klass() || k->is_typeArray_klass(), "must be");
+      k->remove_unshareable_info();
+    }
+  }
+}
+
+static void remove_java_mirror_in_classes() {
+  for (int i = 0; i < _global_klass_objects->length(); i++) {
+    Klass* k = _global_klass_objects->at(i);
+    if (!k->is_objArray_klass()) {
+      // InstanceKlass and TypeArrayKlass will in turn call remove_unshareable_info
+      // on their array classes.
+      assert(k->is_instance_klass() || k->is_typeArray_klass(), "must be");
+      k->remove_java_mirror();
+    }
   }
 }
 
 static void rewrite_nofast_bytecode(Method* method) {
-  RawBytecodeStream bcs(method);
+  BytecodeStream bcs(method);
   while (!bcs.is_last_bytecode()) {
-    Bytecodes::Code opcode = bcs.raw_next();
+    Bytecodes::Code opcode = bcs.next();
     switch (opcode) {
     case Bytecodes::_getfield:      *bcs.bcp() = Bytecodes::_nofast_getfield;      break;
     case Bytecodes::_putfield:      *bcs.bcp() = Bytecodes::_nofast_putfield;      break;
@@ -446,6 +484,17 @@
   }
 }
 
+NOT_PRODUCT(
+static void assert_not_anonymous_class(InstanceKlass* k) {
+  assert(!(k->is_anonymous()), "cannot archive anonymous classes");
+}
+
+// Anonymous classes are not stored inside any dictionaries. They are created by
+// SystemDictionary::parse_stream() with a non-null host_klass.
+static void assert_no_anonymoys_classes_in_dictionaries() {
+  ClassLoaderDataGraph::dictionary_classes_do(assert_not_anonymous_class);
+})
+
 // Objects of the Metadata types (such as Klass and ConstantPool) have C++ vtables.
 // (In GCC this is the field <Type>::_vptr, i.e., first word in the object.)
 //
@@ -957,8 +1006,8 @@
     }
     memcpy(p, obj, bytes);
     bool isnew = _new_loc_table->put(obj, (address)p);
+    log_trace(cds)("Copy: " PTR_FORMAT " ==> " PTR_FORMAT " %d", p2i(obj), p2i(p), bytes);
     assert(isnew, "must be");
-    log_trace(cds)("Copy: " PTR_FORMAT " ==> " PTR_FORMAT " %d", p2i(obj), p2i(p), bytes);
 
     _alloc_stats->record(ref->msotype(), int(newtop - oldtop), read_only);
     if (ref->msotype() == MetaspaceObj::SymbolType) {
@@ -1151,6 +1200,9 @@
   // 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 ... ");
+  remove_java_mirror_in_classes();
+  tty->print_cr("done. ");
   NOT_PRODUCT(SystemDictionary::verify();)
 
   size_t buckets_bytes = SystemDictionary::count_bytes_for_buckets();
@@ -1218,11 +1270,20 @@
   rewrite_nofast_bytecodes_and_calculate_fingerprints();
   tty->print_cr("done. ");
 
+  // Move classes from platform/system dictionaries into the boot dictionary
+  SystemDictionary::combine_shared_dictionaries();
+
   // Remove all references outside the metadata
   tty->print("Removing unshareable information ... ");
   remove_unshareable_in_classes();
   tty->print_cr("done. ");
 
+  // We don't support archiving anonymous classes. Verify that they are not stored in
+  // the any dictionaries.
+  NOT_PRODUCT(assert_no_anonymoys_classes_in_dictionaries());
+
+  SystemDictionaryShared::finalize_verification_constraints();
+
   ArchiveCompactor::initialize();
   ArchiveCompactor::copy_and_compact();
 
@@ -1312,6 +1373,14 @@
     ArchiveCompactor::alloc_stats()->print_stats(int(_ro_region.used()), int(_rw_region.used()),
                                                  int(_mc_region.used()), int(_md_region.used()));
   }
+
+  if (PrintSystemDictionaryAtExit) {
+    SystemDictionary::print();
+  }
+  // There may be other pending VM operations that operate on the InstanceKlasses,
+  // which will fail because InstanceKlasses::remove_unshareable_info()
+  // has been called. Forget these operations and exit the VM directly.
+  vm_direct_exit(0);
 }
 
 void VM_PopulateDumpSharedSpace::print_region_stats() {
@@ -1438,10 +1507,6 @@
       exit(1);
     }
   }
-
-  // Copy the verification constraints from C_HEAP-alloced GrowableArrays to RO-alloced
-  // Arrays
-  SystemDictionaryShared::finalize_verification_constraints();
 }
 
 void MetaspaceShared::prepare_for_dumping() {
@@ -1509,17 +1574,11 @@
     link_and_cleanup_shared_classes(CATCH);
     tty->print_cr("Rewriting and linking classes: done");
 
+    SystemDictionary::clear_invoke_method_table();
+
     VM_PopulateDumpSharedSpace op;
     VMThread::execute(&op);
   }
-
-  if (PrintSystemDictionaryAtExit) {
-    SystemDictionary::print();
-  }
-
-  // Since various initialization steps have been undone by this process,
-  // it is not reasonable to continue running a java process.
-  exit(0);
 }
 
 
@@ -1529,8 +1588,14 @@
 
     while (parser.parse_one_line()) {
       Klass* klass = ClassLoaderExt::load_one_class(&parser, THREAD);
-
-      CLEAR_PENDING_EXCEPTION;
+      if (HAS_PENDING_EXCEPTION) {
+        if (klass == NULL &&
+             (PENDING_EXCEPTION->klass()->name() == vmSymbols::java_lang_ClassNotFoundException())) {
+          // print a warning only when the pending exception is class not found
+          tty->print_cr("Preload Warning: Cannot find %s", parser.current_class_name());
+        }
+        CLEAR_PENDING_EXCEPTION;
+      }
       if (klass != NULL) {
         if (log_is_enabled(Trace, cds)) {
           ResourceMark rm;
--- a/hotspot/src/share/vm/oops/arrayKlass.cpp	Wed Aug 30 19:18:22 2017 -0400
+++ b/hotspot/src/share/vm/oops/arrayKlass.cpp	Mon Aug 28 15:34:04 2017 -0700
@@ -187,12 +187,29 @@
 
 void ArrayKlass::remove_unshareable_info() {
   Klass::remove_unshareable_info();
+  if (_higher_dimension != NULL) {
+    ArrayKlass *ak = ArrayKlass::cast(higher_dimension());
+    ak->remove_unshareable_info();
+  }
+}
+
+void ArrayKlass::remove_java_mirror() {
+  Klass::remove_java_mirror();
+  if (_higher_dimension != NULL) {
+    ArrayKlass *ak = ArrayKlass::cast(higher_dimension());
+    ak->remove_java_mirror();
+  }
 }
 
 void ArrayKlass::restore_unshareable_info(ClassLoaderData* loader_data, Handle protection_domain, TRAPS) {
   assert(loader_data == ClassLoaderData::the_null_class_loader_data(), "array classes belong to null loader");
   Klass::restore_unshareable_info(loader_data, protection_domain, CHECK);
   // Klass recreates the component mirror also
+
+  if (_higher_dimension != NULL) {
+    ArrayKlass *ak = ArrayKlass::cast(higher_dimension());
+    ak->restore_unshareable_info(loader_data, protection_domain, CHECK);
+  }
 }
 
 // Printing
--- a/hotspot/src/share/vm/oops/arrayKlass.hpp	Wed Aug 30 19:18:22 2017 -0400
+++ b/hotspot/src/share/vm/oops/arrayKlass.hpp	Mon Aug 28 15:34:04 2017 -0700
@@ -130,6 +130,7 @@
 
   // CDS support - remove and restore oops from metadata. Oops are not shared.
   virtual void remove_unshareable_info();
+  virtual void remove_java_mirror();
   virtual void restore_unshareable_info(ClassLoaderData* loader_data, Handle protection_domain, TRAPS);
 
   // Printing
--- a/hotspot/src/share/vm/oops/constantPool.cpp	Wed Aug 30 19:18:22 2017 -0400
+++ b/hotspot/src/share/vm/oops/constantPool.cpp	Mon Aug 28 15:34:04 2017 -0700
@@ -257,10 +257,14 @@
   }
 
   objArrayOop rr = resolved_references();
+  Array<u2>* ref_map = reference_map();
   if (rr != NULL) {
-    for (int i = 0; i < rr->length(); i++) {
+    int ref_map_len = ref_map == NULL ? 0 : ref_map->length();
+    int rr_len = rr->length();
+    for (int i = 0; i < rr_len; i++) {
       oop p = rr->obj_at(i);
-      if (p != NULL) {
+      rr->obj_at_put(i, NULL);
+      if (p != NULL && i < ref_map_len) {
         int index = object_to_cp_index(i);
         // Skip the entry if the string hash code is 0 since the string
         // is not included in the shared string_table, see StringTable::copy_shared_string.
@@ -271,11 +275,10 @@
           // have a 'bad' reference in the archived resolved_reference
           // array.
           rr->obj_at_put(i, op);
-        } else {
-          rr->obj_at_put(i, NULL);
         }
       }
     }
+
     oop archived = MetaspaceShared::archive_heap_object(rr, THREAD);
     _cache->set_archived_references(archived);
     set_resolved_references(NULL);
@@ -346,6 +349,26 @@
   // class redefinition. Since shared ConstantPools cannot be deallocated anyway,
   // we always set _on_stack to true to avoid having to change _flags during runtime.
   _flags |= (_on_stack | _is_shared);
+  int num_klasses = 0;
+  for (int index = 1; index < length(); index++) { // Index 0 is unused
+    assert(!tag_at(index).is_unresolved_klass_in_error(), "This must not happen during dump time");
+    if (tag_at(index).is_klass()) {
+      // This class was resolved as a side effect of executing Java code
+      // during dump time. We need to restore it back to an UnresolvedClass,
+      // so that the proper class loading and initialization can happen
+      // at runtime.
+      CPKlassSlot kslot = klass_slot_at(index);
+      int resolved_klass_index = kslot.resolved_klass_index();
+      int name_index = kslot.name_index();
+      assert(tag_at(name_index).is_symbol(), "sanity");
+      resolved_klasses()->at_put(resolved_klass_index, NULL);
+      tag_at_put(index, JVM_CONSTANT_UnresolvedClass);
+      assert(klass_name_at(index) == symbol_at(name_index), "sanity");
+    }
+  }
+  if (cache() != NULL) {
+    cache()->remove_unshareable_info();
+  }
 }
 
 int ConstantPool::cp_to_object_index(int cp_index) {
--- a/hotspot/src/share/vm/oops/cpCache.cpp	Wed Aug 30 19:18:22 2017 -0400
+++ b/hotspot/src/share/vm/oops/cpCache.cpp	Mon Aug 28 15:34:04 2017 -0700
@@ -23,6 +23,8 @@
  */
 
 #include "precompiled.hpp"
+#include "interpreter/bytecodeStream.hpp"
+#include "interpreter/bytecodes.hpp"
 #include "interpreter/interpreter.hpp"
 #include "interpreter/rewriter.hpp"
 #include "logging/log.hpp"
@@ -49,6 +51,24 @@
   assert(constant_pool_index() == index, "");
 }
 
+void ConstantPoolCacheEntry::verify_just_initialized(bool f2_used) {
+  assert((_indices & (~cp_index_mask)) == 0, "sanity");
+  assert(_f1 == NULL, "sanity");
+  assert(_flags == 0, "sanity");
+  if (!f2_used) {
+    assert(_f2 == 0, "sanity");
+  }
+}
+
+void ConstantPoolCacheEntry::reinitialize(bool f2_used) {
+  _indices &= cp_index_mask;
+  _f1 = NULL;
+  _flags = 0;
+  if (!f2_used) {
+    _f2 = 0;
+  }
+}
+
 int ConstantPoolCacheEntry::make_flags(TosState state,
                                        int option_bits,
                                        int field_index_or_method_params) {
@@ -609,6 +629,66 @@
   }
 }
 
+void ConstantPoolCache::verify_just_initialized() {
+  DEBUG_ONLY(walk_entries_for_initialization(/*check_only = */ true));
+}
+
+void ConstantPoolCache::remove_unshareable_info() {
+  walk_entries_for_initialization(/*check_only = */ false);
+}
+
+void ConstantPoolCache::walk_entries_for_initialization(bool check_only) {
+  assert(DumpSharedSpaces, "sanity");
+  // When dumping the archive, we want to clean up the ConstantPoolCache
+  // to remove any effect of linking due to the execution of Java code --
+  // each ConstantPoolCacheEntry will have the same contents as if
+  // ConstantPoolCache::initialize has just returned:
+  //
+  // - We keep the ConstantPoolCache::constant_pool_index() bits for all entries.
+  // - We keep the "f2" field for entries used by invokedynamic and invokehandle
+  // - All other bits in the entries are cleared to zero.
+  ResourceMark rm;
+
+  InstanceKlass* ik = constant_pool()->pool_holder();
+  bool* f2_used = NEW_RESOURCE_ARRAY(bool, length());
+  memset(f2_used, 0, sizeof(bool) * length());
+
+  // Find all the slots that we need to preserve f2
+  for (int i = 0; i < ik->methods()->length(); i++) {
+    Method* m = ik->methods()->at(i);
+    RawBytecodeStream bcs(m);
+    while (!bcs.is_last_bytecode()) {
+      Bytecodes::Code opcode = bcs.raw_next();
+      switch (opcode) {
+      case Bytecodes::_invokedynamic: {
+          int index = Bytes::get_native_u4(bcs.bcp() + 1);
+          int cp_cache_index = constant_pool()->invokedynamic_cp_cache_index(index);
+          f2_used[cp_cache_index] = 1;
+        }
+        break;
+      case Bytecodes::_invokehandle: {
+          int cp_cache_index = Bytes::get_native_u2(bcs.bcp() + 1);
+          f2_used[cp_cache_index] = 1;
+        }
+        break;
+      default:
+        break;
+      }
+    }
+  }
+
+  if (check_only) {
+    DEBUG_ONLY(
+      for (int i=0; i<length(); i++) {
+        entry_at(i)->verify_just_initialized(f2_used[i]);
+      })
+  } else {
+    for (int i=0; i<length(); i++) {
+      entry_at(i)->reinitialize(f2_used[i]);
+    }
+  }
+}
+
 void ConstantPoolCache::deallocate_contents(ClassLoaderData* data) {
   assert(!is_shared(), "shared caches are not deallocated");
   data->remove_handle(_resolved_references);
--- a/hotspot/src/share/vm/oops/cpCache.hpp	Wed Aug 30 19:18:22 2017 -0400
+++ b/hotspot/src/share/vm/oops/cpCache.hpp	Mon Aug 28 15:34:04 2017 -0700
@@ -393,6 +393,9 @@
     // When shifting flags as a 32-bit int, make sure we don't need an extra mask for tos_state:
     assert((((u4)-1 >> tos_state_shift) & ~tos_state_mask) == 0, "no need for tos_state mask");
   }
+
+  void verify_just_initialized(bool f2_used);
+  void reinitialize(bool f2_used);
 };
 
 
@@ -464,7 +467,11 @@
   // Assembly code support
   static int resolved_references_offset_in_bytes() { return offset_of(ConstantPoolCache, _resolved_references); }
 
+  // CDS support
+  void remove_unshareable_info();
+  void verify_just_initialized();
  private:
+  void walk_entries_for_initialization(bool check_only);
   void set_length(int length)                    { _length = length; }
 
   static int header_size()                       { return sizeof(ConstantPoolCache) / wordSize; }
--- a/hotspot/src/share/vm/oops/instanceKlass.cpp	Wed Aug 30 19:18:22 2017 -0400
+++ b/hotspot/src/share/vm/oops/instanceKlass.cpp	Mon Aug 28 15:34:04 2017 -0700
@@ -747,10 +747,10 @@
       char* message = NEW_RESOURCE_ARRAY(char, msglen);
       if (NULL == message) {
         // Out of memory: can't create detailed error message
-        THROW_MSG(vmSymbols::java_lang_NoClassDefFoundError(), className);
+          THROW_MSG(vmSymbols::java_lang_NoClassDefFoundError(), className);
       } else {
         jio_snprintf(message, msglen, "%s%s", desc, className);
-        THROW_MSG(vmSymbols::java_lang_NoClassDefFoundError(), message);
+          THROW_MSG(vmSymbols::java_lang_NoClassDefFoundError(), message);
       }
     }
 
@@ -2067,14 +2067,14 @@
     m->remove_unshareable_info();
   }
 
+  // do array classes also.
+  if (array_klasses() != NULL) {
+    array_klasses()->remove_unshareable_info();
+  }
+
   // These are not allocated from metaspace, but they should should all be empty
-  // during dump time, so we don't need to worry about them in InstanceKlass::metaspace_pointers_do().
+  // during dump time, so we don't need to worry about them in InstanceKlass::iterate().
   guarantee(_source_debug_extension == NULL, "must be");
-  guarantee(_oop_map_cache == NULL, "must be");
-  guarantee(_init_thread == NULL, "must be");
-  guarantee(_oop_map_cache == NULL, "must be");
-  guarantee(_jni_ids == NULL, "must be");
-  guarantee(_methods_jmethod_ids == NULL, "must be");
   guarantee(_dep_context == DependencyContext::EMPTY, "must be");
   guarantee(_osr_nmethods_head == NULL, "must be");
 
@@ -2082,12 +2082,20 @@
   guarantee(_breakpoints == NULL, "must be");
   guarantee(_previous_versions == NULL, "must be");
 #endif
+
+ _init_thread = NULL;
+ _methods_jmethod_ids = NULL;
+ _jni_ids = NULL;
+ _oop_map_cache = NULL;
 }
 
-static void restore_unshareable_in_class(Klass* k, TRAPS) {
-  // Array classes have null protection domain.
-  // --> see ArrayKlass::complete_create_array_klass()
-  k->restore_unshareable_info(ClassLoaderData::the_null_class_loader_data(), Handle(), CHECK);
+void InstanceKlass::remove_java_mirror() {
+  Klass::remove_java_mirror();
+
+  // do array classes also.
+  if (array_klasses() != NULL) {
+    array_klasses()->remove_java_mirror();
+  }
 }
 
 void InstanceKlass::restore_unshareable_info(ClassLoaderData* loader_data, Handle protection_domain, TRAPS) {
@@ -2114,7 +2122,11 @@
   // restore constant pool resolved references
   constants()->restore_unshareable_info(CHECK);
 
-  array_klasses_do(restore_unshareable_in_class, CHECK);
+  if (array_klasses() != NULL) {
+    // Array classes have null protection domain.
+    // --> see ArrayKlass::complete_create_array_klass()
+    array_klasses()->restore_unshareable_info(ClassLoaderData::the_null_class_loader_data(), Handle(), CHECK);
+  }
 }
 
 // returns true IFF is_in_error_state() has been changed as a result of this call.
--- a/hotspot/src/share/vm/oops/instanceKlass.hpp	Wed Aug 30 19:18:22 2017 -0400
+++ b/hotspot/src/share/vm/oops/instanceKlass.hpp	Mon Aug 28 15:34:04 2017 -0700
@@ -327,8 +327,6 @@
   }
 
   void set_class_loader_type(s2 loader_type) {
-    assert(( _misc_flags & loader_type_bits()) == 0,
-           "Should only be called once for each class.");
     switch (loader_type) {
     case ClassLoader::BOOT_LOADER:
       _misc_flags |= _misc_is_shared_boot_class;
@@ -1335,6 +1333,7 @@
 public:
   // CDS support - remove and restore oops from metadata. Oops are not shared.
   virtual void remove_unshareable_info();
+  virtual void remove_java_mirror();
   virtual void restore_unshareable_info(ClassLoaderData* loader_data, Handle protection_domain, TRAPS);
 
   // jvm support
--- a/hotspot/src/share/vm/oops/klass.cpp	Wed Aug 30 19:18:22 2017 -0400
+++ b/hotspot/src/share/vm/oops/klass.cpp	Mon Aug 28 15:34:04 2017 -0700
@@ -512,11 +512,13 @@
 void Klass::remove_unshareable_info() {
   assert (DumpSharedSpaces, "only called for DumpSharedSpaces");
   TRACE_REMOVE_ID(this);
+  if (log_is_enabled(Trace, cds, unshareable)) {
+    ResourceMark rm;
+    log_trace(cds, unshareable)("remove: %s", external_name());
+  }
 
   set_subklass(NULL);
   set_next_sibling(NULL);
-  // Clear the java mirror
-  set_java_mirror(NULL);
   set_next_link(NULL);
 
   // Null out class_loader_data because we don't share that yet.
@@ -524,10 +526,23 @@
   set_is_shared();
 }
 
+void Klass::remove_java_mirror() {
+  assert (DumpSharedSpaces, "only called for DumpSharedSpaces");
+  if (log_is_enabled(Trace, cds, unshareable)) {
+    ResourceMark rm;
+    log_trace(cds, unshareable)("remove java_mirror: %s", external_name());
+  }
+  set_java_mirror(NULL);
+}
+
 void Klass::restore_unshareable_info(ClassLoaderData* loader_data, Handle protection_domain, TRAPS) {
   assert(is_klass(), "ensure C++ vtable is restored");
   assert(is_shared(), "must be set");
   TRACE_RESTORE_ID(this);
+  if (log_is_enabled(Trace, cds, unshareable)) {
+    ResourceMark rm;
+    log_trace(cds, unshareable)("restore: %s", external_name());
+  }
 
   // If an exception happened during CDS restore, some of these fields may already be
   // set.  We leave the class on the CLD list, even if incomplete so that we don't
--- a/hotspot/src/share/vm/oops/klass.hpp	Wed Aug 30 19:18:22 2017 -0400
+++ b/hotspot/src/share/vm/oops/klass.hpp	Mon Aug 28 15:34:04 2017 -0700
@@ -479,6 +479,7 @@
 
   // CDS support - remove and restore oops from metadata. Oops are not shared.
   virtual void remove_unshareable_info();
+  virtual void remove_java_mirror();
   virtual void restore_unshareable_info(ClassLoaderData* loader_data, Handle protection_domain, TRAPS);
 
  protected:
--- a/hotspot/src/share/vm/oops/method.cpp	Wed Aug 30 19:18:22 2017 -0400
+++ b/hotspot/src/share/vm/oops/method.cpp	Mon Aug 28 15:34:04 2017 -0700
@@ -944,10 +944,6 @@
   _from_compiled_entry = cds_adapter->get_c2i_entry_trampoline();
   assert(*((int*)_from_compiled_entry) == 0, "must be NULL during dump time, to be initialized at run time");
 
-
-  // In case of DumpSharedSpaces, _method_data should always be NULL.
-  assert(_method_data == NULL, "unexpected method data?");
-
   set_method_data(NULL);
   clear_method_counters();
 }
--- a/hotspot/src/share/vm/runtime/arguments.cpp	Wed Aug 30 19:18:22 2017 -0400
+++ b/hotspot/src/share/vm/runtime/arguments.cpp	Mon Aug 28 15:34:04 2017 -0700
@@ -1291,13 +1291,11 @@
                                            "jdk.module.limitmods",
                                            "jdk.module.path",
                                            "jdk.module.upgrade.path",
-                                           "jdk.module.addmods.0",
                                            "jdk.module.patch.0" };
   const char* unsupported_options[] = { "-m", // cannot use at dump time
                                         "--limit-modules", // ignored at dump time
                                         "--module-path", // ignored at dump time
                                         "--upgrade-module-path", // ignored at dump time
-                                        "--add-modules", // ignored at dump time
                                         "--patch-module" // ignored at dump time
                                       };
   assert(ARRAY_SIZE(unsupported_properties) == ARRAY_SIZE(unsupported_options), "must be");
@@ -2667,17 +2665,11 @@
   }
 
   // Do final processing now that all arguments have been parsed
-  result = finalize_vm_init_args();
+  result = finalize_vm_init_args(patch_mod_javabase);
   if (result != JNI_OK) {
     return result;
   }
 
-#if INCLUDE_CDS
-  if (UseSharedSpaces && patch_mod_javabase) {
-    no_shared_spaces("CDS is disabled when " JAVA_BASE_NAME " module is patched.");
-  }
-#endif
-
   return JNI_OK;
 }
 
@@ -3602,7 +3594,7 @@
   return nonEmptyDirs;
 }
 
-jint Arguments::finalize_vm_init_args() {
+jint Arguments::finalize_vm_init_args(bool patch_mod_javabase) {
   // check if the default lib/endorsed directory exists; if so, error
   char path[JVM_MAXPATHLEN];
   const char* fileSep = os::file_separator();
@@ -3723,6 +3715,17 @@
   }
 #endif
 
+#if INCLUDE_CDS
+  if (DumpSharedSpaces) {
+    // Disable biased locking now as it interferes with the clean up of
+    // the archived Klasses and Java string objects (at dump time only).
+    UseBiasedLocking = false;
+  }
+  if (UseSharedSpaces && patch_mod_javabase) {
+    no_shared_spaces("CDS is disabled when " JAVA_BASE_NAME " module is patched.");
+  }
+#endif
+
   return JNI_OK;
 }
 
--- a/hotspot/src/share/vm/runtime/arguments.hpp	Wed Aug 30 19:18:22 2017 -0400
+++ b/hotspot/src/share/vm/runtime/arguments.hpp	Mon Aug 28 15:34:04 2017 -0700
@@ -536,7 +536,7 @@
                                  const JavaVMInitArgs *java_options_args,
                                  const JavaVMInitArgs *cmd_line_args);
   static jint parse_each_vm_init_arg(const JavaVMInitArgs* args, bool* patch_mod_javabase, Flag::Flags origin);
-  static jint finalize_vm_init_args();
+  static jint finalize_vm_init_args(bool patch_mod_javabase);
   static bool is_bad_option(const JavaVMOption* option, jboolean ignore, const char* option_type);
 
   static bool is_bad_option(const JavaVMOption* option, jboolean ignore) {
--- a/hotspot/src/share/vm/runtime/arguments_ext.hpp	Wed Aug 30 19:18:22 2017 -0400
+++ b/hotspot/src/share/vm/runtime/arguments_ext.hpp	Mon Aug 28 15:34:04 2017 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2017, 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
@@ -36,6 +36,7 @@
   // Otherwise returns false.
   static inline bool process_options(const JavaVMOption *option) { return false; }
   static inline void report_unsupported_options() { }
+  static inline bool using_AppCDS() { return false; }
 };
 
 void ArgumentsExt::set_gc_specific_flags() {
--- a/hotspot/src/share/vm/runtime/javaCalls.cpp	Wed Aug 30 19:18:22 2017 -0400
+++ b/hotspot/src/share/vm/runtime/javaCalls.cpp	Mon Aug 28 15:34:04 2017 -0700
@@ -308,9 +308,6 @@
 }
 
 void JavaCalls::call_helper(JavaValue* result, const methodHandle& method, JavaCallArguments* args, TRAPS) {
-  // During dumping, Java execution environment is not fully initialized. Also, Java execution
-  // may cause undesirable side-effects in the class metadata.
-  assert(!DumpSharedSpaces, "must not execute Java bytecodes when dumping");
 
   JavaThread* thread = (JavaThread*)THREAD;
   assert(thread->is_Java_thread(), "must be called by a java thread");
--- a/hotspot/src/share/vm/runtime/thread.cpp	Wed Aug 30 19:18:22 2017 -0400
+++ b/hotspot/src/share/vm/runtime/thread.cpp	Mon Aug 28 15:34:04 2017 -0700
@@ -3717,14 +3717,6 @@
 
   Thread* THREAD = Thread::current();
 
-  // At this point, the Universe is initialized, but we have not executed
-  // any byte code.  Now is a good time (the only time) to dump out the
-  // internal state of the JVM for sharing.
-  if (DumpSharedSpaces) {
-    MetaspaceShared::preload_and_dump(CHECK_JNI_ERR);
-    ShouldNotReachHere();
-  }
-
   // Always call even when there are not JVMTI environments yet, since environments
   // may be attached late and JVMTI must track phases of VM execution
   JvmtiExport::enter_early_start_phase();
@@ -3887,6 +3879,12 @@
 #ifdef ASSERT
   _vm_complete = true;
 #endif
+
+  if (DumpSharedSpaces) {
+    MetaspaceShared::preload_and_dump(CHECK_JNI_ERR);
+    ShouldNotReachHere();
+  }
+
   return JNI_OK;
 }
 
--- a/hotspot/src/share/vm/utilities/exceptions.cpp	Wed Aug 30 19:18:22 2017 -0400
+++ b/hotspot/src/share/vm/utilities/exceptions.cpp	Mon Aug 28 15:34:04 2017 -0700
@@ -87,13 +87,9 @@
 #endif // ASSERT
 
   if (thread->is_VM_thread()
-      || !thread->can_call_java()
-      || DumpSharedSpaces ) {
+      || !thread->can_call_java()) {
     // We do not care what kind of exception we get for the vm-thread or a thread which
     // is compiling.  We just install a dummy exception object
-    //
-    // We also cannot throw a proper exception when dumping, because we cannot run
-    // Java bytecodes now. A dummy exception will suffice.
     thread->set_pending_exception(Universe::vm_exception(), file, line);
     return true;
   }
@@ -114,13 +110,9 @@
   }
 
   if (thread->is_VM_thread()
-      || !thread->can_call_java()
-      || DumpSharedSpaces ) {
+      || !thread->can_call_java()) {
     // We do not care what kind of exception we get for the vm-thread or a thread which
     // is compiling.  We just install a dummy exception object
-    //
-    // We also cannot throw a proper exception when dumping, because we cannot run
-    // Java bytecodes now. A dummy exception will suffice.
     thread->set_pending_exception(Universe::vm_exception(), file, line);
     return true;
   }
--- a/hotspot/test/runtime/SharedArchiveFile/BootAppendTests.java	Wed Aug 30 19:18:22 2017 -0400
+++ b/hotspot/test/runtime/SharedArchiveFile/BootAppendTests.java	Mon Aug 28 15:34:04 2017 -0700
@@ -205,7 +205,11 @@
             OutputAnalyzer out = CDSTestUtils.runWithArchive(opts);
             CDSTestUtils.checkExec(out, opts, "[class,load] org.omg.CORBA.Context");
             if (!CDSTestUtils.isUnableToMap(out)) {
-                out.shouldMatch(".*\\[class,load\\] org.omg.CORBA.Context source:.*bootAppend.jar");
+                if (mode.equals("off")) {
+                    out.shouldMatch(".*\\[class,load\\] org.omg.CORBA.Context source:.*bootAppend.jar");
+                } else {
+                    CDSTestUtils.checkExec(out, opts, "[class,load] org.omg.CORBA.Context source: shared objects file");
+                }
             }
         }
     }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/runtime/SharedArchiveFile/NonBootLoaderClasses.java	Mon Aug 28 15:34:04 2017 -0700
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2017, 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 NonBootLoaderClasses
+ * @summary Test to ensure platform and app classes are not being archived
+ * @requires (vm.opt.UseCompressedOops == null) | (vm.opt.UseCompressedOops == true)
+ * @library /test/lib
+ * @modules java.base/jdk.internal.misc
+ *          java.management
+ * @run main NonBootLoaderClasses
+ */
+
+import jdk.test.lib.cds.CDSOptions;
+import jdk.test.lib.cds.CDSTestUtils;
+import jdk.test.lib.process.OutputAnalyzer;
+import jdk.test.lib.process.ProcessTools;
+import java.io.File;
+
+public class NonBootLoaderClasses {
+    public static void main(String[] args) throws Exception {
+        final String PLATFORM_CLASS = "jdk/dynalink/DynamicLinker";
+        final String APP_CLASS = "com/sun/tools/javac/Main";
+        String[] classes = {PLATFORM_CLASS, APP_CLASS};
+        String classList =
+            CDSTestUtils.makeClassList(classes).getPath();
+        String archiveName = "NonBootLoaderClasses.jsa";
+        CDSOptions opts = (new CDSOptions())
+            .addPrefix("-XX:ExtraSharedClassListFile=" + classList)
+            .setArchiveName(archiveName);
+        CDSTestUtils.createArchiveAndCheck(opts);
+
+        // Print the shared dictionary and inspect the output
+        ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(
+                "-XX:+UnlockDiagnosticVMOptions", "-XX:SharedArchiveFile=./" + archiveName,
+                "-XX:+PrintSharedArchiveAndExit", "-XX:+PrintSharedDictionary");
+        OutputAnalyzer out = CDSTestUtils.executeAndLog(pb, "print-shared-archive");
+        if (!CDSTestUtils.isUnableToMap(out)) {
+            out.shouldContain("archive is valid")
+               .shouldHaveExitValue(0)               // Should report success in error code.
+               .shouldNotContain(PLATFORM_CLASS)
+               .shouldNotContain(APP_CLASS);
+        }
+   }
+}
--- a/hotspot/test/runtime/modules/PatchModule/PatchModuleCDS.java	Wed Aug 30 19:18:22 2017 -0400
+++ b/hotspot/test/runtime/modules/PatchModule/PatchModuleCDS.java	Mon Aug 28 15:34:04 2017 -0700
@@ -69,7 +69,7 @@
             "-XX:+UnlockDiagnosticVMOptions",
             "-XX:SharedArchiveFile=" + filename,
             "-Xshare:dump",
-            "--patch-module=java.base=" + System.getProperty("test.classes"),
+            "--patch-module=java.naming=" + System.getProperty("test.classes"),
             "-Xlog:class+path=info",
             "-version");
         new OutputAnalyzer(pb.start())