8187118: Remove appending -cp path to the boot class path at AppCDS dump time
authorjiangli
Sun, 19 Nov 2017 23:30:41 -0500
changeset 47991 a474466c4fdb
parent 47915 d4af6b80aec3
child 47992 cd4705f9eaff
child 47996 0fd0f31ade3e
8187118: Remove appending -cp path to the boot class path at AppCDS dump time 8187119: Consolidate record_shared_class_loader_type() and record_result() Summary: Remove -cp path from the boot append list at dump time and other AppCDS cleanups. Reviewed-by: lfoltan, iklam
src/hotspot/share/classfile/classLoader.cpp
src/hotspot/share/classfile/classLoader.hpp
src/hotspot/share/classfile/classLoaderExt.hpp
src/hotspot/share/classfile/klassFactory.cpp
src/hotspot/share/classfile/systemDictionary.cpp
src/hotspot/share/memory/filemap.cpp
--- a/src/hotspot/share/classfile/classLoader.cpp	Fri Nov 17 20:56:14 2017 +0300
+++ b/src/hotspot/share/classfile/classLoader.cpp	Sun Nov 19 23:30:41 2017 -0500
@@ -145,9 +145,9 @@
 ClassPathEntry* ClassLoader::_jrt_entry = NULL;
 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
+ClassPathEntry* ClassLoader::_app_classpath_entries = NULL;
+ClassPathEntry* ClassLoader::_last_app_classpath_entry = NULL;
 GrowableArray<char*>* ClassLoader::_boot_modules_array = NULL;
 GrowableArray<char*>* ClassLoader::_platform_modules_array = NULL;
 SharedPathsMiscInfo* ClassLoader::_shared_paths_misc_info = NULL;
@@ -660,20 +660,18 @@
 
 void ClassLoader::setup_bootstrap_search_path() {
   const char* sys_class_path = Arguments::get_sysclasspath();
-  const char* java_class_path = Arguments::get_appclasspath();
   if (PrintSharedArchiveAndExit) {
     // Don't print sys_class_path - this is the bootcp of this current VM process, not necessarily
     // the same as the bootcp of the shared archive.
   } else {
     trace_class_path("bootstrap loader class path=", sys_class_path);
-    trace_class_path("classpath: ", java_class_path);
   }
 #if INCLUDE_CDS
   if (DumpSharedSpaces) {
     _shared_paths_misc_info->add_boot_classpath(sys_class_path);
   }
 #endif
-  setup_search_path(sys_class_path, true);
+  setup_boot_search_path(sys_class_path);
 }
 
 #if INCLUDE_CDS
@@ -691,6 +689,36 @@
   delete checker;
   return result;
 }
+
+void ClassLoader::setup_app_search_path(const char *class_path) {
+
+  assert(DumpSharedSpaces, "Sanity");
+
+  Thread* THREAD = Thread::current();
+  int len = (int)strlen(class_path);
+  int end = 0;
+
+  // Iterate over class path entries
+  for (int start = 0; start < len; start = end) {
+    while (class_path[end] && class_path[end] != os::path_separator()[0]) {
+      end++;
+    }
+    EXCEPTION_MARK;
+    ResourceMark rm(THREAD);
+    char* path = NEW_RESOURCE_ARRAY(char, end - start + 1);
+    strncpy(path, &class_path[start], end - start);
+    path[end - start] = '\0';
+
+    check_shared_classpath(path);
+
+    update_class_path_entry_list(path, false, false);
+
+    while (class_path[end] == os::path_separator()[0]) {
+      end++;
+    }
+  }
+}
+
 #endif
 
 // Construct the array of module/path pairs as specified to --patch-module
@@ -764,10 +792,11 @@
   return false;
 }
 
-void ClassLoader::setup_search_path(const char *class_path, bool bootstrap_search) {
+// Set up the _jrt_entry if present and boot append path
+void ClassLoader::setup_boot_search_path(const char *class_path) {
   int len = (int)strlen(class_path);
   int end = 0;
-  bool set_base_piece = bootstrap_search;
+  bool set_base_piece = true;
 
   // Iterate over class path entries
   for (int start = 0; start < len; start = end) {
@@ -780,10 +809,10 @@
     strncpy(path, &class_path[start], end - start);
     path[end - start] = '\0';
 
-    // The first time through the bootstrap_search setup, it must be determined
-    // what the base or core piece of the boot loader search is.  Either a java runtime
-    // image is present or this is an exploded module build situation.
     if (set_base_piece) {
+      // The first time through the bootstrap_search setup, it must be determined
+      // what the base or core piece of the boot loader search is.  Either a java runtime
+      // image is present or this is an exploded module build situation.
       assert(string_ends_with(path, MODULES_IMAGE_NAME) || string_ends_with(path, JAVA_BASE_NAME),
              "Incorrect boot loader search path, no java runtime image or " JAVA_BASE_NAME " exploded build");
       struct stat st;
@@ -797,13 +826,7 @@
           assert(_jrt_entry == NULL, "should not setup bootstrap class search path twice");
           assert(new_entry != NULL && new_entry->is_modules_image(), "No java runtime image present");
           _jrt_entry = new_entry;
-          ++_num_entries;
-#if INCLUDE_CDS
-          if (DumpSharedSpaces) {
-            JImageFile *jimage = _jrt_entry->jimage();
-            assert(jimage != NULL, "No java runtime image file present");
-          }
-#endif
+          assert(_jrt_entry->jimage() != NULL, "No java runtime image");
         }
       } else {
         // If path does not exist, exit
@@ -813,7 +836,7 @@
     } else {
       // Every entry on the system boot class path after the initial base piece,
       // which is set by os::set_boot_path(), is considered an appended entry.
-      update_class_path_entry_list(path, false, bootstrap_search);
+      update_class_path_entry_list(path, false, true);
     }
 
 #if INCLUDE_CDS
@@ -968,7 +991,7 @@
   return false;
 }
 
-void ClassLoader::add_to_list(ClassPathEntry *new_entry) {
+void ClassLoader::add_to_boot_append_entries(ClassPathEntry *new_entry) {
   if (new_entry != NULL) {
     if (_last_append_entry == NULL) {
       assert(_first_append_entry == NULL, "boot loader's append class path entry list not empty");
@@ -978,11 +1001,48 @@
       _last_append_entry = new_entry;
     }
   }
-  _num_entries++;
 }
 
-void ClassLoader::add_to_list(const char *apath) {
-  update_class_path_entry_list((char*)apath, false, false);
+// Record the path entries specified in -cp during dump time. The recorded
+// information will be used at runtime for loading the archived app classes.
+//
+// Note that at dump time, ClassLoader::_app_classpath_entries are NOT used for
+// loading app classes. Instead, the app class are loaded by the
+// jdk/internal/loader/ClassLoaders$AppClassLoader instance.
+void ClassLoader::add_to_app_classpath_entries(const char* path,
+                                               ClassPathEntry* entry,
+                                               bool check_for_duplicates) {
+#if INCLUDE_CDS
+  assert(entry != NULL, "ClassPathEntry should not be NULL");
+  ClassPathEntry* e = _app_classpath_entries;
+  if (check_for_duplicates) {
+    while (e != NULL) {
+      if (strcmp(e->name(), entry->name()) == 0) {
+        // entry already exists
+        return;
+      }
+      e = e->next();
+    }
+  }
+
+  // The entry does not exist, add to the list
+  if (_app_classpath_entries == NULL) {
+    assert(_last_app_classpath_entry == NULL, "Sanity");
+    _app_classpath_entries = _last_app_classpath_entry = entry;
+  } else {
+    _last_app_classpath_entry->set_next(entry);
+    _last_app_classpath_entry = entry;
+  }
+
+  if (entry->is_jar_file()) {
+    ClassLoaderExt::process_jar_manifest(entry, check_for_duplicates);
+  } else {
+    if (!os::dir_is_empty(path)) {
+      tty->print_cr("Error: non-empty directory '%s'", path);
+      exit_with_path_failure("Cannot have non-empty directory in app classpaths", NULL);
+    }
+  }
+#endif
 }
 
 // Returns true IFF the file/dir exists and the entry was successfully created.
@@ -1002,8 +1062,10 @@
 
     // Do not reorder the bootclasspath which would break get_system_package().
     // Add new entry to linked list
-    if (!check_for_duplicates || !contains_append_entry(new_entry->name())) {
-      ClassLoaderExt::add_class_path_entry(path, check_for_duplicates, new_entry);
+    if (is_boot_append) {
+      add_to_boot_append_entries(new_entry);
+    } else {
+      add_to_app_classpath_entries(path, new_entry, check_for_duplicates);
     }
     return true;
   } else {
@@ -1323,6 +1385,7 @@
   return NULL;
 }
 
+// Called by the boot classloader to load classes
 InstanceKlass* ClassLoader::load_class(Symbol* name, bool search_append_only, TRAPS) {
   assert(name != NULL, "invariant");
   assert(THREAD->is_Java_thread(), "must be a JavaThread");
@@ -1402,11 +1465,6 @@
 
     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;
@@ -1442,7 +1500,11 @@
     return NULL;
   }
 
-  return context.record_result(name, e, classpath_index, result, THREAD);
+  if (!add_package(file_name, classpath_index, THREAD)) {
+    return NULL;
+  }
+
+  return result;
 }
 
 #if INCLUDE_CDS
@@ -1465,7 +1527,9 @@
   return source;
 }
 
-void ClassLoader::record_shared_class_loader_type(InstanceKlass* ik, const ClassFileStream* stream) {
+// Record the shared classpath index and loader type for classes loaded
+// by the builtin loaders at dump time.
+void ClassLoader::record_result(InstanceKlass* ik, const ClassFileStream* stream) {
   assert(DumpSharedSpaces, "sanity");
   assert(stream != NULL, "sanity");
 
@@ -1474,7 +1538,8 @@
     return;
   }
 
-  if (stream->source() == NULL) {
+  char* src = (char*)stream->source();
+  if (src == NULL) {
     if (ik->class_loader() == NULL) {
       // JFR classes
       ik->set_shared_classpath_index(0);
@@ -1486,56 +1551,42 @@
   assert(has_jrt_entry(), "CDS dumping does not support exploded JDK build");
 
   ModuleEntry* module = ik->module();
-  ClassPathEntry* e = NULL;
-  int classpath_index = 0;
+  int classpath_index = -1;
+  ResourceMark rm;
+  char* canonical_path = NEW_RESOURCE_ARRAY(char, JVM_MAXPATHLEN);
 
-  // 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 ++;
+  // save the path from the file: protocol or the module name from the jrt: protocol
+  // if no protocol prefix is found, path is the same as stream->source()
+  char* path = skip_uri_protocol(src);
+  for (int i = 0; i < FileMapInfo::get_number_of_share_classpaths(); i++) {
+    SharedClassPathEntry* ent = FileMapInfo::shared_classpath(i);
+    if (get_canonical_path(ent->name(), canonical_path, JVM_MAXPATHLEN)) {
+      // If the path (from the class stream srouce) is the same as the shared
+      // class path, then we have a match. For classes from module image loaded by the
+      // PlatformClassLoader, the stream->source() is not the name of the module image.
+      // Need to look for 'jrt:' explicitly.
+      if (strcmp(canonical_path, os::native_path((char*)path)) == 0 ||
+          (i == 0 && string_starts_with(src, "jrt:"))) {
+        classpath_index = i;
+        break;
       }
     }
-    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 < 0) {
+    // Shared classpath entry table only contains boot class path and -cp path.
+    // No path entry found for this class. Must be a shared class loaded by the
+    // user defined classloader.
+    assert(ik->shared_classpath_index() < 0, "Sanity");
+    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);
+  context.record_result(ik->name(), classpath_index, ik, THREAD);
 }
 #endif // INCLUDE_CDS
 
@@ -1623,7 +1674,6 @@
 #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/src/hotspot/share/classfile/classLoader.hpp	Fri Nov 17 20:56:14 2017 +0300
+++ b/src/hotspot/share/classfile/classLoader.hpp	Sun Nov 19 23:30:41 2017 -0500
@@ -237,14 +237,6 @@
   // Last entry in linked list of appended ClassPathEntry instances
   static ClassPathEntry* _last_append_entry;
 
-  // Note: _num_entries includes the java runtime image and all
-  //       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;)
 
@@ -254,12 +246,22 @@
   // Info used by CDS
   CDS_ONLY(static SharedPathsMiscInfo * _shared_paths_misc_info;)
 
+  CDS_ONLY(static ClassPathEntry* _app_classpath_entries;)
+  CDS_ONLY(static ClassPathEntry* _last_app_classpath_entry;)
+  CDS_ONLY(static void setup_app_search_path(const char *class_path);)
+  static void add_to_app_classpath_entries(const char* path,
+                                           ClassPathEntry* entry,
+                                           bool check_for_duplicates);
+ public:
+  CDS_ONLY(static ClassPathEntry* app_classpath_entries() {return _app_classpath_entries;})
+
+ protected:
   // Initialization:
   //   - setup the boot loader's system class path
   //   - setup the boot loader's patch mod entries, if present
   //   - create the ModuleEntry for java.base
   static void setup_bootstrap_search_path();
-  static void setup_search_path(const char *class_path, bool setting_bootstrap);
+  static void setup_boot_search_path(const char *class_path);
   static void setup_patch_mod_entries();
   static void create_javabase();
 
@@ -395,7 +397,6 @@
 
   static ClassPathEntry* classpath_entry(int n) {
     assert(n >= 0, "sanity");
-    assert(!has_jrt_entry() || n < _num_entries, "sanity");
     if (n == 0) {
       assert(has_jrt_entry(), "No class path entry at 0 for exploded module builds");
       return ClassLoader::_jrt_entry;
@@ -414,15 +415,46 @@
     }
   }
 
-  static int number_of_classpath_entries() {
-    return _num_entries;
-  }
-
   static bool is_in_patch_mod_entries(Symbol* module_name);
 
 #if INCLUDE_CDS
   // Sharing dump and restore
 
+  // Helper function used by CDS code to get the number of boot classpath
+  // entries during shared classpath setup time.
+  static int num_boot_classpath_entries() {
+    assert(DumpSharedSpaces, "Should only be called at CDS dump time");
+    assert(has_jrt_entry(), "must have a java runtime image");
+    int num_entries = 1; // count the runtime image
+    ClassPathEntry* e = ClassLoader::_first_append_entry;
+    while (e != NULL) {
+      num_entries ++;
+      e = e->next();
+    }
+    return num_entries;
+  }
+
+  static ClassPathEntry* get_next_boot_classpath_entry(ClassPathEntry* e) {
+    if (e == ClassLoader::_jrt_entry) {
+      return ClassLoader::_first_append_entry;
+    } else {
+      return e->next();
+    }
+  }
+
+  // Helper function used by CDS code to get the number of app classpath
+  // entries during shared classpath setup time.
+  static int num_app_classpath_entries() {
+    assert(DumpSharedSpaces, "Should only be called at CDS dump time");
+    int num_entries = 0;
+    ClassPathEntry* e= ClassLoader::_app_classpath_entries;
+    while (e != NULL) {
+      num_entries ++;
+      e = e->next();
+    }
+    return num_entries;
+  }
+
   static void  check_shared_classpath(const char *path);
   static void  finalize_shared_paths_misc_info();
   static int   get_shared_paths_misc_info_size();
@@ -430,7 +462,7 @@
   static bool  check_shared_paths_misc_info(void* info, int size);
   static void  exit_with_path_failure(const char* error, const char* message);
 
-  static void record_shared_class_loader_type(InstanceKlass* ik, const ClassFileStream* stream);
+  static void record_result(InstanceKlass* ik, const ClassFileStream* stream);
 #endif
   static JImageLocationRef jimage_find_resource(JImageFile* jf, const char* module_name,
                                                 const char* file_name, jlong &size);
@@ -446,20 +478,15 @@
   static jlong class_link_count();
   static jlong class_link_time_ms();
 
-  static void set_first_append_entry(ClassPathEntry* entry);
-
   // indicates if class path already contains a entry (exact match by name)
   static bool contains_append_entry(const char* name);
 
-  // adds a class path list
-  static void add_to_list(ClassPathEntry* new_entry);
+  // adds a class path to the boot append entries
+  static void add_to_boot_append_entries(ClassPathEntry* new_entry);
 
   // creates a class path zip entry (returns NULL if JAR file cannot be opened)
   static ClassPathZipEntry* create_class_path_zip_entry(const char *apath, bool is_boot_append);
 
-  // add a path to class path list
-  static void add_to_list(const char* apath);
-
   static bool string_ends_with(const char* str, const char* str_to_find);
 
   // obtain package name from a fully qualified class name
--- a/src/hotspot/share/classfile/classLoaderExt.hpp	Fri Nov 17 20:56:14 2017 +0300
+++ b/src/hotspot/share/classfile/classLoaderExt.hpp	Sun Nov 19 23:30:41 2017 -0500
@@ -50,40 +50,28 @@
       return false;
     }
 
-    InstanceKlass* record_result(Symbol* class_name,
-                                 ClassPathEntry* e,
-                                 const s2 classpath_index,
-                                 InstanceKlass* result, TRAPS) {
-      if (ClassLoader::add_package(_file_name, classpath_index, THREAD)) {
+    void record_result(Symbol* class_name,
+                       const s2 classpath_index,
+                       InstanceKlass* result, TRAPS) {
 #if INCLUDE_CDS
-        if (DumpSharedSpaces) {
-          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);
-        }
+      assert(DumpSharedSpaces, "Sanity");
+      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);
 #endif
-        return result;
-      } else {
-        return NULL;
-      }
     }
   };
 
-
-  static void add_class_path_entry(const char* path, bool check_for_duplicates,
-                                   ClassPathEntry* new_entry) {
-    ClassLoader::add_to_list(new_entry);
-  }
   static void append_boot_classpath(ClassPathEntry* new_entry) {
-    ClassLoader::add_to_list(new_entry);
+    ClassLoader::add_to_boot_append_entries(new_entry);
   }
   static void setup_search_paths() {}
   static bool is_boot_classpath(int classpath_index) {
@@ -96,6 +84,7 @@
   static char* read_manifest(ClassPathEntry* entry, jint *manifest_size, TRAPS) {
     return NULL;
   }
+  static void process_jar_manifest(ClassPathEntry* entry, bool check_for_duplicates) {}
 #endif
 };
 
--- a/src/hotspot/share/classfile/klassFactory.cpp	Fri Nov 17 20:56:14 2017 +0300
+++ b/src/hotspot/share/classfile/klassFactory.cpp	Sun Nov 19 23:30:41 2017 -0500
@@ -231,7 +231,7 @@
 
 #if INCLUDE_CDS
   if (DumpSharedSpaces) {
-    ClassLoader::record_shared_class_loader_type(result, stream);
+    ClassLoader::record_result(result, stream);
 #if INCLUDE_JVMTI
     assert(cached_class_file == NULL, "Sanity");
     // Archive the class stream data into the optional data section
--- a/src/hotspot/share/classfile/systemDictionary.cpp	Fri Nov 17 20:56:14 2017 +0300
+++ b/src/hotspot/share/classfile/systemDictionary.cpp	Sun Nov 19 23:30:41 2017 -0500
@@ -1465,25 +1465,23 @@
       // java.base packages in the boot loader's PackageEntryTable.
       // No class outside of java.base is allowed to be loaded during
       // this bootstrapping window.
-      if (!DumpSharedSpaces) {
-        if (pkg_entry == NULL || pkg_entry->in_unnamed_module()) {
-          // Class is either in the unnamed package or in
-          // a named package within the unnamed module.  Either
-          // case is outside of java.base, do not attempt to
-          // load the class post java.base definition.  If
-          // java.base has not been defined, let the class load
-          // and its package will be checked later by
-          // ModuleEntryTable::verify_javabase_packages.
-          if (ModuleEntryTable::javabase_defined()) {
-            return NULL;
-          }
-        } else {
-          // Check that the class' package is defined within java.base.
-          ModuleEntry* mod_entry = pkg_entry->module();
-          Symbol* mod_entry_name = mod_entry->name();
-          if (mod_entry_name->fast_compare(vmSymbols::java_base()) != 0) {
-            return NULL;
-          }
+      if (pkg_entry == NULL || pkg_entry->in_unnamed_module()) {
+        // Class is either in the unnamed package or in
+        // a named package within the unnamed module.  Either
+        // case is outside of java.base, do not attempt to
+        // load the class post java.base definition.  If
+        // java.base has not been defined, let the class load
+        // and its package will be checked later by
+        // ModuleEntryTable::verify_javabase_packages.
+        if (ModuleEntryTable::javabase_defined()) {
+          return NULL;
+        }
+      } else {
+        // Check that the class' package is defined within java.base.
+        ModuleEntry* mod_entry = pkg_entry->module();
+        Symbol* mod_entry_name = mod_entry->name();
+        if (mod_entry_name->fast_compare(vmSymbols::java_base()) != 0) {
+          return NULL;
         }
       }
     } else {
@@ -1501,7 +1499,7 @@
 
     // Prior to bootstrapping's module initialization, never load a class outside
     // of the boot loader's module path
-    assert(Universe::is_module_initialized() || DumpSharedSpaces ||
+    assert(Universe::is_module_initialized() ||
            !search_only_bootloader_append,
            "Attempt to load a class outside of boot loader's module path");
 
--- a/src/hotspot/share/memory/filemap.cpp	Fri Nov 17 20:56:14 2017 +0300
+++ b/src/hotspot/share/memory/filemap.cpp	Sun Nov 19 23:30:41 2017 -0500
@@ -266,32 +266,55 @@
 }
 
 void FileMapInfo::allocate_classpath_entry_table() {
+  assert(DumpSharedSpaces, "Sanity");
+
   Thread* THREAD = Thread::current();
   ClassLoaderData* loader_data = ClassLoaderData::the_null_class_loader_data();
+  ClassPathEntry* jrt = ClassLoader::get_jrt_entry();
+
+  assert(jrt != NULL,
+         "No modular java runtime image present when allocating the CDS classpath entry table");
+
   size_t entry_size = SharedClassUtil::shared_class_path_entry_size(); // assert ( should be 8 byte aligned??)
-  int num_entries = ClassLoader::number_of_classpath_entries();
+  int num_boot_classpath_entries = ClassLoader::num_boot_classpath_entries();
+  int num_app_classpath_entries = ClassLoader::num_app_classpath_entries();
+  int num_entries = num_boot_classpath_entries + num_app_classpath_entries;
   size_t bytes = entry_size * num_entries;
 
   _classpath_entry_table = MetadataFactory::new_array<u8>(loader_data, (int)(bytes + 7 / 8), THREAD);
   _classpath_entry_table_size = num_entries;
   _classpath_entry_size = entry_size;
 
-  assert(ClassLoader::get_jrt_entry() != NULL,
-         "No modular java runtime image present when allocating the CDS classpath entry table");
-
-  for (int i=0; i<num_entries; i++) {
-    ClassPathEntry *cpe = ClassLoader::classpath_entry(i);
-    const char* type = ((i == 0) ? "jrt" : (cpe->is_jar_file() ? "jar" : "dir"));
-
+  // 1. boot class path
+  int i = 0;
+  ClassPathEntry* cpe = jrt;
+  while (cpe != NULL) {
+    const char* type = ((cpe == jrt) ? "jrt" : (cpe->is_jar_file() ? "jar" : "dir"));
     log_info(class, path)("add main shared path (%s) %s", type, cpe->name());
     SharedClassPathEntry* ent = shared_classpath(i);
     ent->init(cpe->name(), THREAD);
-
-    if (i > 0) { // No need to do jimage.
+    if (cpe != jrt) { // No need to do jimage.
       EXCEPTION_MARK; // The following call should never throw, but would exit VM on error.
       SharedClassUtil::update_shared_classpath(cpe, ent, THREAD);
     }
+    cpe = ClassLoader::get_next_boot_classpath_entry(cpe);
+    i++;
   }
+  assert(i == num_boot_classpath_entries,
+         "number of boot class path entry mismatch");
+
+  // 2. app class path
+  ClassPathEntry *acpe = ClassLoader::app_classpath_entries();
+  while (acpe != NULL) {
+    log_info(class, path)("add app shared path %s", acpe->name());
+    SharedClassPathEntry* ent = shared_classpath(i);
+    ent->init(acpe->name(), THREAD);
+    EXCEPTION_MARK;
+    SharedClassUtil::update_shared_classpath(acpe, ent, THREAD);
+    acpe = acpe->next();
+    i ++;
+  }
+  assert(i == num_entries, "number of app class path entry mismatch");
 }
 
 bool FileMapInfo::validate_classpath_entry_table() {