8194812: Extend class-data sharing to support the module path
authorccheung
Tue, 10 Apr 2018 11:43:40 -0700
changeset 49739 00805b129186
parent 49738 a7bc87a63dd8
child 49740 4062c2c5f7d7
8194812: Extend class-data sharing to support the module path 8199360: Rework the support for the 'ignored' module options in CDS Reviewed-by: jiangli, lfoltan, iklam, mseledtsov
src/hotspot/share/classfile/classLoader.cpp
src/hotspot/share/classfile/classLoader.hpp
src/hotspot/share/classfile/classLoaderExt.cpp
src/hotspot/share/classfile/classLoaderExt.hpp
src/hotspot/share/classfile/klassFactory.cpp
src/hotspot/share/classfile/modules.cpp
src/hotspot/share/classfile/modules.hpp
src/hotspot/share/classfile/sharedClassUtil.cpp
src/hotspot/share/classfile/sharedClassUtil.hpp
src/hotspot/share/classfile/systemDictionary.cpp
src/hotspot/share/classfile/systemDictionaryShared.cpp
src/hotspot/share/memory/filemap.cpp
src/hotspot/share/memory/filemap.hpp
src/hotspot/share/memory/metaspaceShared.cpp
src/hotspot/share/oops/klass.hpp
src/hotspot/share/runtime/arguments.cpp
src/hotspot/share/runtime/arguments.hpp
src/hotspot/share/runtime/thread.cpp
test/hotspot/jtreg/runtime/appcds/JarBuilder.java
test/hotspot/jtreg/runtime/appcds/TestCommon.java
test/hotspot/jtreg/runtime/appcds/jigsaw/CheckUnsupportedDumpingOptions.java
test/hotspot/jtreg/runtime/appcds/jigsaw/JigsawOptionsCombo.java
test/hotspot/jtreg/runtime/appcds/jigsaw/PatchModule/AppClassInCP.java
test/hotspot/jtreg/runtime/appcds/jigsaw/PatchModule/CustomPackage.java
test/hotspot/jtreg/runtime/appcds/jigsaw/PatchModule/MismatchedPatchModule.java
test/hotspot/jtreg/runtime/appcds/jigsaw/PatchModule/PatchDir.java
test/hotspot/jtreg/runtime/appcds/jigsaw/PatchModule/PatchJavaBase.java
test/hotspot/jtreg/runtime/appcds/jigsaw/PatchModule/Simple.java
test/hotspot/jtreg/runtime/appcds/jigsaw/PatchModule/SubClassOfPatchedClass.java
test/hotspot/jtreg/runtime/appcds/jigsaw/PatchModule/TwoJars.java
test/hotspot/jtreg/runtime/appcds/jigsaw/classpathtests/BootAppendTests.java
test/hotspot/jtreg/runtime/appcds/jigsaw/classpathtests/EmptyClassInBootClassPath.java
test/hotspot/jtreg/runtime/appcds/jigsaw/limitmods/LimitModsHelper.java
test/hotspot/jtreg/runtime/appcds/jigsaw/limitmods/LimitModsTests.java
test/hotspot/jtreg/runtime/appcds/jigsaw/modulepath/AddModules.java
test/hotspot/jtreg/runtime/appcds/jigsaw/modulepath/AddOpens.java
test/hotspot/jtreg/runtime/appcds/jigsaw/modulepath/AddReads.java
test/hotspot/jtreg/runtime/appcds/jigsaw/modulepath/ExportModule.java
test/hotspot/jtreg/runtime/appcds/jigsaw/modulepath/JvmtiAddPath.java
test/hotspot/jtreg/runtime/appcds/jigsaw/modulepath/MainModuleOnly.java
test/hotspot/jtreg/runtime/appcds/jigsaw/modulepath/ModulePathAndCP.java
test/hotspot/jtreg/runtime/appcds/jigsaw/modulepath/src/com.greetings/com/greetings/Main.java
test/hotspot/jtreg/runtime/appcds/jigsaw/modulepath/src/com.greetings/module-info.java
test/hotspot/jtreg/runtime/appcds/jigsaw/modulepath/src/com.hello/com/hello/Main.java
test/hotspot/jtreg/runtime/appcds/jigsaw/modulepath/src/com.hello/module-info.java
test/hotspot/jtreg/runtime/appcds/jigsaw/modulepath/src/com.nomodule/com/nomodule/Main.java
test/hotspot/jtreg/runtime/appcds/jigsaw/modulepath/src/com.norequires/com/norequires/Main.java
test/hotspot/jtreg/runtime/appcds/jigsaw/modulepath/src/com.norequires/module-info.java
test/hotspot/jtreg/runtime/appcds/jigsaw/modulepath/src/com.simple/com/simple/Main.java
test/hotspot/jtreg/runtime/appcds/jigsaw/modulepath/src/com.simple/module-info.java
test/hotspot/jtreg/runtime/appcds/jigsaw/modulepath/src/org.astro/module-info.java
test/hotspot/jtreg/runtime/appcds/jigsaw/modulepath/src/org.astro/org/astro/World.java
test/hotspot/jtreg/runtime/appcds/test-classes/JvmtiApp.java
test/hotspot/jtreg/runtime/modules/PatchModule/PatchModuleCDS.java
test/lib/jdk/test/lib/cds/CDSTestUtils.java
--- a/src/hotspot/share/classfile/classLoader.cpp	Tue Apr 10 10:06:42 2018 -0400
+++ b/src/hotspot/share/classfile/classLoader.cpp	Tue Apr 10 11:43:40 2018 -0700
@@ -148,6 +148,8 @@
 #if INCLUDE_CDS
 ClassPathEntry* ClassLoader::_app_classpath_entries = NULL;
 ClassPathEntry* ClassLoader::_last_app_classpath_entry = NULL;
+ClassPathEntry* ClassLoader::_module_path_entries = NULL;
+ClassPathEntry* ClassLoader::_last_module_path_entry = NULL;
 SharedPathsMiscInfo* ClassLoader::_shared_paths_misc_info = NULL;
 #endif
 
@@ -721,7 +723,44 @@
   }
 }
 
-#endif
+void ClassLoader::add_to_module_path_entries(const char* path,
+                                             ClassPathEntry* entry) {
+  assert(entry != NULL, "ClassPathEntry should not be NULL");
+  assert(DumpSharedSpaces, "dump time only");
+
+  // The entry does not exist, add to the list
+  if (_module_path_entries == NULL) {
+    assert(_last_module_path_entry == NULL, "Sanity");
+    _module_path_entries = _last_module_path_entry = entry;
+  } else {
+    _last_module_path_entry->set_next(entry);
+    _last_module_path_entry = entry;
+  }
+}
+
+// Add a module path to the _module_path_entries list.
+void ClassLoader::update_module_path_entry_list(const char *path, TRAPS) {
+  assert(DumpSharedSpaces, "dump time only");
+  struct stat st;
+  int ret = os::stat(path, &st);
+  assert(ret == 0, "module path must exist");
+  // File or directory found
+  ClassPathEntry* new_entry = NULL;
+  new_entry = create_class_path_entry(path, &st, true /* throw_exception */,
+                                      false /*is_boot_append */, CHECK);
+  if (new_entry == NULL) {
+    return;
+  }
+
+  add_to_module_path_entries(path, new_entry);
+  return;
+}
+
+void ClassLoader::setup_module_search_path(const char* path, TRAPS) {
+  check_shared_classpath(path);
+  update_module_path_entry_list(path, THREAD);
+}
+#endif // INCLUDE_CDS
 
 // Construct the array of module/path pairs as specified to --patch-module
 // for the boot loader to search ahead of the jimage, if the class being
@@ -1512,7 +1551,7 @@
 }
 
 #if INCLUDE_CDS
-static char* skip_uri_protocol(char* source) {
+char* ClassLoader::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
@@ -1533,7 +1572,7 @@
 
 // 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) {
+void ClassLoader::record_result(InstanceKlass* ik, const ClassFileStream* stream, TRAPS) {
   assert(DumpSharedSpaces, "sanity");
   assert(stream != NULL, "sanity");
 
@@ -1542,9 +1581,10 @@
     return;
   }
 
+  oop loader = ik->class_loader();
   char* src = (char*)stream->source();
   if (src == NULL) {
-    if (ik->class_loader() == NULL) {
+    if (loader == NULL) {
       // JFR classes
       ik->set_shared_classpath_index(0);
       ik->set_class_loader_type(ClassLoader::BOOT_LOADER);
@@ -1554,41 +1594,84 @@
 
   assert(has_jrt_entry(), "CDS dumping does not support exploded JDK build");
 
-  ModuleEntry* module = ik->module();
+  ResourceMark rm(THREAD);
   int classpath_index = -1;
-  ResourceMark rm;
-  char* canonical_path = NEW_RESOURCE_ARRAY(char, JVM_MAXPATHLEN);
+  PackageEntry* pkg_entry = ik->package();
+
+  if (FileMapInfo::get_number_of_shared_paths() > 0) {
+    char* canonical_path = NEW_RESOURCE_ARRAY(char, JVM_MAXPATHLEN);
 
-  // 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;
+    // 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_shared_paths(); i++) {
+      SharedClassPathEntry* ent = FileMapInfo::shared_path(i);
+      if (get_canonical_path(ent->name(), canonical_path, JVM_MAXPATHLEN)) {
+        // If the path (from the class stream source) is the same as the shared
+        // class or module path, then we have a match.
+        if (strcmp(canonical_path, os::native_path((char*)path)) == 0) {
+          // NULL pkg_entry and pkg_entry in an unnamed module implies the class
+          // is from the -cp or boot loader append path which consists of -Xbootclasspath/a
+          // and jvmti appended entries.
+          if ((pkg_entry == NULL) || (pkg_entry->in_unnamed_module())) {
+            // Ensure the index is within the -cp range before assigning
+            // to the classpath_index.
+            if (SystemDictionary::is_system_class_loader(loader) &&
+                (i >= ClassLoaderExt::app_class_paths_start_index()) &&
+                (i < ClassLoaderExt::app_module_paths_start_index())) {
+              classpath_index = i;
+              break;
+            } else {
+              if ((i >= 1) &&
+                  (i < ClassLoaderExt::app_class_paths_start_index())) {
+                // The class must be from boot loader append path which consists of
+                // -Xbootclasspath/a and jvmti appended entries.
+                assert(loader == NULL, "sanity");
+                classpath_index = i;
+                break;
+              }
+            }
+          } else {
+            // A class from a named module from the --module-path. Ensure the index is
+            // within the --module-path range before assigning to the classpath_index.
+            if ((pkg_entry != NULL) && !(pkg_entry->in_unnamed_module()) && (i > 0)) {
+              if (i >= ClassLoaderExt::app_module_paths_start_index() &&
+                  i < FileMapInfo::get_number_of_shared_paths()) {
+                classpath_index = i;
+                break;
+              }
+            }
+          }
+        }
+        // for index 0 and the stream->source() is the modules image or has the jrt: protocol.
+        // The class must be from the runtime modules image.
+        if (i == 0 && (is_modules_image(src) || string_starts_with(src, "jrt:"))) {
+          classpath_index = i;
+          break;
+        }
       }
     }
-  }
-  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 < 0) {
+      assert(ik->shared_classpath_index() < 0, "Sanity");
+      return;
+    }
+  } else {
+    // The shared path table is set up after module system initialization.
+    // The path table contains no entry before that. Any classes loaded prior
+    // to the setup of the shared path table must be from the modules image.
+    assert(is_modules_image(src), "stream must be from modules image");
+    assert(FileMapInfo::get_number_of_shared_paths() == 0, "shared path table must not have been setup");
+    classpath_index = 0;
   }
 
   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(), classpath_index, ik, THREAD);
 }
@@ -1673,6 +1756,13 @@
     _shared_paths_misc_info->write_jint(0); // see comments in SharedPathsMiscInfo::check()
   }
 }
+
+void ClassLoader::initialize_module_path(TRAPS) {
+  if (DumpSharedSpaces) {
+    ClassLoaderExt::setup_module_paths(THREAD);
+    FileMapInfo::allocate_shared_path_table();
+  }
+}
 #endif
 
 jlong ClassLoader::classloader_time_ms() {
--- a/src/hotspot/share/classfile/classLoader.hpp	Tue Apr 10 10:06:42 2018 -0400
+++ b/src/hotspot/share/classfile/classLoader.hpp	Tue Apr 10 11:43:40 2018 -0700
@@ -238,12 +238,18 @@
 
   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);)
+  CDS_ONLY(static ClassPathEntry* _module_path_entries;)
+  CDS_ONLY(static ClassPathEntry* _last_module_path_entry;)
+  CDS_ONLY(static void setup_app_search_path(const char* class_path);)
+  CDS_ONLY(static void setup_module_search_path(const char* path, TRAPS);)
   static void add_to_app_classpath_entries(const char* path,
                                            ClassPathEntry* entry,
                                            bool check_for_duplicates);
+  CDS_ONLY(static void add_to_module_path_entries(const char* path,
+                                           ClassPathEntry* entry);)
  public:
   CDS_ONLY(static ClassPathEntry* app_classpath_entries() {return _app_classpath_entries;})
+  CDS_ONLY(static ClassPathEntry* module_path_entries() {return _module_path_entries;})
 
  protected:
   // Initialization:
@@ -286,6 +292,7 @@
                                            bool check_for_duplicates,
                                            bool is_boot_append,
                                            bool throw_exception=true);
+  CDS_ONLY(static void update_module_path_entry_list(const char *path, TRAPS);)
   static void print_bootclasspath();
 
   // Timing
@@ -382,6 +389,7 @@
   static void initialize();
   static void classLoader_init2(TRAPS);
   CDS_ONLY(static void initialize_shared_path();)
+  CDS_ONLY(static void initialize_module_path(TRAPS);)
 
   static int compute_Object_vtable();
 
@@ -402,14 +410,28 @@
   // entries during shared classpath setup time.
   static int num_app_classpath_entries();
 
+  // Helper function used by CDS code to get the number of module path
+  // entries during shared classpath setup time.
+  static int num_module_path_entries() {
+    assert(DumpSharedSpaces, "Should only be called at CDS dump time");
+    int num_entries = 0;
+    ClassPathEntry* e= ClassLoader::_module_path_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();
   static void* get_shared_paths_misc_info();
   static bool  check_shared_paths_misc_info(void* info, int size);
+  static int   get_module_paths_misc_info_size();
+  static void* get_module_paths_misc_info();
   static void  exit_with_path_failure(const char* error, const char* message);
-
-  static void record_result(InstanceKlass* ik, const ClassFileStream* stream);
+  static char* skip_uri_protocol(char* source);
+  static void  record_result(InstanceKlass* ik, const ClassFileStream* stream, TRAPS);
 #endif
   static JImageLocationRef jimage_find_resource(JImageFile* jf, const char* module_name,
                                                 const char* file_name, jlong &size);
--- a/src/hotspot/share/classfile/classLoaderExt.cpp	Tue Apr 10 10:06:42 2018 -0400
+++ b/src/hotspot/share/classfile/classLoaderExt.cpp	Tue Apr 10 11:43:40 2018 -0700
@@ -30,6 +30,7 @@
 #include "classfile/classLoaderExt.hpp"
 #include "classfile/classLoaderData.inline.hpp"
 #include "classfile/klassFactory.hpp"
+#include "classfile/modules.hpp"
 #include "classfile/sharedClassUtil.hpp"
 #include "classfile/sharedPathsMiscInfo.hpp"
 #include "classfile/systemDictionaryShared.hpp"
@@ -41,19 +42,21 @@
 #include "oops/oop.inline.hpp"
 #include "oops/symbol.hpp"
 #include "runtime/arguments.hpp"
+#include "runtime/handles.inline.hpp"
 #include "runtime/java.hpp"
 #include "runtime/javaCalls.hpp"
 #include "runtime/os.hpp"
 #include "services/threadService.hpp"
 #include "utilities/stringUtils.hpp"
 
-jshort ClassLoaderExt::_app_paths_start_index = ClassLoaderExt::max_classpath_index;
+jshort ClassLoaderExt::_app_class_paths_start_index = ClassLoaderExt::max_classpath_index;
+jshort ClassLoaderExt::_app_module_paths_start_index = ClassLoaderExt::max_classpath_index;
 bool ClassLoaderExt::_has_app_classes = false;
 bool ClassLoaderExt::_has_platform_classes = false;
 
 void ClassLoaderExt::setup_app_search_path() {
   assert(DumpSharedSpaces, "this function is only used with -Xshare:dump and -XX:+UseAppCDS");
-  _app_paths_start_index = ClassLoader::num_boot_classpath_entries();
+  _app_class_paths_start_index = ClassLoader::num_boot_classpath_entries();
   char* app_class_path = os::strdup(Arguments::get_appclasspath());
 
   if (strcmp(app_class_path, ".") == 0) {
@@ -68,6 +71,29 @@
   }
 }
 
+void ClassLoaderExt::process_module_table(ModuleEntryTable* met, TRAPS) {
+  ResourceMark rm;
+  for (int i = 0; i < met->table_size(); i++) {
+    for (ModuleEntry* m = met->bucket(i); m != NULL;) {
+      char* path = m->location()->as_C_string();
+      if (strncmp(path, "file:", 5) == 0 && ClassLoader::string_ends_with(path, ".jar")) {
+        m->print();
+        path = ClassLoader::skip_uri_protocol(path);
+        ClassLoader::setup_module_search_path(path, THREAD);
+      }
+      m = m->next();
+    }
+  }
+}
+void ClassLoaderExt::setup_module_search_path(TRAPS) {
+  assert(DumpSharedSpaces, "this function is only used with -Xshare:dump and -XX:+UseAppCDS");
+  _app_module_paths_start_index = ClassLoader::num_boot_classpath_entries() +
+                              ClassLoader::num_app_classpath_entries();
+  Handle system_class_loader (THREAD, SystemDictionary::java_system_loader());
+  ModuleEntryTable* met = Modules::get_module_entry_table(system_class_loader);
+  process_module_table(met, THREAD);
+}
+
 char* ClassLoaderExt::read_manifest(ClassPathEntry* entry, jint *manifest_size, bool clean_text, TRAPS) {
   const char* name = "META-INF/MANIFEST.MF";
   char* manifest;
@@ -195,6 +221,12 @@
   }
 }
 
+void ClassLoaderExt::setup_module_paths(TRAPS) {
+  if (UseAppCDS) {
+    ClassLoaderExt::setup_module_search_path(THREAD);
+  }
+}
+
 Thread* ClassLoaderExt::Context::_dump_thread = NULL;
 
 void ClassLoaderExt::record_result(ClassLoaderExt::Context *context,
--- a/src/hotspot/share/classfile/classLoaderExt.hpp	Tue Apr 10 10:06:42 2018 -0400
+++ b/src/hotspot/share/classfile/classLoaderExt.hpp	Tue Apr 10 11:43:40 2018 -0700
@@ -26,6 +26,7 @@
 #define SHARE_VM_CLASSFILE_CLASSLOADEREXT_HPP
 
 #include "classfile/classLoader.hpp"
+#include "classfile/moduleEntry.hpp"
 #include "utilities/macros.hpp"
 
 CDS_ONLY(class SharedPathsMiscInfoExt;)
@@ -59,14 +60,14 @@
       _file_name = file_name;
 #if INCLUDE_CDS
       if (!DumpSharedSpaces && !UseSharedSpaces) {
-        // Must not modify _app_paths_start_index if we're not using CDS.
-        assert(_app_paths_start_index == ClassLoaderExt::max_classpath_index, "must be");
+        // Must not modify _app_class_paths_start_index if we're not using CDS.
+        assert(_app_class_paths_start_index == ClassLoaderExt::max_classpath_index, "must be");
       }
 #endif
     }
 
     bool should_verify(int classpath_index) {
-      CDS_ONLY(return (classpath_index >= _app_paths_start_index);)
+      CDS_ONLY(return (classpath_index >= _app_class_paths_start_index);)
       NOT_CDS(return false;)
     }
 
@@ -82,8 +83,8 @@
     ~Context() {
 #if INCLUDE_CDS
       if (!DumpSharedSpaces && !UseSharedSpaces) {
-        // Must not modify app_paths_start_index if we're not using CDS.
-        assert(_app_paths_start_index == ClassLoaderExt::max_classpath_index, "must be");
+        // Must not modify app_class_paths_start_index if we're not using CDS.
+        assert(_app_class_paths_start_index == ClassLoaderExt::max_classpath_index, "must be");
       }
 #endif
     }
@@ -93,10 +94,16 @@
 #if INCLUDE_CDS
   static char* get_class_path_attr(const char* jar_path, char* manifest, jint manifest_size);
   static void setup_app_search_path(); // Only when -Xshare:dump
+  static void process_module_table(ModuleEntryTable* met, TRAPS);
+  static void setup_module_search_path(TRAPS);
   static SharedPathsMiscInfoExt* shared_paths_misc_info() {
     return (SharedPathsMiscInfoExt*)_shared_paths_misc_info;
   }
-  static jshort _app_paths_start_index; // index of first app JAR in shared classpath entry table
+  // index of first app JAR in shared classpath entry table
+  static jshort _app_class_paths_start_index;
+  // index of first modular JAR in shared modulepath entry table
+  static jshort _app_module_paths_start_index;
+
   static bool _has_app_classes;
   static bool _has_platform_classes;
 #endif
@@ -116,6 +123,7 @@
   }
 
   static void setup_search_paths() NOT_CDS_RETURN;
+  static void setup_module_paths(TRAPS) NOT_CDS_RETURN;
 
 #if INCLUDE_CDS
 private:
@@ -137,14 +145,20 @@
 
   static void finalize_shared_paths_misc_info();
 
-  static jshort app_paths_start_index() { return _app_paths_start_index; }
+  static jshort app_class_paths_start_index() { return _app_class_paths_start_index; }
+
+  static jshort app_module_paths_start_index() { return _app_module_paths_start_index; }
 
   static void init_paths_start_index(jshort app_start) {
-    _app_paths_start_index = app_start;
+    _app_class_paths_start_index = app_start;
+  }
+
+  static void init_app_module_paths_start_index(jshort module_start) {
+    _app_module_paths_start_index = module_start;
   }
 
   static bool is_boot_classpath(int classpath_index) {
-    return classpath_index < _app_paths_start_index;
+    return classpath_index < _app_class_paths_start_index;
   }
 
   static bool has_platform_or_app_classes() {
--- a/src/hotspot/share/classfile/klassFactory.cpp	Tue Apr 10 10:06:42 2018 -0400
+++ b/src/hotspot/share/classfile/klassFactory.cpp	Tue Apr 10 11:43:40 2018 -0700
@@ -84,7 +84,7 @@
         }
       } else {
         SharedClassPathEntry* ent =
-          (SharedClassPathEntry*)FileMapInfo::shared_classpath(path_index);
+          (SharedClassPathEntry*)FileMapInfo::shared_path(path_index);
         pathname = ent == NULL ? NULL : ent->name();
       }
       ClassFileStream* stream = new ClassFileStream(ptr,
@@ -232,7 +232,7 @@
 
 #if INCLUDE_CDS
   if (DumpSharedSpaces) {
-    ClassLoader::record_result(result, stream);
+    ClassLoader::record_result(result, stream, THREAD);
 #if INCLUDE_JVMTI
     assert(cached_class_file == NULL, "Sanity");
     // Archive the class stream data into the optional data section
--- a/src/hotspot/share/classfile/modules.cpp	Tue Apr 10 10:06:42 2018 -0400
+++ b/src/hotspot/share/classfile/modules.cpp	Tue Apr 10 11:43:40 2018 -0700
@@ -85,7 +85,7 @@
   return java_lang_String::as_utf8_string(JNIHandles::resolve_non_null(version));
 }
 
-static ModuleEntryTable* get_module_entry_table(Handle h_loader) {
+ModuleEntryTable* Modules::get_module_entry_table(Handle h_loader) {
   // This code can be called during start-up, before the classLoader's classLoader data got
   // created.  So, call register_loader() to make sure the classLoader data gets created.
   ClassLoaderData *loader_cld = SystemDictionary::register_loader(h_loader);
--- a/src/hotspot/share/classfile/modules.hpp	Tue Apr 10 10:06:42 2018 -0400
+++ b/src/hotspot/share/classfile/modules.hpp	Tue Apr 10 11:43:40 2018 -0700
@@ -1,5 +1,5 @@
 /*
-* Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
+* Copyright (c) 2016, 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
@@ -28,6 +28,7 @@
 #include "memory/allocation.hpp"
 #include "runtime/handles.hpp"
 
+class ModuleEntryTable;
 class Symbol;
 
 class Modules : AllStatic {
@@ -122,6 +123,7 @@
 
   // Return TRUE iff package is defined by loader
   static bool is_package_defined(Symbol* package_name, Handle h_loader, TRAPS);
+  static ModuleEntryTable* get_module_entry_table(Handle h_loader);
 };
 
 #endif // SHARE_VM_CLASSFILE_MODULES_HPP
--- a/src/hotspot/share/classfile/sharedClassUtil.cpp	Tue Apr 10 10:06:42 2018 -0400
+++ b/src/hotspot/share/classfile/sharedClassUtil.cpp	Tue Apr 10 11:43:40 2018 -0700
@@ -93,6 +93,9 @@
   case APP:
     ClassLoader::trace_class_path("Expecting -Djava.class.path=", path);
     break;
+  case MODULE:
+    ClassLoader::trace_class_path("Checking module path: ", path);
+    break;
   default:
     SharedPathsMiscInfo::print_path(out, type, path);
   }
@@ -167,12 +170,13 @@
 
 void SharedClassUtil::initialize(TRAPS) {
   if (UseSharedSpaces) {
-    int size = FileMapInfo::get_number_of_share_classpaths();
+    int size = FileMapInfo::get_number_of_shared_paths();
     if (size > 0) {
       SystemDictionaryShared::allocate_shared_data_arrays(size, THREAD);
       if (!DumpSharedSpaces) {
         FileMapHeaderExt* header = (FileMapHeaderExt*)FileMapInfo::current_info()->header();
-        ClassLoaderExt::init_paths_start_index(header->_app_paths_start_index);
+        ClassLoaderExt::init_paths_start_index(header->_app_class_paths_start_index);
+        ClassLoaderExt::init_app_module_paths_start_index(header->_app_module_paths_start_index);
       }
     }
   }
@@ -208,7 +212,7 @@
 bool SharedClassUtil::is_classpath_entry_signed(int classpath_index) {
   assert(classpath_index >= 0, "Sanity");
   SharedClassPathEntryExt* ent = (SharedClassPathEntryExt*)
-    FileMapInfo::shared_classpath(classpath_index);
+    FileMapInfo::shared_path(classpath_index);
   return ent->_is_signed;
 }
 
@@ -216,7 +220,8 @@
   FileMapInfo::FileMapHeader::populate(mapinfo, alignment);
 
   ClassLoaderExt::finalize_shared_paths_misc_info();
-  _app_paths_start_index = ClassLoaderExt::app_paths_start_index();
+  _app_class_paths_start_index = ClassLoaderExt::app_class_paths_start_index();
+  _app_module_paths_start_index = ClassLoaderExt::app_module_paths_start_index();
 
   _verify_local = BytecodeVerificationLocal;
   _verify_remote = BytecodeVerificationRemote;
--- a/src/hotspot/share/classfile/sharedClassUtil.hpp	Tue Apr 10 10:06:42 2018 -0400
+++ b/src/hotspot/share/classfile/sharedClassUtil.hpp	Tue Apr 10 11:43:40 2018 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 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
@@ -34,10 +34,11 @@
 
 class FileMapHeaderExt: public FileMapInfo::FileMapHeader {
 public:
-  jshort _app_paths_start_index;    // Index of first app classpath entry
-  bool   _verify_local;             // BytecodeVerificationLocal setting
-  bool   _verify_remote;            // BytecodeVerificationRemote setting
-  bool   _has_platform_or_app_classes;          // Archive contains app classes
+  jshort _app_class_paths_start_index;  // Index of first app classpath entry
+  jshort _app_module_paths_start_index; // Index of first module path entry
+  bool   _verify_local;                 // BytecodeVerificationLocal setting
+  bool   _verify_remote;                // BytecodeVerificationRemote setting
+  bool   _has_platform_or_app_classes;  // Archive contains app classes
 
   FileMapHeaderExt() {
     _has_platform_or_app_classes = true;
@@ -56,12 +57,14 @@
   int   _app_offset;
 public:
   enum {
-    APP       = 5
+    APP       = 5,
+    MODULE    = 6
   };
 
   virtual const char* type_name(int type) {
     switch (type) {
     case APP:     return "APP";
+    case MODULE:  return "MODULE";
     default:      return SharedPathsMiscInfo::type_name(type);
     }
   }
--- a/src/hotspot/share/classfile/systemDictionary.cpp	Tue Apr 10 10:06:42 2018 -0400
+++ b/src/hotspot/share/classfile/systemDictionary.cpp	Tue Apr 10 11:43:40 2018 -0700
@@ -1217,7 +1217,7 @@
     }
   }
   SharedClassPathEntry* ent =
-            (SharedClassPathEntry*)FileMapInfo::shared_classpath(path_index);
+            (SharedClassPathEntry*)FileMapInfo::shared_path(path_index);
   if (!Universe::is_module_initialized()) {
     assert(ent != NULL && ent->is_modules_image(),
            "Loading non-bootstrap classes before the module system is initialized");
--- a/src/hotspot/share/classfile/systemDictionaryShared.cpp	Tue Apr 10 10:06:42 2018 -0400
+++ b/src/hotspot/share/classfile/systemDictionaryShared.cpp	Tue Apr 10 11:43:40 2018 -0700
@@ -92,7 +92,7 @@
   Handle empty;
   Handle manifest ;
   if (shared_jar_manifest(shared_path_index) == NULL) {
-    SharedClassPathEntryExt* ent = (SharedClassPathEntryExt*)FileMapInfo::shared_classpath(shared_path_index);
+    SharedClassPathEntryExt* ent = (SharedClassPathEntryExt*)FileMapInfo::shared_path(shared_path_index);
     long size = ent->manifest_size();
     if (size <= 0) {
       return empty; // No manifest - return NULL handle
@@ -138,7 +138,7 @@
   Handle url_h;
   if (shared_jar_url(shared_path_index) == NULL) {
     JavaValue result(T_OBJECT);
-    const char* path = FileMapInfo::shared_classpath_name(shared_path_index);
+    const char* path = FileMapInfo::shared_path_name(shared_path_index);
     Handle path_string = java_lang_String::create_from_str(path, CHECK_(url_h));
     Klass* classLoaders_klass =
         SystemDictionary::jdk_internal_loader_ClassLoaders_klass();
@@ -304,7 +304,7 @@
     int index = ik->shared_classpath_index();
     assert(index >= 0, "Sanity");
     SharedClassPathEntryExt* ent =
-            (SharedClassPathEntryExt*)FileMapInfo::shared_classpath(index);
+            (SharedClassPathEntryExt*)FileMapInfo::shared_path(index);
     Symbol* class_name = ik->name();
 
     if (ent->is_modules_image()) {
@@ -328,13 +328,13 @@
       // For shared app/platform classes originated from JAR files on the class path:
       //   Each of the 3 SystemDictionaryShared::_shared_xxx arrays has the same length
       //   as the shared classpath table in the shared archive (see
-      //   FileMap::_classpath_entry_table in filemap.hpp for details).
+      //   FileMap::_shared_path_table in filemap.hpp for details).
       //
       //   If a shared InstanceKlass k is loaded from the class path, let
       //
       //     index = k->shared_classpath_index():
       //
-      //   FileMap::_classpath_entry_table[index] identifies the JAR file that contains k.
+      //   FileMap::_shared_path_table[index] identifies the JAR file that contains k.
       //
       //   k's protection domain is:
       //
@@ -358,9 +358,7 @@
 }
 
 // Currently AppCDS only archives classes from the run-time image, the
-// -Xbootclasspath/a path, and the class path. The following rules need to be
-// revised when AppCDS is changed to archive classes from other code sources
-// in the future, for example the module path (specified by -p).
+// -Xbootclasspath/a path, the class path, and the module path.
 //
 // Check if a shared class can be loaded by the specific classloader. Following
 // are the "visible" archived classes for different classloaders.
@@ -368,10 +366,10 @@
 // NULL classloader:
 //   - see SystemDictionary::is_shared_class_visible()
 // Platform classloader:
-//   - Module class from "modules" jimage. ModuleEntry must be defined in the
+//   - Module class from runtime image. ModuleEntry must be defined in the
 //     classloader.
-// App Classloader:
-//   - Module class from "modules" jimage. ModuleEntry must be defined in the
+// App classloader:
+//   - Module Class from runtime image and module path. ModuleEntry must be defined in the
 //     classloader.
 //   - Class from -cp. The class must have no PackageEntry defined in any of the
 //     boot/platform/app classloader, or must be in the unnamed module defined in the
@@ -386,10 +384,11 @@
                                                      TRAPS) {
   assert(class_loader.not_null(), "Class loader should not be NULL");
   assert(Universe::is_module_initialized(), "Module system is not initialized");
+  ResourceMark rm(THREAD);
 
   int path_index = ik->shared_classpath_index();
   SharedClassPathEntry* ent =
-            (SharedClassPathEntry*)FileMapInfo::shared_classpath(path_index);
+            (SharedClassPathEntry*)FileMapInfo::shared_path(path_index);
 
   if (SystemDictionary::is_platform_class_loader(class_loader())) {
     assert(ent != NULL, "shared class for PlatformClassLoader should have valid SharedClassPathEntry");
@@ -400,7 +399,7 @@
       // PackageEntry/ModuleEntry is found in the classloader. Check if the
       // ModuleEntry's location agrees with the archived class' origination.
       if (ent->is_modules_image() && mod_entry->location()->starts_with("jrt:")) {
-        return true; // Module class from the "modules" jimage
+        return true; // Module class from the runtime image
       }
     }
   } else if (SystemDictionary::is_system_class_loader(class_loader())) {
@@ -409,7 +408,8 @@
       // The archived class is in the unnamed package. Currently, the boot image
       // does not contain any class in the unnamed package.
       assert(!ent->is_modules_image(), "Class in the unnamed package must be from the classpath");
-      if (path_index >= ClassLoaderExt::app_paths_start_index()) {
+      if (path_index >= ClassLoaderExt::app_class_paths_start_index()) {
+        assert(path_index < ClassLoaderExt::app_module_paths_start_index(), "invalid path_index");
         return true;
       }
     } else {
@@ -421,23 +421,37 @@
         if (get_package_entry(pkg_name, ClassLoaderData::class_loader_data_or_null(SystemDictionary::java_platform_loader())) == NULL &&
             get_package_entry(pkg_name, ClassLoaderData::the_null_class_loader_data()) == NULL) {
           // The PackageEntry is not defined in any of the boot/platform/app classloaders.
-          // The archived class must from -cp path and not from the run-time image.
-          if (!ent->is_modules_image() && path_index >= ClassLoaderExt::app_paths_start_index()) {
+          // The archived class must from -cp path and not from the runtime image.
+          if (!ent->is_modules_image() && path_index >= ClassLoaderExt::app_class_paths_start_index() &&
+                                          path_index < ClassLoaderExt::app_module_paths_start_index()) {
             return true;
           }
         }
       } else if (mod_entry != NULL) {
-        // The package/module is defined in the AppClassLoader. Currently we only
-        // support archiving application module class from the run-time image.
+        // The package/module is defined in the AppClassLoader. We support
+        // archiving application module class from the runtime image or from
+        // a named module from a module path.
         // Packages from the -cp path are in the unnamed_module.
-        if ((ent->is_modules_image() && mod_entry->location()->starts_with("jrt:")) ||
-            (pkg_entry->in_unnamed_module() && path_index >= ClassLoaderExt::app_paths_start_index())) {
+        if (ent->is_modules_image() && mod_entry->location()->starts_with("jrt:")) {
+          // shared module class from runtime image
+          return true;
+        } else if (pkg_entry->in_unnamed_module() && path_index >= ClassLoaderExt::app_class_paths_start_index() &&
+            path_index < ClassLoaderExt::app_module_paths_start_index()) {
+          // shared class from -cp
           DEBUG_ONLY( \
             ClassLoaderData* loader_data = class_loader_data(class_loader); \
-            if (pkg_entry->in_unnamed_module()) \
-              assert(mod_entry == loader_data->unnamed_module(), "the unnamed module is not defined in the classloader");)
-
+            assert(mod_entry == loader_data->unnamed_module(), "the unnamed module is not defined in the classloader");)
           return true;
+        } else {
+          if(!pkg_entry->in_unnamed_module() &&
+              (path_index >= ClassLoaderExt::app_module_paths_start_index())&&
+              (path_index < FileMapInfo::get_number_of_shared_paths()) &&
+              (strcmp(ent->name(), ClassLoader::skip_uri_protocol(mod_entry->location()->as_C_string())) == 0)) {
+            // shared module class from module path
+            return true;
+          } else {
+            assert(path_index < FileMapInfo::get_number_of_shared_paths(), "invalid path_index");
+          }
         }
       }
     }
--- a/src/hotspot/share/memory/filemap.cpp	Tue Apr 10 10:06:42 2018 -0400
+++ b/src/hotspot/share/memory/filemap.cpp	Tue Apr 10 11:43:40 2018 -0700
@@ -96,7 +96,7 @@
   va_list ap;
   va_start(ap, msg);
   MetaspaceShared::set_archive_loading_failed();
-  if (PrintSharedArchiveAndExit && _validating_classpath_entry_table) {
+  if (PrintSharedArchiveAndExit && _validating_shared_path_table) {
     // If we are doing PrintSharedArchiveAndExit and some of the classpath entries
     // do not validate, we can still continue "limping" to validate the remaining
     // entries. No need to quit.
@@ -188,9 +188,9 @@
   _max_heap_size = MaxHeapSize;
   _narrow_klass_base = Universe::narrow_klass_base();
   _narrow_klass_shift = Universe::narrow_klass_shift();
-  _classpath_entry_table_size = mapinfo->_classpath_entry_table_size;
-  _classpath_entry_table = mapinfo->_classpath_entry_table;
-  _classpath_entry_size = mapinfo->_classpath_entry_size;
+  _shared_path_table_size = mapinfo->_shared_path_table_size;
+  _shared_path_table = mapinfo->_shared_path_table;
+  _shared_path_entry_size = mapinfo->_shared_path_entry_size;
 
   // The following fields are for sanity checks for whether this archive
   // will function correctly with this JVM and the bootclasspath it's
@@ -231,12 +231,16 @@
   strcpy(_name->data(), name);
 }
 
-bool SharedClassPathEntry::validate() {
+bool SharedClassPathEntry::validate(bool is_class_path) {
   struct stat st;
   const char* name = this->name();
   bool ok = true;
   log_info(class, path)("checking shared classpath entry: %s", name);
-  if (os::stat(name, &st) != 0) {
+  if (os::stat(name, &st) != 0 && is_class_path) {
+    // If the archived module path entry does not exist at runtime, it is not fatal
+    // (no need to invalid the shared archive) because the shared runtime visibility check
+    // filters out any archived module classes that do not have a matching runtime
+    // module path location.
     FileMapInfo::fail_continue("Required classpath entry does not exist: %s", name);
     ok = false;
   } else if (is_dir()) {
@@ -266,7 +270,7 @@
   it->push(&_manifest);
 }
 
-void FileMapInfo::allocate_classpath_entry_table() {
+void FileMapInfo::allocate_shared_path_table() {
   assert(DumpSharedSpaces, "Sanity");
 
   Thread* THREAD = Thread::current();
@@ -279,12 +283,13 @@
   size_t entry_size = SharedClassUtil::shared_class_path_entry_size(); // assert ( should be 8 byte aligned??)
   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;
+  int num_module_path_entries = ClassLoader::num_module_path_entries();
+  int num_entries = num_boot_classpath_entries + num_app_classpath_entries + num_module_path_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;
+  _shared_path_table = MetadataFactory::new_array<u8>(loader_data, (int)(bytes + 7 / 8), THREAD);
+  _shared_path_table_size = num_entries;
+  _shared_path_entry_size = entry_size;
 
   // 1. boot class path
   int i = 0;
@@ -292,7 +297,7 @@
   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);
+    SharedClassPathEntry* ent = shared_path(i);
     ent->init(cpe->name(), THREAD);
     if (cpe != jrt) { // No need to do jimage.
       EXCEPTION_MARK; // The following call should never throw, but would exit VM on error.
@@ -308,41 +313,66 @@
   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);
+    SharedClassPathEntry* ent = shared_path(i);
     ent->init(acpe->name(), THREAD);
     EXCEPTION_MARK;
     SharedClassUtil::update_shared_classpath(acpe, ent, THREAD);
     acpe = acpe->next();
-    i ++;
+    i++;
   }
-  assert(i == num_entries, "number of app class path entry mismatch");
+
+  // 3. module path
+  ClassPathEntry *mpe = ClassLoader::module_path_entries();
+  while (mpe != NULL) {
+    log_info(class, path)("add module path %s",mpe->name());
+    SharedClassPathEntry* ent = shared_path(i);
+    ent->init(mpe->name(), THREAD);
+    EXCEPTION_MARK;
+    SharedClassUtil::update_shared_classpath(mpe, ent, THREAD);
+    mpe = mpe->next();
+    i++;
+  }
+  assert(i == num_entries, "number of shared path entry mismatch");
 }
 
-bool FileMapInfo::validate_classpath_entry_table() {
-  _validating_classpath_entry_table = true;
+// This function should only be called during run time with UseSharedSpaces enabled.
+bool FileMapInfo::validate_shared_path_table() {
+  _validating_shared_path_table = true;
+
+  _shared_path_table = _header->_shared_path_table;
+  _shared_path_entry_size = _header->_shared_path_entry_size;
+  _shared_path_table_size = _header->_shared_path_table_size;
 
-  int count = _header->_classpath_entry_table_size;
+  // Note: _app_module_paths_start_index may not have a valid value if the UseAppCDS flag
+  // wasn't enabled during dump time. Therefore, we need to use the smaller of
+  // _shared_path_table_size and _app_module_paths_start_index for the _app_module_paths_start_index.
+  FileMapHeaderExt* header = (FileMapHeaderExt*)FileMapInfo::current_info()->header();
+  int module_paths_start_index = (header->_app_module_paths_start_index >= _shared_path_table_size) ?
+                                  _shared_path_table_size : header->_app_module_paths_start_index;
 
-  _classpath_entry_table = _header->_classpath_entry_table;
-  _classpath_entry_size = _header->_classpath_entry_size;
-  _classpath_entry_table_size = _header->_classpath_entry_table_size;
+  int count = _shared_path_table_size;
 
   for (int i=0; i<count; i++) {
-    if (shared_classpath(i)->validate()) {
-      log_info(class, path)("ok");
+    if (i < module_paths_start_index) {
+      if (shared_path(i)->validate()) {
+        log_info(class, path)("ok");
+      }
+    } else if (i >= module_paths_start_index) {
+      if (shared_path(i)->validate(false /* not a class path entry */)) {
+        log_info(class, path)("ok");
+      }
     } else if (!PrintSharedArchiveAndExit) {
-      _validating_classpath_entry_table = false;
-      _classpath_entry_table = NULL;
-      _classpath_entry_table_size = 0;
+      _validating_shared_path_table = false;
+      _shared_path_table = NULL;
+      _shared_path_table_size = 0;
       return false;
     }
   }
 
-  _validating_classpath_entry_table = false;
+  _validating_shared_path_table = false;
   return true;
 }
 
-
 // Read the FileMapInfo information from the file.
 
 bool FileMapInfo::init_from_file(int fd) {
@@ -925,18 +955,18 @@
 }
 
 void FileMapInfo::metaspace_pointers_do(MetaspaceClosure* it) {
-  it->push(&_classpath_entry_table);
-  for (int i=0; i<_classpath_entry_table_size; i++) {
-    shared_classpath(i)->metaspace_pointers_do(it);
+  it->push(&_shared_path_table);
+  for (int i=0; i<_shared_path_table_size; i++) {
+    shared_path(i)->metaspace_pointers_do(it);
   }
 }
 
 
 FileMapInfo* FileMapInfo::_current_info = NULL;
-Array<u8>* FileMapInfo::_classpath_entry_table = NULL;
-int FileMapInfo::_classpath_entry_table_size = 0;
-size_t FileMapInfo::_classpath_entry_size = 0x1234baad;
-bool FileMapInfo::_validating_classpath_entry_table = false;
+Array<u8>* FileMapInfo::_shared_path_table = NULL;
+int FileMapInfo::_shared_path_table_size = 0;
+size_t FileMapInfo::_shared_path_entry_size = 0x1234baad;
+bool FileMapInfo::_validating_shared_path_table = false;
 
 // Open the shared archive file, read and validate the header
 // information (version, boot classpath, etc.).  If initialization
@@ -946,7 +976,7 @@
 // Validation of the archive is done in two steps:
 //
 // [1] validate_header() - done here. This checks the header, including _paths_misc_info.
-// [2] validate_classpath_entry_table - this is done later, because the table is in the RW
+// [2] validate_shared_path_table - this is done later, because the table is in the RW
 //     region of the archive, which is not mapped yet.
 bool FileMapInfo::initialize() {
   assert(UseSharedSpaces, "UseSharedSpaces expected.");
@@ -980,6 +1010,7 @@
   return crc;
 }
 
+// This function should only be called during run time with UseSharedSpaces enabled.
 bool FileMapInfo::FileMapHeader::validate() {
   if (VerifySharedSpaces && compute_crc() != _crc) {
     fail_continue("Header checksum verification failed.");
--- a/src/hotspot/share/memory/filemap.hpp	Tue Apr 10 10:06:42 2018 -0400
+++ b/src/hotspot/share/memory/filemap.hpp	Tue Apr 10 11:43:40 2018 -0700
@@ -53,7 +53,7 @@
 public:
   void init(const char* name, TRAPS);
   void metaspace_pointers_do(MetaspaceClosure* it);
-  bool validate();
+  bool validate(bool is_class_path = true);
 
   // The _timestamp only gets set for jar files and "modules" jimage.
   bool is_jar_or_bootimage() {
@@ -85,10 +85,10 @@
   size_t  _file_offset;
 
 private:
-  static Array<u8>*            _classpath_entry_table;
-  static int                   _classpath_entry_table_size;
-  static size_t                _classpath_entry_size;
-  static bool                  _validating_classpath_entry_table;
+  static Array<u8>*            _shared_path_table;
+  static int                   _shared_path_table_size;
+  static size_t                _shared_path_entry_size;
+  static bool                  _validating_shared_path_table;
 
   // FileMapHeader describes the shared space data in the file to be
   // mapped.  This structure gets written to a file.  It is not a class, so
@@ -153,7 +153,7 @@
     // checking the validity of the archive and is deallocated after the archive is loaded.
     //
     // Note that the _paths_misc_info does NOT include information for JAR files
-    // that existed during dump time. Their information is stored in _classpath_entry_table.
+    // that existed during dump time. Their information is stored in _shared_path_table.
     int _paths_misc_info_size;
 
     // The following is a table of all the class path entries that were used
@@ -167,9 +167,9 @@
     // FIXME -- if JAR files in the tail of the list were specified but not used during dumping,
     // they should be removed from this table, to save space and to avoid spurious
     // loading failures during runtime.
-    int _classpath_entry_table_size;
-    size_t _classpath_entry_size;
-    Array<u8>* _classpath_entry_table;
+    int _shared_path_table_size;
+    size_t _shared_path_entry_size;
+    Array<u8>* _shared_path_table;
 
     char* region_addr(int idx);
 
@@ -270,25 +270,26 @@
   // Stop CDS sharing and unmap CDS regions.
   static void stop_sharing_and_unmap(const char* msg);
 
-  static void allocate_classpath_entry_table();
-  bool validate_classpath_entry_table();
+  static void allocate_shared_path_table();
+  bool validate_shared_path_table();
 
-  static SharedClassPathEntry* shared_classpath(int index) {
+  static SharedClassPathEntry* shared_path(int index) {
     if (index < 0) {
       return NULL;
     }
-    assert(index < _classpath_entry_table_size, "sanity");
-    char* p = (char*)_classpath_entry_table->data();
-    p += _classpath_entry_size * index;
+    assert(index < _shared_path_table_size, "sanity");
+    char* p = (char*)_shared_path_table->data();
+    p += _shared_path_entry_size * index;
     return (SharedClassPathEntry*)p;
   }
-  static const char* shared_classpath_name(int index) {
+
+  static const char* shared_path_name(int index) {
     assert(index >= 0, "Sanity");
-    return shared_classpath(index)->name();
+    return shared_path(index)->name();
   }
 
-  static int get_number_of_share_classpaths() {
-    return _classpath_entry_table_size;
+  static int get_number_of_shared_paths() {
+    return _shared_path_table_size;
   }
 
  private:
--- a/src/hotspot/share/memory/metaspaceShared.cpp	Tue Apr 10 10:06:42 2018 -0400
+++ b/src/hotspot/share/memory/metaspaceShared.cpp	Tue Apr 10 11:43:40 2018 -0700
@@ -1619,7 +1619,6 @@
 void MetaspaceShared::prepare_for_dumping() {
   Arguments::check_unsupported_dumping_properties();
   ClassLoader::initialize_shared_path();
-  FileMapInfo::allocate_classpath_entry_table();
 }
 
 // Preload classes from a list, populate the shared spaces and dump to a
@@ -2001,7 +2000,7 @@
       (md_base = mapinfo->map_region(md, &md_top)) != NULL &&
       (od_base = mapinfo->map_region(od, &od_top)) != NULL &&
       (image_alignment == (size_t)os::vm_allocation_granularity()) &&
-      mapinfo->validate_classpath_entry_table()) {
+      mapinfo->validate_shared_path_table()) {
     // Success -- set up MetaspaceObj::_shared_metaspace_{base,top} for
     // fast checking in MetaspaceShared::is_in_shared_metaspace() and
     // MetaspaceObj::is_shared().
--- a/src/hotspot/share/oops/klass.hpp	Tue Apr 10 10:06:42 2018 -0400
+++ b/src/hotspot/share/oops/klass.hpp	Tue Apr 10 11:43:40 2018 -0700
@@ -150,7 +150,7 @@
   int _vtable_len;
 
 private:
-  // This is an index into FileMapHeader::_classpath_entry_table[], to
+  // This is an index into FileMapHeader::_shared_path_table[], to
   // associate this class with the JAR file where it's loaded from during
   // dump time. If a class is not loaded from the shared archive, this field is
   // -1.
--- a/src/hotspot/share/runtime/arguments.cpp	Tue Apr 10 10:06:42 2018 -0400
+++ b/src/hotspot/share/runtime/arguments.cpp	Tue Apr 10 11:43:40 2018 -0700
@@ -1446,35 +1446,23 @@
 }
 
 #if INCLUDE_CDS
+const char* unsupported_properties[] = { "jdk.module.limitmods",
+                                         "jdk.module.upgrade.path",
+                                         "jdk.module.patch.0" };
+const char* unsupported_options[] = { "--limit-modules",
+                                      "--upgrade-module-path",
+                                      "--patch-module"
+                                    };
 void Arguments::check_unsupported_dumping_properties() {
   assert(DumpSharedSpaces, "this function is only used with -Xshare:dump");
-  const char* unsupported_properties[] = { "jdk.module.main",
-                                           "jdk.module.limitmods",
-                                           "jdk.module.path",
-                                           "jdk.module.upgrade.path",
-                                           "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
-                                        "--patch-module" // ignored at dump time
-                                      };
   assert(ARRAY_SIZE(unsupported_properties) == ARRAY_SIZE(unsupported_options), "must be");
-  // If a vm option is found in the unsupported_options array with index less than the info_idx,
-  // vm will exit with an error message. Otherwise, it will print an informational message if
-  // -Xlog:cds is enabled.
-  uint info_idx = 1;
+  // If a vm option is found in the unsupported_options array, vm will exit with an error message.
   SystemProperty* sp = system_properties();
   while (sp != NULL) {
     for (uint i = 0; i < ARRAY_SIZE(unsupported_properties); i++) {
       if (strcmp(sp->key(), unsupported_properties[i]) == 0) {
-        if (i < info_idx) {
-          vm_exit_during_initialization(
-            "Cannot use the following option when dumping the shared archive", unsupported_options[i]);
-        } else {
-          log_info(cds)("Info: the %s option is ignored when dumping the shared archive",
-                        unsupported_options[i]);
-        }
+        vm_exit_during_initialization(
+          "Cannot use the following option when dumping the shared archive", unsupported_options[i]);
       }
     }
     sp = sp->next();
@@ -1485,6 +1473,20 @@
     vm_exit_during_initialization("Dumping the shared archive is not supported with an exploded module build");
   }
 }
+
+bool Arguments::check_unsupported_cds_runtime_properties() {
+  assert(UseSharedSpaces, "this function is only used with -Xshare:{on,auto}");
+  assert(ARRAY_SIZE(unsupported_properties) == ARRAY_SIZE(unsupported_options), "must be");
+  for (uint i = 0; i < ARRAY_SIZE(unsupported_properties); i++) {
+    if (get_property(unsupported_properties[i]) != NULL) {
+      if (RequireSharedSpaces) {
+        warning("CDS is disabled when the %s option is specified.", unsupported_options[i]);
+      }
+      return true;
+    }
+  }
+  return false;
+}
 #endif
 
 //===========================================================================================================
@@ -3378,6 +3380,9 @@
   if (UseSharedSpaces && patch_mod_javabase) {
     no_shared_spaces("CDS is disabled when " JAVA_BASE_NAME " module is patched.");
   }
+  if (UseSharedSpaces && !DumpSharedSpaces && check_unsupported_cds_runtime_properties()) {
+    FLAG_SET_DEFAULT(UseSharedSpaces, false);
+  }
 #endif
 
 #ifndef CAN_SHOW_REGISTERS_ON_ASSERT
--- a/src/hotspot/share/runtime/arguments.hpp	Tue Apr 10 10:06:42 2018 -0400
+++ b/src/hotspot/share/runtime/arguments.hpp	Tue Apr 10 11:43:40 2018 -0700
@@ -703,6 +703,8 @@
 
   static void check_unsupported_dumping_properties() NOT_CDS_RETURN;
 
+  static bool check_unsupported_cds_runtime_properties() NOT_CDS_RETURN;
+
   static bool atojulong(const char *s, julong* result);
 };
 
--- a/src/hotspot/share/runtime/thread.cpp	Tue Apr 10 10:06:42 2018 -0400
+++ b/src/hotspot/share/runtime/thread.cpp	Tue Apr 10 11:43:40 2018 -0700
@@ -3891,6 +3891,11 @@
   // cache the system and platform class loaders
   SystemDictionary::compute_java_loaders(CHECK_JNI_ERR);
 
+  if (DumpSharedSpaces) {
+    // capture the module path info from the ModuleEntryTable
+    ClassLoader::initialize_module_path(THREAD);
+  }
+
 #if INCLUDE_JVMCI
   if (force_JVMCI_intialization) {
     JVMCIRuntime::force_initialization(CHECK_JNI_ERR);
--- a/test/hotspot/jtreg/runtime/appcds/JarBuilder.java	Tue Apr 10 10:06:42 2018 -0400
+++ b/test/hotspot/jtreg/runtime/appcds/JarBuilder.java	Tue Apr 10 11:43:40 2018 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 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
@@ -32,9 +32,11 @@
  */
 
 import jdk.test.lib.JDKToolFinder;
+import jdk.test.lib.compiler.CompilerUtils;
 import jdk.test.lib.process.OutputAnalyzer;
 import jdk.test.lib.process.ProcessTools;
 import java.io.File;
+import java.nio.file.Path;
 import java.util.ArrayList;
 import sun.tools.jar.Main;
 
@@ -145,6 +147,21 @@
         }
     }
 
+    public static void createModularJar(String jarPath,
+                                      String classesDir,
+                                      String mainClass) throws Exception {
+        ArrayList<String> argList = new ArrayList<String>();
+        argList.add("--create");
+        argList.add("--file=" + jarPath);
+        if (mainClass != null) {
+            argList.add("--main-class=" + mainClass);
+        }
+        argList.add("-C");
+        argList.add(classesDir);
+        argList.add(".");
+        createJar(argList);
+    }
+
     private static void createJar(ArrayList<String> args) {
         if (DEBUG) printIterable("createJar args: ", args);
 
@@ -190,6 +207,23 @@
         output.shouldHaveExitValue(0);
     }
 
+    public static void compileModule(Path src,
+                                     Path dest,
+                                     String modulePathArg // arg to --module-path
+                                     ) throws Exception {
+        boolean compiled = false;
+        if (modulePathArg == null) {
+            compiled = CompilerUtils.compile(src, dest);
+        } else {
+            compiled = CompilerUtils.compile(src, dest,
+                                           "--module-path", modulePathArg);
+        }
+        if (!compiled) {
+            throw new RuntimeException("module did not compile");
+        }
+    }
+
+
     public static void signJar() throws Exception {
         String keyTool = JDKToolFinder.getJDKTool("keytool");
         String jarSigner = JDKToolFinder.getJDKTool("jarsigner");
--- a/test/hotspot/jtreg/runtime/appcds/TestCommon.java	Tue Apr 10 10:06:42 2018 -0400
+++ b/test/hotspot/jtreg/runtime/appcds/TestCommon.java	Tue Apr 10 11:43:40 2018 -0700
@@ -200,13 +200,18 @@
         return new Result(opts, runWithArchive(opts));
     }
 
-
     public static OutputAnalyzer exec(String appJar, String... suffix) throws Exception {
         AppCDSOptions opts = (new AppCDSOptions()).setAppJar(appJar);
         opts.addSuffix(suffix);
         return runWithArchive(opts);
     }
 
+    public static Result runWithModules(String prefix[], String upgrademodulepath, String modulepath,
+                                            String mid, String... testClassArgs) throws Exception {
+        AppCDSOptions opts = makeModuleOptions(prefix, upgrademodulepath, modulepath,
+                                               mid, testClassArgs);
+        return new Result(opts, runWithArchive(opts));
+    }
 
     public static OutputAnalyzer execAuto(String... suffix) throws Exception {
         AppCDSOptions opts = (new AppCDSOptions());
@@ -220,10 +225,9 @@
         return runWithArchive(opts);
     }
 
-    public static OutputAnalyzer execModule(String prefix[], String upgrademodulepath, String modulepath,
-                                            String mid, String... testClassArgs)
-        throws Exception {
 
+    private static AppCDSOptions makeModuleOptions(String prefix[], String upgrademodulepath, String modulepath,
+                                            String mid, String testClassArgs[]) {
         AppCDSOptions opts = (new AppCDSOptions());
 
         opts.addPrefix(prefix);
@@ -234,7 +238,14 @@
                            "-p", modulepath, "-m", mid);
         }
         opts.addSuffix(testClassArgs);
+        return opts;
+    }
 
+    public static OutputAnalyzer execModule(String prefix[], String upgrademodulepath, String modulepath,
+                                            String mid, String... testClassArgs)
+        throws Exception {
+        AppCDSOptions opts = makeModuleOptions(prefix, upgrademodulepath, modulepath,
+                                               mid, testClassArgs);
         return runWithArchive(opts);
     }
 
--- a/test/hotspot/jtreg/runtime/appcds/jigsaw/CheckUnsupportedDumpingOptions.java	Tue Apr 10 10:06:42 2018 -0400
+++ b/test/hotspot/jtreg/runtime/appcds/jigsaw/CheckUnsupportedDumpingOptions.java	Tue Apr 10 11:43:40 2018 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 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
@@ -40,20 +40,15 @@
 
 public class CheckUnsupportedDumpingOptions {
     private static final String[] jigsawOptions = {
-        "-m",
         "--limit-modules",
-        "--module-path",
         "--upgrade-module-path",
         "--patch-module"
     };
     private static final String[] optionValues = {
         "mymod",
-        "mymod",
-        "mydir",
         ".",
         "java.naming=javax.naming.spi.NamingManger"
     };
-    private static final int infoIdx = 1;
 
     public static void main(String[] args) throws Exception {
         String source = "package javax.naming.spi; "                +
@@ -71,31 +66,11 @@
         String appClasses[] = {"Hello"};
         for (int i = 0; i < jigsawOptions.length; i++) {
             OutputAnalyzer output;
-            if (i == 5) {
-                // --patch-module
-                output = TestCommon.dump(appJar, appClasses, "-Xlog:cds,cds+hashtables",
-                                         jigsawOptions[i] + optionValues[i] + appJar);
-            } else {
-                output = TestCommon.dump(appJar, appClasses, "-Xlog:cds,cds+hashtables",
-                                         jigsawOptions[i], optionValues[i]);
-            }
-            if (i < infoIdx) {
-                output.shouldContain("Cannot use the following option " +
-                    "when dumping the shared archive: " + jigsawOptions[i])
-                      .shouldHaveExitValue(1);
-            } else {
-                output.shouldContain("Info: the " + jigsawOptions[i] +
-                    " option is ignored when dumping the shared archive");
-                if (optionValues[i].equals("mymod")) {
-                      // java will throw FindException for a module
-                      // which cannot be found during init_phase2() of vm init
-                      output.shouldHaveExitValue(1)
-                            .shouldContain("java.lang.module.FindException: Module mymod not found");
-                } else {
-                      output.shouldHaveExitValue(0);
-                }
-            }
+            output = TestCommon.dump(appJar, appClasses, "-Xlog:cds,cds+hashtables",
+                                     jigsawOptions[i], optionValues[i]);
+            output.shouldContain("Cannot use the following option " +
+                "when dumping the shared archive: " + jigsawOptions[i])
+                  .shouldHaveExitValue(1);
         }
     }
 }
-
--- a/test/hotspot/jtreg/runtime/appcds/jigsaw/JigsawOptionsCombo.java	Tue Apr 10 10:06:42 2018 -0400
+++ b/test/hotspot/jtreg/runtime/appcds/jigsaw/JigsawOptionsCombo.java	Tue Apr 10 11:43:40 2018 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 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
@@ -69,8 +69,7 @@
     private ArrayList<TestCase> testCaseTable = new ArrayList<TestCase>();
 
     public static String infoDuringDump(String option) {
-        return "Info: the " + option +
-            " option is ignored when dumping the shared archive";
+        return "Cannot use the following option when dumping the shared archive: " + option;
     }
 
     public void runTests() throws Exception {
@@ -78,7 +77,7 @@
         testCaseTable.add(new TestCase(
             "basic: Basic dump and execute, to verify the test plumbing works",
             "", "", 0,
-            "", "", 0) );
+            "", "", 0, true) );
 
         String bcpArg = "-Xbootclasspath/a:" +
         TestCommon.getTestJar("hello_more.jar");
@@ -86,51 +85,50 @@
         testCaseTable.add(new TestCase(
             "Xbootclasspath/a: is OK for both dump and run time",
             bcpArg, "", 0,
-            bcpArg, "", 0) );
+            bcpArg, "", 0, true) );
 
         testCaseTable.add(new TestCase(
             "module-path-01: --module-path is ignored for dump time",
-            "--module-path mods",
-            infoDuringDump("--module-path"), 0,
-            null, null, 0) );
+            "--module-path mods", "", 0,
+            null, null, 0, true) );
 
         testCaseTable.add(new TestCase(
             "module-path-02: --module-path is ok for run time",
             "", "", 0,
-            "--module-path mods", "", 0) );
+            "--module-path mods", "", 0, true) );
 
         testCaseTable.add(new TestCase(
             "add-modules-01: --add-modules is ok at dump time",
             "--add-modules java.management",
             "", 0,
-            null, null, 0) );
+            null, null, 0, true) );
 
         testCaseTable.add(new TestCase(
             "add-modules-02: --add-modules is ok at run time",
             "", "", 0,
-            "--add-modules java.management", "", 0) );
+            "--add-modules java.management", "", 0, true) );
 
         testCaseTable.add(new TestCase(
             "limit-modules-01: --limit-modules is ignored at dump time",
             "--limit-modules java.base",
-            infoDuringDump("--limit-modules"), 0,
-            null, null, 0) );
+            infoDuringDump("--limit-modules"), 1,
+            null, null, 0, true) );
 
         testCaseTable.add(new TestCase(
             "limit-modules-02: --limit-modules is ok at run time",
             "", "", 0,
-            "--limit-modules java.base", "", 0) );
+            "--limit-modules java.base", "", 0, false) );
 
         testCaseTable.add(new TestCase(
             "upgrade-module-path-01: --upgrade-module-path is ignored at dump time",
             "--upgrade-module-path mods",
-            infoDuringDump("--upgrade-module-path"), 0,
-            null, null, 0) );
+            infoDuringDump("--upgrade-module-path"), 1,
+            null, null, 0, true) );
 
         testCaseTable.add(new TestCase(
             "-upgrade-module-path-module-path-02: --upgrade-module-path is ok at run time",
             "", "", 0,
-            "--upgrade-module-path mods", "", 0) );
+            "--upgrade-module-path mods", "", 0, false) );
 
         for (TestCase tc : testCaseTable) tc.execute();
     }
@@ -145,6 +143,7 @@
         String runTimeArgs;
         String runTimeExpectedOutput;
         int    runTimeExpectedExitValue;
+        boolean sharingOn;
 
         private String appJar = TestCommon.getTestJar("hello.jar");
         private String appClasses[] = {"Hello"};
@@ -152,7 +151,8 @@
 
         public TestCase(String description,
             String dumpTimeArgs, String dumpTimeExpectedOutput, int dumpTimeExpectedExitValue,
-            String runTimeArgs, String runTimeExpectedOutput, int runTimeExpectedExitValue) {
+            String runTimeArgs, String runTimeExpectedOutput, int runTimeExpectedExitValue,
+            boolean sharingOn) {
 
             this.description = description;
             this.dumpTimeArgs = dumpTimeArgs;
@@ -161,6 +161,7 @@
             this.runTimeArgs = runTimeArgs;
             this.runTimeExpectedOutput = runTimeExpectedOutput;
             this.runTimeExpectedExitValue = runTimeExpectedExitValue;
+            this.sharingOn = sharingOn;
         }
 
 
@@ -183,7 +184,13 @@
                 OutputAnalyzer execOutput = TestCommon.exec(appJar, getRunOptions());
 
                 if (runTimeExpectedExitValue == 0) {
-                    TestCommon.checkExec(execOutput, runTimeExpectedOutput, "Hello World");
+                    if (sharingOn) {
+                        TestCommon.checkExec(execOutput, runTimeExpectedOutput, "Hello World");
+                    } else {
+                        execOutput.shouldHaveExitValue(0)
+                                  .shouldContain(runTimeExpectedOutput)
+                                  .shouldContain("Hello World");
+                    }
                 } else {
                     execOutput.shouldMatch(dumpTimeExpectedOutput);
                     execOutput.shouldHaveExitValue(dumpTimeExpectedExitValue);
--- a/test/hotspot/jtreg/runtime/appcds/jigsaw/PatchModule/AppClassInCP.java	Tue Apr 10 10:06:42 2018 -0400
+++ b/test/hotspot/jtreg/runtime/appcds/jigsaw/PatchModule/AppClassInCP.java	Tue Apr 10 11:43:40 2018 -0700
@@ -86,7 +86,8 @@
                 "--patch-module=java.naming=" + moduleJar,
                 "-Xlog:class+load",
                 "PatchMain", "javax.naming.spi.NamingManager", "mypackage.Hello");
-        TestCommon.checkDump(output, "Loading classes to share");
+        output.shouldHaveExitValue(1)
+              .shouldContain("Cannot use the following option when dumping the shared archive: --patch-module");
 
         String classPath = appJar + File.pathSeparator + classDir;
         System.out.println("classPath: " + classPath);
@@ -96,9 +97,6 @@
             "--patch-module=java.naming=" + moduleJar,
             "-Xlog:class+load",
             "PatchMain", "javax.naming.spi.NamingManager", "mypackage.Hello")
-          .assertNormalExit(
-            "I pass!",
-            "Hello!",
-            "Hello source: shared objects file");
+            .assertSilentlyDisabledCDS(0, "I pass!", "Hello!");
     }
 }
--- a/test/hotspot/jtreg/runtime/appcds/jigsaw/PatchModule/CustomPackage.java	Tue Apr 10 10:06:42 2018 -0400
+++ b/test/hotspot/jtreg/runtime/appcds/jigsaw/PatchModule/CustomPackage.java	Tue Apr 10 11:43:40 2018 -0700
@@ -70,7 +70,8 @@
                 "-Xlog:class+load",
                 "-Xlog:class+path=info",
                 "PatchMain", "javax.naming.myspi.NamingManager");
-        TestCommon.checkDump(output, "Preload Warning: Cannot find javax/naming/myspi/NamingManager");
+        output.shouldHaveExitValue(1)
+              .shouldContain("Cannot use the following option when dumping the shared archive: --patch-module");
 
         TestCommon.run(
             "-XX:+UnlockDiagnosticVMOptions",
@@ -78,6 +79,6 @@
             "-Xlog:class+load",
             "-Xlog:class+path=info",
             "PatchMain", "javax.naming.myspi.NamingManager")
-          .assertNormalExit("I pass!");
+            .assertSilentlyDisabledCDS(0, "I pass!");
     }
 }
--- a/test/hotspot/jtreg/runtime/appcds/jigsaw/PatchModule/MismatchedPatchModule.java	Tue Apr 10 10:06:42 2018 -0400
+++ b/test/hotspot/jtreg/runtime/appcds/jigsaw/PatchModule/MismatchedPatchModule.java	Tue Apr 10 11:43:40 2018 -0700
@@ -62,41 +62,18 @@
         JarBuilder.build("javanaming", "javax/naming/spi/NamingManager");
         moduleJar = TestCommon.getTestJar("javanaming.jar");
 
-        // Case 1: --patch-module specified for dump time and run time
+        // Case 1: --patch-module specified for dump time
         System.out.println("Case 1: --patch-module specified for dump time and run time");
         OutputAnalyzer output =
             TestCommon.dump(null,
                 TestCommon.list("javax/naming/spi/NamingManager"),
                 "--patch-module=java.naming=" + moduleJar,
                 "PatchMain", "javax.naming.spi.NamingManager");
-        TestCommon.checkDump(output, "Loading classes to share");
-
-        // javax.naming.spi.NamingManager is not patched at runtime
-        TestCommon.run(
-            "-XX:+UnlockDiagnosticVMOptions",
-            "--patch-module=java.naming2=" + moduleJar,
-            "-Xlog:class+path=info",
-            "PatchMain", "javax.naming.spi.NamingManager")
-          .assertNormalExit(o -> o.shouldNotContain("I pass!"));
+        output.shouldHaveExitValue(1)
+              .shouldContain("Cannot use the following option when dumping the shared archive: --patch-module");
 
-        // Case 2: --patch-module specified for dump time but not for run time
-        System.out.println("Case 2: --patch-module specified for dump time but not for run time");
-        output =
-            TestCommon.dump(null,
-                TestCommon.list("javax/naming/spi/NamingManager"),
-                "--patch-module=java.naming=" + moduleJar,
-                "PatchMain", "javax.naming.spi.NamingManager");
-        TestCommon.checkDump(output, "Loading classes to share");
-
-        // javax.naming.spi.NamingManager is not patched at runtime
-        TestCommon.run(
-            "-XX:+UnlockDiagnosticVMOptions",
-            "-Xlog:class+path=info",
-            "PatchMain", "javax.naming.spi.NamingManager")
-          .assertNormalExit(o -> o.shouldNotContain("I pass!"));
-
-        // Case 3: --patch-module specified for run time but not for dump time
-        System.out.println("Case 3: --patch-module specified for run time but not for dump time");
+        // Case 2: --patch-module specified for run time but not for dump time
+        System.out.println("Case 2: --patch-module specified for run time but not for dump time");
         output =
             TestCommon.dump(null,
                 TestCommon.list("javax/naming/spi/NamingManager"),
@@ -107,26 +84,9 @@
         TestCommon.run(
             "-XX:+UnlockDiagnosticVMOptions",
             "--patch-module=java.naming=" + moduleJar,
-            "-Xlog:class+path=info",
-            "PatchMain", "javax.naming.spi.NamingManager")
-          .assertNormalExit("I pass!");
-
-        // Case 4: mismatched --patch-module entry counts between dump time and run time
-        System.out.println("Case 4: mismatched --patch-module entry counts between dump time and run time");
-        output =
-            TestCommon.dump(null,
-                TestCommon.list("javax/naming/spi/NamingManager"),
-                "--patch-module=java.naming=" + moduleJar,
-                "PatchMain", "javax.naming.spi.NamingManager");
-        TestCommon.checkDump(output, "Loading classes to share");
-
-        // javax.naming.spi.NamingManager is patched at runtime
-        TestCommon.run(
-            "-XX:+UnlockDiagnosticVMOptions",
-            "--patch-module=java.naming=" + moduleJar,
             "--patch-module=java.naming2=" + moduleJar,
             "-Xlog:class+path=info",
             "PatchMain", "javax.naming.spi.NamingManager")
-          .assertNormalExit("I pass!");
+            .assertSilentlyDisabledCDS(0, "I pass!");
     }
 }
--- a/test/hotspot/jtreg/runtime/appcds/jigsaw/PatchModule/PatchDir.java	Tue Apr 10 10:06:42 2018 -0400
+++ b/test/hotspot/jtreg/runtime/appcds/jigsaw/PatchModule/PatchDir.java	Tue Apr 10 11:43:40 2018 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 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
@@ -67,7 +67,7 @@
             "--patch-module=java.naming=" + moduleJar,
             "-Xlog:class+load",
             "PatchMain", "javax.naming.spi.NamingManager")
-            .shouldContain("Loading classes to share")
-            .shouldHaveExitValue(0);
+            .shouldContain("Cannot use the following option when dumping the shared archive: --patch-module")
+            .shouldHaveExitValue(1);
     }
 }
--- a/test/hotspot/jtreg/runtime/appcds/jigsaw/PatchModule/PatchJavaBase.java	Tue Apr 10 10:06:42 2018 -0400
+++ b/test/hotspot/jtreg/runtime/appcds/jigsaw/PatchModule/PatchJavaBase.java	Tue Apr 10 11:43:40 2018 -0700
@@ -62,7 +62,8 @@
             TestCommon.dump(null, null,
                 "--patch-module=java.base=" + moduleJar,
                 "PatchMain", "java.lang.NewClass");
-        TestCommon.checkDump(output, "Loading classes to share");
+        output.shouldHaveExitValue(1)
+              .shouldContain("Cannot use the following option when dumping the shared archive: --patch-module");
 
         TestCommon.run(
             "-XX:+UnlockDiagnosticVMOptions",
--- a/test/hotspot/jtreg/runtime/appcds/jigsaw/PatchModule/Simple.java	Tue Apr 10 10:06:42 2018 -0400
+++ b/test/hotspot/jtreg/runtime/appcds/jigsaw/PatchModule/Simple.java	Tue Apr 10 11:43:40 2018 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 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
@@ -68,7 +68,8 @@
                 "-Xlog:class+load",
                 "-Xlog:class+path=info",
                 "PatchMain", "javax.naming.spi.NamingManager");
-        TestCommon.checkDump(output, "Loading classes to share");
+        output.shouldHaveExitValue(1)
+              .shouldContain("Cannot use the following option when dumping the shared archive: --patch-module");
 
         TestCommon.run(
             "-XX:+UnlockDiagnosticVMOptions",
@@ -76,6 +77,6 @@
             "-Xlog:class+load",
             "-Xlog:class+path=info",
             "PatchMain", "javax.naming.spi.NamingManager")
-          .assertNormalExit("I pass!");
+            .assertSilentlyDisabledCDS(0, "I pass!");
     }
 }
--- a/test/hotspot/jtreg/runtime/appcds/jigsaw/PatchModule/SubClassOfPatchedClass.java	Tue Apr 10 10:06:42 2018 -0400
+++ b/test/hotspot/jtreg/runtime/appcds/jigsaw/PatchModule/SubClassOfPatchedClass.java	Tue Apr 10 11:43:40 2018 -0700
@@ -88,7 +88,8 @@
                 "--patch-module=java.naming=" + moduleJar,
                 "-Xlog:class+load",
                 "PatchMain", "javax.naming.Reference", "mypackage.MyReference");
-        TestCommon.checkDump(output, "Loading classes to share");
+        output.shouldHaveExitValue(1)
+              .shouldContain("Cannot use the following option when dumping the shared archive: --patch-module");
 
         String classPath = appJar + File.pathSeparator + classDir;
         System.out.println("classPath: " + classPath);
@@ -98,8 +99,6 @@
             "--patch-module=java.naming=" + moduleJar,
             "-Xlog:class+load",
             "PatchMain", "javax.naming.Reference", "mypackage.MyReference")
-          .assertNormalExit(
-            "I pass!",
-            "MyReference source: file:");
+            .assertSilentlyDisabledCDS(0, "MyReference source: file:", "I pass!");
     }
 }
--- a/test/hotspot/jtreg/runtime/appcds/jigsaw/PatchModule/TwoJars.java	Tue Apr 10 10:06:42 2018 -0400
+++ b/test/hotspot/jtreg/runtime/appcds/jigsaw/PatchModule/TwoJars.java	Tue Apr 10 11:43:40 2018 -0700
@@ -87,7 +87,8 @@
                 "-Xlog:class+load",
                 "-Xlog:class+path=info",
                 "PatchMain", "javax.naming.spi.NamingManager");
-        TestCommon.checkDump(output, "Loading classes to share");
+        output.shouldHaveExitValue(1)
+              .shouldContain("Cannot use the following option when dumping the shared archive: --patch-module");
 
         TestCommon.run(
             "-XX:+UnlockDiagnosticVMOptions",
@@ -95,6 +96,6 @@
             "-Xlog:class+load",
             "-Xlog:class+path=info",
             "PatchMain", "javax.naming.spi.NamingManager")
-          .assertNormalExit("I pass");
+            .assertSilentlyDisabledCDS(0, "I pass!");
     }
 }
--- a/test/hotspot/jtreg/runtime/appcds/jigsaw/classpathtests/BootAppendTests.java	Tue Apr 10 10:06:42 2018 -0400
+++ b/test/hotspot/jtreg/runtime/appcds/jigsaw/classpathtests/BootAppendTests.java	Tue Apr 10 11:43:40 2018 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 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
@@ -145,29 +145,32 @@
     // Test #3: A class in excluded package defined in boot module
     //     - should be loaded from the -Xbootclasspath/a by the boot classloader
     public static void testBootAppendExcludedModuleClassWithoutAppCDS() throws Exception {
-        CDSOptions opts = (new CDSOptions())
-            .addPrefix("-Xbootclasspath/a:" + bootAppendJar, "-cp", appJar,
-                       "--limit-modules", "java.base")
-            .setArchiveName(testArchiveName)
-            .addSuffix(MAIN_CLASS, "Test #3", BOOT_APPEND_MODULE_CLASS, "true", "BOOT");
-
-        CDSTestUtils.runWithArchiveAndCheck(opts);
+        TestCommon.run(
+            "-Xbootclasspath/a:" + bootAppendJar, "-cp", appJar,
+            "-Xlog:class+load=info",
+            "--limit-modules", "java.base",
+            MAIN_CLASS, "Test #3", BOOT_APPEND_MODULE_CLASS, "true", "BOOT")
+            .assertSilentlyDisabledCDS(out -> {
+                out.shouldHaveExitValue(0)
+                   .shouldMatch(".class.load. sun.nio.cs.ext.MyClass source:.*bootAppend.jar");
+            });
     }
 
     // Test #4: A shared class in excluded package that's archived from
     //          -Xbootclasspath/a
-    //     - should be loaded from the archive by the bootstrap classloader
+    //     - should be loaded from the jar since AppCDS will be disabled with
+    //       the --limit-modules option
     public static void testBootAppendExcludedModuleClassWithAppCDS() throws Exception {
-        OutputAnalyzer output = TestCommon.exec(
-            appJar,
-            "-Xbootclasspath/a:" + bootAppendJar,
+        TestCommon.run(
+            "-cp", appJar, "-Xbootclasspath/a:" + bootAppendJar,
+            "-Xlog:class+load=info",
             "--limit-modules", "java.base",
-            "-XX:+TraceClassLoading",
             MAIN_CLASS,
-            "Test #4", BOOT_APPEND_MODULE_CLASS, "true", "BOOT");
-        TestCommon.checkExec(output);
-        if (!TestCommon.isUnableToMap(output))
-            output.shouldContain("[class,load] sun.nio.cs.ext.MyClass source: shared objects file");
+            "Test #4", BOOT_APPEND_MODULE_CLASS, "true", "BOOT")
+            .assertSilentlyDisabledCDS(out -> {
+                out.shouldHaveExitValue(0)
+                   .shouldMatch(".class.load. sun.nio.cs.ext.MyClass source:.*bootAppend.jar");
+            });
     }
 
 
@@ -229,28 +232,28 @@
     public static void testBootAppendAppExcludeModuleClassWithoutAppCDS()
         throws Exception {
 
-        CDSOptions opts = (new CDSOptions())
-            .addPrefix("-Xbootclasspath/a:" + bootAppendJar, "-cp", appJar,
-                       "--limit-modules", "java.base")
-            .setArchiveName(testArchiveName)
-            .addSuffix(MAIN_CLASS, "Test #9", APP_MODULE_CLASS, "true", "BOOT");
-
-        CDSTestUtils.runWithArchiveAndCheck(opts);
+        TestCommon.run(
+            "-Xbootclasspath/a:" + bootAppendJar, "-cp", appJar,
+            "-Xlog:class+load=info",
+            "--limit-modules", "java.base",
+            MAIN_CLASS, "Test #9", APP_MODULE_CLASS, "true", "BOOT")
+            .assertSilentlyDisabledCDS(out -> {
+                out.shouldHaveExitValue(0)
+                   .shouldMatch(".class.load. com.sun.tools.javac.Main2 source:.*bootAppend.jar");
+            });
     }
 
     // Test #10: A shared class in excluded package defined in jimage app module
     //    - should be loaded from the -Xbootclasspath/a with AppCDS
     public static void testBootAppendAppExcludeModuleClassAppCDS() throws Exception {
-        OutputAnalyzer output = TestCommon.exec(
-            appJar,
-            "-Xbootclasspath/a:" + bootAppendJar,
-            "-XX:+TraceClassLoading",
+        TestCommon.run(
+            "-cp", appJar, "-Xbootclasspath/a:" + bootAppendJar,
+            "-Xlog:class+load=info",
             "--limit-modules", "java.base",
-            MAIN_CLASS,
-            "Test #10", APP_MODULE_CLASS, "true", "BOOT");
-        TestCommon.checkExec(output);
-
-        if (!TestCommon.isUnableToMap(output))
-            output.shouldContain("[class,load] com.sun.tools.javac.Main2 source: shared objects file");
+            MAIN_CLASS, "Test #10", APP_MODULE_CLASS, "true", "BOOT")
+            .assertSilentlyDisabledCDS(out -> {
+                out.shouldHaveExitValue(0)
+                   .shouldMatch(".class.load. com.sun.tools.javac.Main2 source:.*bootAppend.jar");
+            });
     }
 }
--- a/test/hotspot/jtreg/runtime/appcds/jigsaw/classpathtests/EmptyClassInBootClassPath.java	Tue Apr 10 10:06:42 2018 -0400
+++ b/test/hotspot/jtreg/runtime/appcds/jigsaw/classpathtests/EmptyClassInBootClassPath.java	Tue Apr 10 11:43:40 2018 -0700
@@ -89,13 +89,15 @@
         argsList.add("useAppLoader");
         opts = new String[argsList.size()];
         opts = argsList.toArray(opts);
-        TestCommon.run(opts).assertNormalExit(EXPECTED_EXCEPTION);
+        TestCommon.run(opts)
+            .assertSilentlyDisabledCDS(0, EXPECTED_EXCEPTION);
 
         // case 4: load class in bootclasspath using boot loader with '--limit-modules java.base'
         argsList.remove(argsList.size() - 1);
         argsList.add("useBootLoader");
         opts = new String[argsList.size()];
         opts = argsList.toArray(opts);
-        TestCommon.run(opts).assertNormalExit(EXPECTED_EXCEPTION);
+        TestCommon.run(opts)
+            .assertSilentlyDisabledCDS(0, EXPECTED_EXCEPTION);
     }
 }
--- a/test/hotspot/jtreg/runtime/appcds/jigsaw/limitmods/LimitModsHelper.java	Tue Apr 10 10:06:42 2018 -0400
+++ b/test/hotspot/jtreg/runtime/appcds/jigsaw/limitmods/LimitModsHelper.java	Tue Apr 10 11:43:40 2018 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 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
@@ -65,11 +65,22 @@
                 // Make sure we got the expected defining ClassLoader
                 testLoader(clazz, expectedLoaders[i]);
 
-                // Make sure the class is in the shared space
-                if (!wb.isSharedClass(clazz)) {
-                    throw new RuntimeException(clazz.getName() +
-                        ".class should be in the shared space. " +
-                         "loader=" + clazz.getClassLoader() + " module=" + clazz.getModule().getName());
+                // Make sure the class is not in the shared space
+                // because CDS is disabled with --limit-modules during run time.
+                if (excludeModIdx != -1) {
+                    if (wb.isSharedClass(clazz)) {
+                        throw new RuntimeException(clazz.getName() +
+                            ".class should not be in the shared space. " +
+                             "loader=" + clazz.getClassLoader() + " module=" + clazz.getModule().getName());
+                    }
+                } else {
+                    // class should be in the shared space if --limit-modules
+                    // isn't specified during run time
+                    if (!wb.isSharedClass(clazz)) {
+                        throw new RuntimeException(clazz.getName() +
+                            ".class should be in the shared space. " +
+                             "loader=" + clazz.getClassLoader() + " module=" + clazz.getModule().getName());
+                    }
                 }
             }
             clazz = null;
--- a/test/hotspot/jtreg/runtime/appcds/jigsaw/limitmods/LimitModsTests.java	Tue Apr 10 10:06:42 2018 -0400
+++ b/test/hotspot/jtreg/runtime/appcds/jigsaw/limitmods/LimitModsTests.java	Tue Apr 10 11:43:40 2018 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 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
@@ -150,14 +150,14 @@
                     }
                 }
             }
-            output = TestCommon.exec(
-                appJar + File.pathSeparator + helperJar,
+            TestCommon.run(
+                "-cp", appJar + File.pathSeparator + helperJar,
                 "-XX:+UnlockDiagnosticVMOptions", "-XX:+WhiteBoxAPI", bootClassPath,
                 "--limit-modules", limitMods,
                 "LimitModsHelper",
                 BOOT_ARCHIVE_CLASS, PLATFORM_ARCHIVE_CLASS, APP_ARCHIVE_CLASS,
-                Integer.toString(excludeModIdx)); // last 4 args passed to test
-            TestCommon.checkExec(output);
+                Integer.toString(excludeModIdx)) // last 4 args passed to test
+                .assertSilentlyDisabledCDS(0);
             limitMods = null;
         }
     }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/appcds/jigsaw/modulepath/AddModules.java	Tue Apr 10 11:43:40 2018 -0700
@@ -0,0 +1,137 @@
+/*
+ * 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
+ * @requires vm.cds
+ * @library /test/jdk/lib/testlibrary /test/lib /test/hotspot/jtreg/runtime/appcds
+ * @modules jdk.compiler
+ *          jdk.jartool/sun.tools.jar
+ *          jdk.jlink
+ * @run main AddModules
+ * @summary sanity test the --add-modules option
+ */
+
+import java.io.File;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+
+import jdk.test.lib.process.OutputAnalyzer;
+import jdk.testlibrary.ProcessTools;
+
+public class AddModules {
+
+    private static final Path USER_DIR = Paths.get(System.getProperty("user.dir"));
+
+    private static final String TEST_SRC = System.getProperty("test.src");
+
+    private static final Path SRC_DIR = Paths.get(TEST_SRC, "src");
+    private static final Path MODS_DIR = Paths.get("mods");
+
+    // the module name of the test module
+    private static final String MAIN_MODULE1 = "com.greetings";
+    private static final String MAIN_MODULE2 = "com.hello";
+    private static final String SUB_MODULE = "org.astro";
+
+    // the module main class
+    private static final String MAIN_CLASS1 = "com.greetings.Main";
+    private static final String MAIN_CLASS2 = "com.hello.Main";
+    private static final String APP_CLASS = "org.astro.World";
+
+    private static Path moduleDir = null;
+    private static Path subJar = null;
+    private static Path mainJar1 = null;
+    private static Path mainJar2 = null;
+
+    public static void buildTestModule() throws Exception {
+
+        // javac -d mods/$TESTMODULE src/$TESTMODULE/**
+        JarBuilder.compileModule(SRC_DIR.resolve(SUB_MODULE),
+                                 MODS_DIR.resolve(SUB_MODULE),
+                                 null);
+
+        // javac -d mods/$TESTMODULE --module-path MOD_DIR src/$TESTMODULE/**
+        JarBuilder.compileModule(SRC_DIR.resolve(MAIN_MODULE1),
+                                 MODS_DIR.resolve(MAIN_MODULE1),
+                                 MODS_DIR.toString());
+
+        JarBuilder.compileModule(SRC_DIR.resolve(MAIN_MODULE2),
+                                 MODS_DIR.resolve(MAIN_MODULE2),
+                                 MODS_DIR.toString());
+
+        moduleDir = Files.createTempDirectory(USER_DIR, "mlib");
+        subJar = moduleDir.resolve(SUB_MODULE + ".jar");
+        String classes = MODS_DIR.resolve(SUB_MODULE).toString();
+        JarBuilder.createModularJar(subJar.toString(), classes, null);
+
+        mainJar1 = moduleDir.resolve(MAIN_MODULE1 + ".jar");
+        classes = MODS_DIR.resolve(MAIN_MODULE1).toString();
+        JarBuilder.createModularJar(mainJar1.toString(), classes, MAIN_CLASS1);
+
+        mainJar2 = moduleDir.resolve(MAIN_MODULE2 + ".jar");
+        classes = MODS_DIR.resolve(MAIN_MODULE2).toString();
+        JarBuilder.createModularJar(mainJar2.toString(), classes, MAIN_CLASS2);
+
+    }
+
+    public static void main(String... args) throws Exception {
+        // compile the modules and create the modular jar files
+        buildTestModule();
+        String appClasses[] = {MAIN_CLASS1, MAIN_CLASS2, APP_CLASS};
+        // create an archive with the classes in the modules built in the
+        // previous step
+        OutputAnalyzer output = TestCommon.createArchive(
+                                        null, appClasses,
+                                        "--module-path", moduleDir.toString(),
+                                        "--add-modules",
+                                        MAIN_MODULE1 + "," + MAIN_MODULE2);
+        TestCommon.checkDump(output);
+        String prefix[] = {"-cp", "\"\"", "-Xlog:class+load=trace"};
+
+        // run the com.greetings module with the archive with the --module-path
+        // the same as the one during dump time.
+        // The classes should be loaded from the archive.
+        TestCommon.runWithModules(prefix,
+                                  null, // --upgrade-module-path
+                                  moduleDir.toString(), // --module-path
+                                  MAIN_MODULE1) // -m
+            .assertNormalExit(out -> {
+                out.shouldContain("[class,load] com.greetings.Main source: shared objects file")
+                   .shouldContain("[class,load] org.astro.World source: shared objects file");
+            });
+
+        // run the com.hello module with the archive with the --module-path
+        // the same as the one during dump time.
+        // The classes should be loaded from the archive.
+        TestCommon.runWithModules(prefix,
+                                  null, // --upgrade-module-path
+                                  moduleDir.toString(), // --module-path
+                                  MAIN_MODULE2) // -m
+            .assertNormalExit(out -> {
+                out.shouldContain("[class,load] com.hello.Main source: shared objects file")
+                   .shouldContain("[class,load] org.astro.World source: shared objects file");
+            });
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/appcds/jigsaw/modulepath/AddOpens.java	Tue Apr 10 11:43:40 2018 -0700
@@ -0,0 +1,110 @@
+/*
+ * 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
+ * @requires vm.cds
+ * @library /test/jdk/lib/testlibrary /test/lib /test/hotspot/jtreg/runtime/appcds
+ * @modules jdk.compiler
+ *          jdk.jartool/sun.tools.jar
+ *          jdk.jlink
+ * @run main AddOpens
+ * @summary sanity test the --add-opens option
+ */
+
+import java.io.File;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+
+import jdk.test.lib.process.OutputAnalyzer;
+import jdk.testlibrary.ProcessTools;
+
+public class AddOpens {
+
+    private static final Path USER_DIR = Paths.get(System.getProperty("user.dir"));
+
+    private static final String TEST_SRC = System.getProperty("test.src");
+
+    private static final Path SRC_DIR = Paths.get(TEST_SRC, "src");
+    private static final Path MODS_DIR = Paths.get("mods");
+
+    // the module name of the test module
+    private static final String TEST_MODULE1 = "com.simple";
+
+    // the module main class
+    private static final String MAIN_CLASS = "com.simple.Main";
+
+    private static Path moduleDir = null;
+    private static Path moduleDir2 = null;
+    private static Path destJar = null;
+
+    public static void buildTestModule() throws Exception {
+
+        // javac -d mods/$TESTMODULE --module-path MOD_DIR src/$TESTMODULE/**
+        JarBuilder.compileModule(SRC_DIR.resolve(TEST_MODULE1),
+                                 MODS_DIR.resolve(TEST_MODULE1),
+                                 MODS_DIR.toString());
+
+        moduleDir = Files.createTempDirectory(USER_DIR, "mlib");
+        moduleDir2 = Files.createTempDirectory(USER_DIR, "mlib2");
+
+        Path srcJar = moduleDir.resolve(TEST_MODULE1 + ".jar");
+        destJar = moduleDir2.resolve(TEST_MODULE1 + ".jar");
+        String classes = MODS_DIR.resolve(TEST_MODULE1).toString();
+        JarBuilder.createModularJar(srcJar.toString(), classes, MAIN_CLASS);
+        Files.copy(srcJar, destJar);
+
+    }
+
+    public static void main(String... args) throws Exception {
+        // compile the modules and create the modular jar files
+        buildTestModule();
+        String appClasses[] = {MAIN_CLASS};
+        // create an archive with both -cp and --module-path in the command line.
+        // Only the class in the modular jar in the --module-path will be archived;
+        // the class in the modular jar in the -cp won't be archived.
+        OutputAnalyzer output = TestCommon.createArchive(
+                                        destJar.toString(), appClasses,
+                                        "-Xlog:class+load=trace", "-XX:+PrintSystemDictionaryAtExit",
+                                        "--module-path", moduleDir.toString(),
+                                        "-m", TEST_MODULE1);
+        TestCommon.checkDump(output);
+
+        // run with the archive using the same command line as in dump time
+        // plus the "--add-opens java.base/java.lang=com.simple" option.
+        // The main class should be loaded from the archive.
+        // The setaccessible(true) on the ClassLoader.defineClass method should
+        // be successful.
+        TestCommon.run( "-Xlog:class+load=trace",
+                        "-cp", destJar.toString(),
+                        "--add-opens", "java.base/java.lang=" + TEST_MODULE1,
+                        "--module-path", moduleDir.toString(),
+                        "-m", TEST_MODULE1, "with_add_opens")
+            .assertNormalExit(
+                "[class,load] com.simple.Main source: shared objects file",
+                "method.setAccessible succeeded!");
+
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/appcds/jigsaw/modulepath/AddReads.java	Tue Apr 10 11:43:40 2018 -0700
@@ -0,0 +1,143 @@
+/*
+ * 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
+ * @requires vm.cds
+ * @library /test/jdk/lib/testlibrary /test/lib /test/hotspot/jtreg/runtime/appcds
+ * @modules jdk.compiler
+ *          jdk.jartool/sun.tools.jar
+ *          jdk.jlink
+ * @run main AddReads
+ * @summary sanity test the --add-reads option
+ */
+
+import java.io.File;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+
+import jdk.test.lib.process.OutputAnalyzer;
+import jdk.testlibrary.ProcessTools;
+import jdk.testlibrary.Asserts;
+
+public class AddReads {
+
+    private static final Path USER_DIR = Paths.get(System.getProperty("user.dir"));
+
+    private static final String TEST_SRC = System.getProperty("test.src");
+
+    private static final Path SRC_DIR = Paths.get(TEST_SRC, "src");
+    private static final Path MODS_DIR = Paths.get("mods");
+
+    // the module name of the test module
+    private static final String MAIN_MODULE = "com.norequires";
+    private static final String SUB_MODULE = "org.astro";
+
+    // the module main class
+    private static final String MAIN_CLASS = "com.norequires.Main";
+    private static final String APP_CLASS = "org.astro.World";
+
+    private static Path moduleDir = null;
+    private static Path subJar = null;
+    private static Path mainJar = null;
+
+    public static void buildTestModule() throws Exception {
+
+        // javac -d mods/$TESTMODULE src/$TESTMODULE/**
+        JarBuilder.compileModule(SRC_DIR.resolve(SUB_MODULE),
+                                       MODS_DIR.resolve(SUB_MODULE),
+                                       null);
+
+        Asserts.assertTrue(CompilerUtils
+            .compile(SRC_DIR.resolve(MAIN_MODULE),
+                     MODS_DIR.resolve(MAIN_MODULE),
+                     "-cp", MODS_DIR.resolve(SUB_MODULE).toString(),
+                     "--add-reads", "com.norequires=ALL-UNNAMED"));
+
+        moduleDir = Files.createTempDirectory(USER_DIR, "mlib");
+        subJar = moduleDir.resolve(SUB_MODULE + ".jar");
+        String classes = MODS_DIR.resolve(SUB_MODULE).toString();
+        JarBuilder.createModularJar(subJar.toString(), classes, null);
+
+        mainJar = moduleDir.resolve(MAIN_MODULE + ".jar");
+        classes = MODS_DIR.resolve(MAIN_MODULE).toString();
+        JarBuilder.createModularJar(mainJar.toString(), classes, MAIN_CLASS);
+    }
+
+    public static void main(String... args) throws Exception {
+        // compile the modules and create the modular jar files
+        buildTestModule();
+        String appClasses[] = {MAIN_CLASS, APP_CLASS};
+        // create an archive with the classes in the modules built in the
+        // previous step
+        OutputAnalyzer output = TestCommon.createArchive(
+                                        null, appClasses,
+                                        "--module-path", moduleDir.toString(),
+                                        "--add-modules", SUB_MODULE,
+                                        "--add-reads", "com.norequires=org.astro",
+                                        "-m", MAIN_MODULE);
+        TestCommon.checkDump(output);
+        String prefix[] = {"-cp", "\"\"", "-Xlog:class+load=trace",
+                           "--add-modules", SUB_MODULE,
+                           "--add-reads", "com.norequires=org.astro"};
+
+        // run the com.norequires module with the archive with the same args
+        // used during dump time.
+        // The classes should be loaded from the archive.
+        TestCommon.runWithModules(prefix,
+                                  null, // --upgrade-module-path
+                                  moduleDir.toString(), // --module-path
+                                  MAIN_MODULE) // -m
+            .assertNormalExit(out -> {
+                out.shouldContain("[class,load] com.norequires.Main source: shared objects file")
+                   .shouldContain("[class,load] org.astro.World source: shared objects file");
+            });
+
+        // create an archive with -cp pointing to the jar file containing the
+        // org.astro module and --module-path pointing to the main module
+        output = TestCommon.createArchive(
+                                        subJar.toString(), appClasses,
+                                        "--module-path", moduleDir.toString(),
+                                        "--add-modules", SUB_MODULE,
+                                        "--add-reads", "com.norequires=org.astro",
+                                        "-m", MAIN_MODULE);
+        TestCommon.checkDump(output);
+        // run the com.norequires module with the archive with the sub-module
+        // in the -cp and with -add-reads=com.norequires=ALL-UNNAMED
+        // The main class should be loaded from the archive.
+        // The org.astro.World should be loaded from the jar.
+        String prefix2[] = {"-cp", subJar.toString(), "-Xlog:class+load=trace",
+                           "--add-reads", "com.norequires=ALL-UNNAMED"};
+        TestCommon.runWithModules(prefix2,
+                                  null, // --upgrade-module-path
+                                  moduleDir.toString(), // --module-path
+                                  MAIN_MODULE) // -m
+            .assertNormalExit(out -> {
+                out.shouldContain("[class,load] com.norequires.Main source: shared objects file")
+                   .shouldMatch(".class.load. org.astro.World source:.*org.astro.jar");
+            });
+
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/appcds/jigsaw/modulepath/ExportModule.java	Tue Apr 10 11:43:40 2018 -0700
@@ -0,0 +1,164 @@
+/*
+ * 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
+ * @requires vm.cds
+ * @library /test/jdk/lib/testlibrary /test/lib /test/hotspot/jtreg/runtime/appcds
+ * @modules jdk.compiler
+ *          jdk.jartool/sun.tools.jar
+ *          jdk.jlink
+ * @run main ExportModule
+ * @summary Tests involve exporting a module from the module path to a jar in the -cp.
+ */
+
+import java.io.File;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+
+import jdk.test.lib.compiler.CompilerUtils;
+import jdk.test.lib.process.OutputAnalyzer;
+import jdk.testlibrary.ProcessTools;
+import jdk.testlibrary.Asserts;
+
+public class ExportModule {
+
+    private static final Path USER_DIR = Paths.get(System.getProperty("user.dir"));
+
+    private static final String TEST_SRC = System.getProperty("test.src");
+
+    private static final Path SRC_DIR = Paths.get(TEST_SRC, "src");
+    private static final Path MODS_DIR = Paths.get("mods");
+
+    // the module name of the test module
+    private static final String TEST_MODULE1 = "com.greetings";
+    private static final String TEST_MODULE2 = "org.astro";
+
+    // unnamed module package name
+    private static final String PKG_NAME = "com.nomodule";
+
+    // the module main class
+    private static final String MAIN_CLASS = "com.greetings.Main";
+    private static final String APP_CLASS = "org.astro.World";
+
+    // unnamed module main class
+    private static final String UNNAMED_MAIN = "com.nomodule.Main";
+
+    private static Path moduleDir = null;
+    private static Path moduleDir2 = null;
+    private static Path appJar = null;
+    private static Path appJar2 = null;
+
+    public static void buildTestModule() throws Exception {
+
+        // javac -d mods/$TESTMODULE src/$TESTMODULE/**
+        JarBuilder.compileModule(SRC_DIR.resolve(TEST_MODULE2),
+                                 MODS_DIR.resolve(TEST_MODULE2),
+                                 null);
+
+        // javac -d mods/$TESTMODULE --module-path MOD_DIR src/$TESTMODULE/**
+        JarBuilder.compileModule(SRC_DIR.resolve(TEST_MODULE1),
+                                 MODS_DIR.resolve(TEST_MODULE1),
+                                 MODS_DIR.toString());
+
+        moduleDir = Files.createTempDirectory(USER_DIR, "mlib");
+        Path jar = moduleDir.resolve(TEST_MODULE2 + ".jar");
+        String classes = MODS_DIR.resolve(TEST_MODULE2).toString();
+        JarBuilder.createModularJar(jar.toString(), classes, null);
+
+        moduleDir2 = Files.createTempDirectory(USER_DIR, "mlib2");
+        appJar = moduleDir2.resolve(TEST_MODULE1 + ".jar");
+        classes = MODS_DIR.resolve(TEST_MODULE1).toString();
+        JarBuilder.createModularJar(appJar.toString(), classes, MAIN_CLASS);
+
+        // build a non-modular jar containing the main class which
+        // requires the org.astro package
+        boolean compiled
+            = CompilerUtils.compile(SRC_DIR.resolve(PKG_NAME),
+                                    MODS_DIR.resolve(PKG_NAME),
+                                    "--module-path", MODS_DIR.toString(),
+                                    "--add-modules", TEST_MODULE2,
+                                    "--add-exports", "org.astro/org.astro=ALL-UNNAMED");
+        Asserts.assertTrue(compiled, "test package did not compile");
+
+        appJar2 = moduleDir2.resolve(PKG_NAME + ".jar");
+        classes = MODS_DIR.resolve(PKG_NAME).toString();
+        JarBuilder.createModularJar(appJar2.toString(), classes, null);
+    }
+
+    public static void main(String... args) throws Exception {
+        // compile the modules and create the modular jar files
+        buildTestModule();
+        String appClasses[] = {MAIN_CLASS, APP_CLASS};
+        // create an archive with the class in the org.astro module built in the
+        // previous step and the main class from the modular jar in the -cp
+        // note: the main class is in the modular jar in the -cp which requires
+        // the module in the --module-path
+        OutputAnalyzer output = TestCommon.createArchive(
+                                        appJar.toString(), appClasses,
+                                        "-Xlog:class+load=trace", "-XX:+PrintSystemDictionaryAtExit",
+                                        "--module-path", moduleDir.toString(),
+                                        "--add-modules", TEST_MODULE2, MAIN_CLASS);
+        TestCommon.checkDump(output);
+
+        // run it using the archive
+        // both the main class and the class from the org.astro module should
+        // be loaded from the archive
+        TestCommon.run("-Xlog:class+load=trace",
+                              "-cp", appJar.toString(),
+                              "--module-path", moduleDir.toString(),
+                              "--add-modules", TEST_MODULE2, MAIN_CLASS)
+            .assertNormalExit(
+                "[class,load] org.astro.World source: shared objects file",
+                "[class,load] com.greetings.Main source: shared objects file");
+
+        String appClasses2[] = {UNNAMED_MAIN, APP_CLASS};
+        // create an archive with the main class from a non-modular jar in the
+        // -cp and the class from the org.astro module
+        // note: the org.astro package needs to be exported to "ALL-UNNAMED"
+        // module since the jar in the -cp is a non-modular jar and thus it is
+        // unnmaed.
+        output = TestCommon.createArchive(
+                                        appJar2.toString(), appClasses2,
+                                        "-Xlog:class+load=trace", "-XX:+PrintSystemDictionaryAtExit",
+                                        "--module-path", moduleDir.toString(),
+                                        "--add-modules", TEST_MODULE2,
+                                        "--add-exports", "org.astro/org.astro=ALL-UNNAMED",
+                                        UNNAMED_MAIN);
+        TestCommon.checkDump(output);
+
+        // both the main class and the class from the org.astro module should
+        // be loaded from the archive
+        TestCommon.run("-Xlog:class+load=trace",
+                       "-cp", appJar2.toString(),
+                       "--module-path", moduleDir.toString(),
+                       "--add-modules", TEST_MODULE2,
+                       "--add-exports", "org.astro/org.astro=ALL-UNNAMED",
+                       UNNAMED_MAIN)
+            .assertNormalExit(
+                "[class,load] org.astro.World source: shared objects file",
+                "[class,load] com.nomodule.Main source: shared objects file");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/appcds/jigsaw/modulepath/JvmtiAddPath.java	Tue Apr 10 11:43:40 2018 -0700
@@ -0,0 +1,156 @@
+/*
+ * 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 JvmtiEnv::AddToBootstrapClassLoaderSearch and JvmtiEnv::AddToSystemClassLoaderSearch should disable AppCDS
+ * @requires vm.cds
+ * @library /test/jdk/lib/testlibrary /test/lib /test/hotspot/jtreg/runtime/appcds
+ * @modules java.base/jdk.internal.misc
+ *          java.management
+ *          jdk.jartool/sun.tools.jar
+ * @build sun.hotspot.WhiteBox
+ * @run driver ClassFileInstaller sun.hotspot.WhiteBox
+ * @compile ../../test-classes/JvmtiApp.java
+ * @run main JvmtiAddPath
+ */
+
+import java.io.File;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import jdk.test.lib.process.OutputAnalyzer;
+import sun.hotspot.WhiteBox;
+
+public class JvmtiAddPath {
+    static String use_whitebox_jar;
+    static String[] no_extra_matches = {};
+    static String[] check_appcds_enabled = {
+        "[class,load] ExtraClass source: shared object"
+    };
+    static String[] check_appcds_disabled = {
+        "[class,load] ExtraClass source: file:"
+    };
+
+    private static final Path USER_DIR = Paths.get(System.getProperty("user.dir"));
+
+    private static final String TEST_SRC = System.getProperty("test.src");
+
+    private static final Path SRC_DIR = Paths.get(TEST_SRC, "src");
+    private static final Path MODS_DIR = Paths.get("mods");
+
+    // the module name of the test module
+    private static final String TEST_MODULE1 = "com.simple";
+
+    // the module main class
+    private static final String MAIN_CLASS = "com.simple.Main";
+
+    private static Path moduleDir = null;
+    private static Path mainJar = null;
+
+    public static void buildTestModule() throws Exception {
+
+        // javac -d mods/$TESTMODULE --module-path MOD_DIR src/$TESTMODULE/**
+        JarBuilder.compileModule(SRC_DIR.resolve(TEST_MODULE1),
+                                 MODS_DIR.resolve(TEST_MODULE1),
+                                 MODS_DIR.toString());
+
+        moduleDir = Files.createTempDirectory(USER_DIR, "mlib");
+
+        mainJar = moduleDir.resolve(TEST_MODULE1 + ".jar");
+        String classes = MODS_DIR.resolve(TEST_MODULE1).toString();
+        JarBuilder.createModularJar(mainJar.toString(), classes, MAIN_CLASS);
+    }
+
+    static void run(String cp, String... args) throws Exception {
+        run(no_extra_matches, cp, args);
+    }
+
+    static void run(String[] extra_matches, String cp, String... args) throws Exception {
+        String[] opts = {"-cp", cp, "-XX:+UnlockDiagnosticVMOptions", "-XX:+WhiteBoxAPI", use_whitebox_jar};
+        opts = TestCommon.concat(opts, args);
+        TestCommon.run(opts).assertNormalExit(extra_matches);
+    }
+
+    public static void main(String[] args) throws Exception {
+        buildTestModule();
+        JarBuilder.build("jvmti_app", "JvmtiApp", "ExtraClass");
+        JarBuilder.build(true, "WhiteBox", "sun/hotspot/WhiteBox");
+
+        // In all the test cases below, appJar does not contain Hello.class. Instead, we
+        // append JAR file(s) that contain Hello.class to the boot classpath, the app
+        // classpath, or both, and verify that Hello.class is loaded by the expected ClassLoader.
+        String appJar = TestCommon.getTestJar("jvmti_app.jar");         // contains JvmtiApp.class
+        String addappJar = mainJar.toString();  // contains Main.class
+        String addbootJar = mainJar.toString(); // contains Main.class
+        String twoAppJars = appJar + File.pathSeparator + addappJar;
+        String modulePath = "--module-path=" + moduleDir.toString();
+        String wbJar = TestCommon.getTestJar("WhiteBox.jar");
+        use_whitebox_jar = "-Xbootclasspath/a:" + wbJar;
+
+        OutputAnalyzer output = TestCommon.createArchive(
+                                    appJar,
+                                    TestCommon.list("JvmtiApp", "ExtraClass", MAIN_CLASS),
+                                    use_whitebox_jar,
+                                    "-Xlog:class+load=trace",
+                                    modulePath);
+        TestCommon.checkDump(output);
+
+        System.out.println("Test case 1: not adding module path - Hello.class should not be found");
+        run(check_appcds_enabled, appJar,
+            "-Xlog:class+load", "JvmtiApp", "noadd", MAIN_CLASS); // appcds should be enabled
+
+        System.out.println("Test case 2: add to boot classpath only - should find Hello.class in boot loader");
+        run(check_appcds_disabled, appJar,
+            "-Xlog:class+load=trace",
+            modulePath,
+            "JvmtiApp", "bootonly", addbootJar, MAIN_CLASS); // appcds should be disabled
+
+        System.out.println("Test case 3: add to app classpath only - should find Hello.class in app loader");
+        run(appJar, modulePath,
+            "JvmtiApp", "apponly", addappJar, MAIN_CLASS);
+
+        System.out.println("Test case 4: add to boot and app paths - should find Hello.class in boot loader");
+        run(appJar, modulePath,
+            "JvmtiApp", "appandboot", addbootJar, addappJar, MAIN_CLASS);
+
+        System.out.println("Test case 5: add to app using -cp, but add to boot using JVMTI - should find Hello.class in boot loader");
+        run(appJar, modulePath,
+            "JvmtiApp", "bootonly", addappJar, MAIN_CLASS);
+
+        System.out.println("Test case 6: add to app using AppCDS, but add to boot using JVMTI - should find Hello.class in boot loader");
+        output = TestCommon.createArchive(
+                     appJar, TestCommon.list("JvmtiApp", "ExtraClass"),
+                     use_whitebox_jar,
+                     "-Xlog:class+load=trace",
+                     modulePath);
+        TestCommon.checkDump(output);
+        run(twoAppJars, modulePath,
+            "JvmtiApp", "bootonly", addappJar, MAIN_CLASS);
+
+        System.out.println("Test case 7: add to app using AppCDS, no JVMTI calls - should find Hello.class in app loader");
+        run(twoAppJars, modulePath,
+            "JvmtiApp", "noadd-appcds", MAIN_CLASS);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/appcds/jigsaw/modulepath/MainModuleOnly.java	Tue Apr 10 11:43:40 2018 -0700
@@ -0,0 +1,177 @@
+/*
+ * 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
+ * @requires vm.cds
+ * @library /test/jdk/lib/testlibrary /test/lib /test/hotspot/jtreg/runtime/appcds
+ * @modules jdk.compiler
+ *          jdk.jartool/sun.tools.jar
+ *          jdk.jlink
+ * @run main MainModuleOnly
+ * @summary Test some scenarios with a main modular jar specified in the --module-path and -cp options in the command line.
+ */
+
+import java.io.File;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+
+import jdk.test.lib.process.OutputAnalyzer;
+import jdk.testlibrary.ProcessTools;
+
+public class MainModuleOnly {
+
+    private static final Path USER_DIR = Paths.get(System.getProperty("user.dir"));
+
+    private static final String TEST_SRC = System.getProperty("test.src");
+
+    private static final Path SRC_DIR = Paths.get(TEST_SRC, "src");
+    private static final Path MODS_DIR = Paths.get("mods");
+
+    // the module name of the test module
+    private static final String TEST_MODULE1 = "com.simple";
+
+    // the module main class
+    private static final String MAIN_CLASS = "com.simple.Main";
+
+    private static Path moduleDir = null;
+    private static Path moduleDir2 = null;
+    private static Path destJar = null;
+
+    public static void buildTestModule() throws Exception {
+
+        // javac -d mods/$TESTMODULE --module-path MOD_DIR src/$TESTMODULE/**
+        JarBuilder.compileModule(SRC_DIR.resolve(TEST_MODULE1),
+                                 MODS_DIR.resolve(TEST_MODULE1),
+                                 MODS_DIR.toString());
+
+
+        moduleDir = Files.createTempDirectory(USER_DIR, "mlib");
+        moduleDir2 = Files.createTempDirectory(USER_DIR, "mlib2");
+
+        Path srcJar = moduleDir.resolve(TEST_MODULE1 + ".jar");
+        destJar = moduleDir2.resolve(TEST_MODULE1 + ".jar");
+        String classes = MODS_DIR.resolve(TEST_MODULE1).toString();
+        JarBuilder.createModularJar(srcJar.toString(), classes, MAIN_CLASS);
+        Files.copy(srcJar, destJar);
+
+    }
+
+    public static void main(String... args) throws Exception {
+        // compile the modules and create the modular jar files
+        buildTestModule();
+        String appClasses[] = {MAIN_CLASS};
+        // create an archive with both -cp and --module-path in the command line.
+        // Only the class in the modular jar in the --module-path will be archived;
+        // the class in the modular jar in the -cp won't be archived.
+        OutputAnalyzer output = TestCommon.createArchive(
+                                        destJar.toString(), appClasses,
+                                        "-Xlog:class+load=trace", "-XX:+PrintSystemDictionaryAtExit",
+                                        "--module-path", moduleDir.toString(),
+                                        "-m", TEST_MODULE1);
+        TestCommon.checkDump(output);
+
+        // run with the archive using the same command line as in dump time.
+        // The main class should be loaded from the archive.
+        TestCommon.run("-Xlog:class+load=trace",
+                       "-cp", destJar.toString(),
+                       "--module-path", moduleDir.toString(),
+                       "-m", TEST_MODULE1)
+            .assertNormalExit("[class,load] com.simple.Main source: shared objects file");
+
+        // run with the archive with the main class name inserted before the -m.
+        // The main class name will be picked up before the module name. So the
+        // main class should be loaded from the jar in the -cp.
+        TestCommon.run("-Xlog:class+load=trace",
+                       "-cp", destJar.toString(),
+                       "--module-path", moduleDir.toString(),
+                       MAIN_CLASS, "-m", TEST_MODULE1)
+            .assertNormalExit(out ->
+                out.shouldMatch(".class.load. com.simple.Main source:.*com.simple.jar"));
+
+        // run with the archive with exploded module. Since during dump time, we
+        // only archive classes from the modular jar in the --module-path, the
+        // main class should be loaded from the exploded module directory.
+        TestCommon.run("-Xlog:class+load=trace",
+                       "-cp", destJar.toString(),
+                       "--module-path", MODS_DIR.toString(),
+                       "-m", TEST_MODULE1 + "/" + MAIN_CLASS)
+            .assertNormalExit(out -> {
+                out.shouldMatch(".class.load. com.simple.Main source:.*com.simple")
+                   .shouldContain(MODS_DIR.toString());
+            });
+
+        // run with the archive with the --upgrade-module-path option.
+        // CDS will be disabled with this options and the main class will be
+        // loaded from the modular jar.
+        TestCommon.run("-Xlog:class+load=trace",
+                       "-cp", destJar.toString(),
+                       "--upgrade-module-path", moduleDir.toString(),
+                       "--module-path", moduleDir.toString(),
+                       "-m", TEST_MODULE1)
+            .assertSilentlyDisabledCDS(out -> {
+                out.shouldHaveExitValue(0)
+                   .shouldMatch("CDS is disabled when the.*option is specified")
+                   .shouldMatch(".class.load. com.simple.Main source:.*com.simple.jar");
+            });
+        // run with the archive with the --limit-modules option.
+        // CDS will be disabled with this options and the main class will be
+        // loaded from the modular jar.
+        TestCommon.run("-Xlog:class+load=trace",
+                       "-cp", destJar.toString(),
+                       "--limit-modules", "java.base," + TEST_MODULE1,
+                       "--module-path", moduleDir.toString(),
+                       "-m", TEST_MODULE1)
+            .assertSilentlyDisabledCDS(out -> {
+                out.shouldHaveExitValue(0)
+                   .shouldMatch("CDS is disabled when the.*option is specified")
+                   .shouldMatch(".class.load. com.simple.Main source:.*com.simple.jar");
+            });
+        // run with the archive with the --patch-module option.
+        // CDS will be disabled with this options and the main class will be
+        // loaded from the modular jar.
+        TestCommon.run("-Xlog:class+load=trace",
+                       "-cp", destJar.toString(),
+                       "--patch-module", TEST_MODULE1 + "=" + MODS_DIR.toString(),
+                       "--module-path", moduleDir.toString(),
+                       "-m", TEST_MODULE1)
+            .assertSilentlyDisabledCDS(out -> {
+                out.shouldHaveExitValue(0)
+                   .shouldMatch("CDS is disabled when the.*option is specified")
+                   .shouldMatch(".class.load. com.simple.Main source:.*com.simple.jar");
+            });
+        // modify the timestamp of the jar file
+        (new File(destJar.toString())).setLastModified(System.currentTimeMillis() + 2000);
+        // run with the archive and the jar with modified timestamp.
+        // It should fail due to timestamp of the jar doesn't match the one
+        // used during dump time.
+        TestCommon.run("-Xlog:class+load=trace",
+                       "-cp", destJar.toString(),
+                       "--module-path", moduleDir.toString(),
+                       "-m", TEST_MODULE1)
+            .assertAbnormalExit(
+                "A jar/jimage file is not the one used while building the shared archive file:");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/appcds/jigsaw/modulepath/ModulePathAndCP.java	Tue Apr 10 11:43:40 2018 -0700
@@ -0,0 +1,186 @@
+/*
+ * 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
+ * @requires vm.cds
+ * @library /test/jdk/lib/testlibrary /test/lib /test/hotspot/jtreg/runtime/appcds
+ * @modules jdk.compiler
+ *          jdk.jartool/sun.tools.jar
+ *          jdk.jlink
+ * @run main ModulePathAndCP
+ * @summary 2 sets of tests: one with only --module-path in the command line;
+ *          another with both -cp and --module-path in the command line.
+ */
+
+import java.io.File;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+
+import jdk.test.lib.process.OutputAnalyzer;
+import jdk.testlibrary.ProcessTools;
+
+public class ModulePathAndCP {
+
+    private static final Path USER_DIR = Paths.get(System.getProperty("user.dir"));
+
+    private static final String TEST_SRC = System.getProperty("test.src");
+
+    private static final Path SRC_DIR = Paths.get(TEST_SRC, "src");
+    private static final Path MODS_DIR = Paths.get("mods");
+
+    // the module name of the test module
+    private static final String MAIN_MODULE = "com.greetings";
+    private static final String APP_MODULE = "org.astro";
+
+    // the module main class
+    private static final String MAIN_CLASS = "com.greetings.Main";
+    private static final String APP_CLASS = "org.astro.World";
+
+    private static Path moduleDir = null;
+    private static Path moduleDir2 = null;
+    private static Path subJar = null;
+    private static Path mainJar = null;
+    private static Path destJar = null;
+
+    public static void buildTestModule() throws Exception {
+
+        // javac -d mods/$TESTMODULE src/$TESTMODULE/**
+        JarBuilder.compileModule(SRC_DIR.resolve(APP_MODULE),
+                                 MODS_DIR.resolve(APP_MODULE),
+                                 null);
+
+        // javac -d mods/$TESTMODULE --module-path MOD_DIR src/$TESTMODULE/**
+        JarBuilder.compileModule(SRC_DIR.resolve(MAIN_MODULE),
+                                 MODS_DIR.resolve(MAIN_MODULE),
+                                 MODS_DIR.toString());
+
+        moduleDir = Files.createTempDirectory(USER_DIR, "mlib");
+        moduleDir2 = Files.createTempDirectory(USER_DIR, "mlib2");
+        subJar = moduleDir.resolve(APP_MODULE + ".jar");
+        destJar = moduleDir2.resolve(APP_MODULE + ".jar");
+        String classes = MODS_DIR.resolve(APP_MODULE).toString();
+        JarBuilder.createModularJar(subJar.toString(), classes, null);
+        Files.copy(subJar, destJar);
+
+        mainJar = moduleDir.resolve(MAIN_MODULE + ".jar");
+        Path mainJar2 = moduleDir2.resolve(MAIN_MODULE + ".jar");
+        classes = MODS_DIR.resolve(MAIN_MODULE).toString();
+        JarBuilder.createModularJar(mainJar.toString(), classes, MAIN_CLASS);
+        Files.copy(mainJar, mainJar2);
+
+    }
+
+    public static void main(String... args) throws Exception {
+        // compile the modules and create the modular jar files
+        buildTestModule();
+        String appClasses[] = {MAIN_CLASS, APP_CLASS};
+        // create an archive with the classes in the modules built in the
+        // previous step
+        OutputAnalyzer output = TestCommon.createArchive(
+                                        null, appClasses,
+                                        "--module-path", moduleDir.toString(),
+                                        "-m", MAIN_MODULE);
+        TestCommon.checkDump(output);
+        String prefix[] = {"-cp", "\"\"", "-Xlog:class+load=trace"};
+
+        // run with the archive with the --module-path the same as the one during
+        // dump time. The classes should be loaded from the archive.
+        TestCommon.runWithModules(prefix,
+                                  null, // --upgrade-module-path
+                                  moduleDir.toString(), // --module-path
+                                  MAIN_MODULE) // -m
+            .assertNormalExit(out -> {
+                out.shouldContain("[class,load] com.greetings.Main source: shared objects file")
+                   .shouldContain("[class,load] org.astro.World source: shared objects file");
+            });
+
+        // run with the archive with the --module-path different from the one during
+        // dump time. The classes should be loaded from the jar files.
+        TestCommon.runWithModules(prefix,
+                                  null, // --upgrade-module-path
+                                  moduleDir2.toString(), // --module-path
+                                  MAIN_MODULE) // -m
+            .assertNormalExit(out -> {
+                out.shouldMatch(".class.load. com.greetings.Main source:.*com.greetings.jar")
+                   .shouldMatch(".class.load. org.astro.World source:.*org.astro.jar");
+            });
+
+        // create an archive with modular jar files in both -cp and --module-path
+        String jars = subJar.toString() + System.getProperty("path.separator") +
+                      mainJar.toString();
+        output = TestCommon.createArchive( jars, appClasses,
+                                           "-Xlog:class+load=trace", "-XX:+PrintSystemDictionaryAtExit",
+                                           "--module-path", moduleDir.toString(),
+                                           "-m", MAIN_MODULE);
+        TestCommon.checkDump(output);
+
+        // run with archive with the main class name specified before
+        // the module name with the -m option. Since the -m option was specified
+        // during dump time, the classes in the jar files after the -cp won't be
+        // archived. Therefore, the classes won't be loaded from the archive but
+        // will be loaded from the jar files.
+        TestCommon.run("-Xlog:class+load=trace",
+                       "-cp", jars,
+                       "--module-path", moduleDir.toString(),
+                       MAIN_CLASS, "-m", MAIN_MODULE)
+            .assertNormalExit(out -> {
+                out.shouldMatch(".class.load. com.greetings.Main source:.*com.greetings.jar")
+                   .shouldMatch(".class.load. org.astro.World source:.*org.astro.jar");
+            });
+
+        // similar to the above case but without the main class name. The classes
+        // should be loaded from the archive.
+        TestCommon.run("-Xlog:class+load=trace",
+                       "-cp", jars,
+                       "--module-path", moduleDir.toString(),
+                       "-m", MAIN_MODULE)
+            .assertNormalExit(
+              "[class,load] com.greetings.Main source: shared objects file",
+              "[class,load] org.astro.World source: shared objects file");
+
+        // create an archive with two modular jars in the --module-path
+        output = TestCommon.createArchive(
+                                        null, appClasses,
+                                        "--module-path", jars,
+                                        "-m", MAIN_MODULE);
+        TestCommon.checkDump(output);
+
+        // run with the above archive but with the modular jar containing the
+        // org.astro module in a different location.
+        // The org.astro.World class should be loaded from the jar.
+        // The Main class should still be loaded from the archive.
+        jars = destJar.toString() + System.getProperty("path.separator") +
+                      mainJar.toString();
+        TestCommon.runWithModules(prefix,
+                                  null, // --upgrade-module-path
+                                  jars, // --module-path
+                                  MAIN_MODULE) // -m
+            .assertNormalExit(out -> {
+                out.shouldContain("[class,load] com.greetings.Main source: shared objects file")
+                   .shouldMatch(".class.load. org.astro.World source:.*org.astro.jar");
+            });
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/appcds/jigsaw/modulepath/src/com.greetings/com/greetings/Main.java	Tue Apr 10 11:43:40 2018 -0700
@@ -0,0 +1,31 @@
+/*
+ * 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.
+ *
+ */
+
+package com.greetings;
+import org.astro.World;
+public class Main {
+    public static void main(String[] args) {
+        System.out.format("Greetings %s!\n", World.name());
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/appcds/jigsaw/modulepath/src/com.greetings/module-info.java	Tue Apr 10 11:43:40 2018 -0700
@@ -0,0 +1,27 @@
+/*
+ * 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.
+ *
+ */
+
+module com.greetings {
+    requires org.astro;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/appcds/jigsaw/modulepath/src/com.hello/com/hello/Main.java	Tue Apr 10 11:43:40 2018 -0700
@@ -0,0 +1,31 @@
+/*
+ * 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.
+ *
+ */
+
+package com.hello;
+import org.astro.World;
+public class Main {
+    public static void main(String[] args) {
+        System.out.format("Hello %s!\n", World.name());
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/appcds/jigsaw/modulepath/src/com.hello/module-info.java	Tue Apr 10 11:43:40 2018 -0700
@@ -0,0 +1,27 @@
+/*
+ * 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.
+ *
+ */
+
+module com.hello {
+    requires org.astro;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/appcds/jigsaw/modulepath/src/com.nomodule/com/nomodule/Main.java	Tue Apr 10 11:43:40 2018 -0700
@@ -0,0 +1,31 @@
+/*
+ * 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.
+ *
+ */
+
+package com.nomodule;
+import org.astro.World;
+public class Main {
+    public static void main(String[] args) {
+        System.out.format("Greetings %s!\n", World.name());
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/appcds/jigsaw/modulepath/src/com.norequires/com/norequires/Main.java	Tue Apr 10 11:43:40 2018 -0700
@@ -0,0 +1,31 @@
+/*
+ * 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.
+ *
+ */
+
+package com.norequires;
+import org.astro.World;
+public class Main {
+    public static void main(String[] args) {
+        System.out.format("Hello %s!\n", World.name());
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/appcds/jigsaw/modulepath/src/com.norequires/module-info.java	Tue Apr 10 11:43:40 2018 -0700
@@ -0,0 +1,25 @@
+/*
+ * 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.
+ *
+ */
+
+module com.norequires { }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/appcds/jigsaw/modulepath/src/com.simple/com/simple/Main.java	Tue Apr 10 11:43:40 2018 -0700
@@ -0,0 +1,39 @@
+/*
+ * 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.
+ *
+ */
+
+package com.simple;
+
+import java.lang.reflect.Method;
+
+public class Main {
+    public static void main(String[] args) throws Exception {
+        System.out.println("Hello World!");
+        if (args.length > 0 && args[0].equals("with_add_opens")) {
+            Method method = ClassLoader.class.getDeclaredMethod("defineClass",
+                byte[].class, int.class, int.class);
+            method.setAccessible(true);
+            System.out.println("method.setAccessible succeeded!");
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/appcds/jigsaw/modulepath/src/com.simple/module-info.java	Tue Apr 10 11:43:40 2018 -0700
@@ -0,0 +1,26 @@
+/*
+ * 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.
+ *
+ */
+
+module com.simple {
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/appcds/jigsaw/modulepath/src/org.astro/module-info.java	Tue Apr 10 11:43:40 2018 -0700
@@ -0,0 +1,27 @@
+/*
+ * 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.
+ *
+ */
+
+module org.astro {
+    exports org.astro;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/appcds/jigsaw/modulepath/src/org.astro/org/astro/World.java	Tue Apr 10 11:43:40 2018 -0700
@@ -0,0 +1,30 @@
+/*
+ * 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.
+ *
+ */
+
+package org.astro;
+public class World {
+    public static String name() {
+        return "world";
+    }
+}
--- a/test/hotspot/jtreg/runtime/appcds/test-classes/JvmtiApp.java	Tue Apr 10 10:06:42 2018 -0400
+++ b/test/hotspot/jtreg/runtime/appcds/test-classes/JvmtiApp.java	Tue Apr 10 11:43:40 2018 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 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
@@ -25,9 +25,9 @@
 import sun.hotspot.WhiteBox;
 
 public class JvmtiApp {
-    static Class forname() {
+    static Class forname(String cn) {
         try {
-            return Class.forName("Hello");
+            return Class.forName(cn);
         } catch (Throwable t) {
             return null;
         }
@@ -40,9 +40,14 @@
 
     // See ../JvmtiAddPath.java for how the classpaths are configured.
     public static void main(String args[]) {
+        String cn = "Hello";
+        if (args.length >= 3) {
+            cn = args[args.length - 1];
+        }
+
         if (args[0].equals("noadd")) {
-            if (forname() != null) {
-                failed("Hello class was loaded unexpectedly");
+            if (forname(cn) != null) {
+                failed(cn + " class was loaded unexpectedly");
             }
             // We use -verbose:class to verify that Extra.class IS loaded by AppCDS if
             // the boot classpath HAS NOT been appended.
@@ -54,39 +59,41 @@
 
         if (args[0].equals("bootonly")) {
             wb.addToBootstrapClassLoaderSearch(args[1]);
-            Class cls = forname();
+            Class cls = forname(cn);
             if (cls == null) {
-                failed("Cannot find Hello class");
+                failed("Cannot find " + cn + " class");
             }
             if (cls.getClassLoader() != null) {
                 failed("Hello class not loaded by boot classloader");
             }
         } else if (args[0].equals("apponly")) {
             wb.addToSystemClassLoaderSearch(args[1]);
-            Class cls = forname();
+            Class cls = forname(cn);
             if (cls == null) {
-                failed("Cannot find Hello class");
+                failed("Cannot find " + cn + " class");
             }
             if (cls.getClassLoader() != JvmtiApp.class.getClassLoader()) {
-                failed("Hello class not loaded by app classloader");
+                failed(cn + " class not loaded by app classloader");
             }
         } else if (args[0].equals("noadd-appcds")) {
-            Class cls = forname();
+            cn = (args.length == 1) ? "Hello" : args[1];
+            Class cls = forname(cn);
             if (cls == null) {
-                failed("Cannot find Hello class");
+                failed("Cannot find " + cn + " class");
             }
             if (cls.getClassLoader() != JvmtiApp.class.getClassLoader()) {
-                failed("Hello class not loaded by app classloader");
+                failed(cn + " class not loaded by app classloader");
             }
         } else if (args[0].equals("appandboot")) {
             wb.addToBootstrapClassLoaderSearch(args[1]);
             wb.addToSystemClassLoaderSearch(args[2]);
-            Class cls = forname();
+            cn = (args.length == 3) ? "Hello" : args[3];
+            Class cls = forname(cn);
             if (cls == null) {
-                failed("Cannot find Hello class");
+                failed("Cannot find " + cn + " class");
             }
             if (cls.getClassLoader() != null) {
-                failed("Hello class not loaded by boot classloader");
+                failed(cn + " class not loaded by boot classloader");
             }
         } else {
             failed("unknown option " + args[0]);
@@ -102,4 +109,4 @@
 
 class ExtraClass {
     static void doit() {}
-}
\ No newline at end of file
+}
--- a/test/hotspot/jtreg/runtime/modules/PatchModule/PatchModuleCDS.java	Tue Apr 10 10:06:42 2018 -0400
+++ b/test/hotspot/jtreg/runtime/modules/PatchModule/PatchModuleCDS.java	Tue Apr 10 11:43:40 2018 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 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
@@ -50,7 +50,8 @@
             "-Xlog:class+path=info",
             "-version");
         new OutputAnalyzer(pb.start())
-            .shouldContain("ro  space:"); // Make sure archive got created.
+            // --patch-module is not supported during CDS dumping
+            .shouldContain("Cannot use the following option when dumping the shared archive: --patch-module");
 
         // Case 2: Test that directory in --patch-module is supported for CDS dumping
         // Create a class file in the module java.base.
@@ -73,7 +74,8 @@
             "-Xlog:class+path=info",
             "-version");
         new OutputAnalyzer(pb.start())
-            .shouldContain("ro  space:"); // Make sure archive got created.
+            // --patch-module is not supported during CDS dumping
+            .shouldContain("Cannot use the following option when dumping the shared archive: --patch-module");
 
         // Case 3a: Test CDS dumping with jar file in --patch-module
         BasicJarBuilder.build("javanaming", "javax/naming/spi/NamingManager");
@@ -87,7 +89,8 @@
             "-Xlog:class+path=info",
             "PatchModuleMain", "javax.naming.spi.NamingManager");
         new OutputAnalyzer(pb.start())
-            .shouldContain("ro  space:"); // Make sure archive got created.
+            // --patch-module is not supported during CDS dumping
+            .shouldContain("Cannot use the following option when dumping the shared archive: --patch-module");
 
         // Case 3b: Test CDS run with jar file in --patch-module
         pb = ProcessTools.createJavaProcessBuilder(
--- a/test/lib/jdk/test/lib/cds/CDSTestUtils.java	Tue Apr 10 10:06:42 2018 -0400
+++ b/test/lib/jdk/test/lib/cds/CDSTestUtils.java	Tue Apr 10 11:43:40 2018 -0700
@@ -117,6 +117,7 @@
         private final boolean hasMappingFailure;
         private final boolean hasAbnormalExit;
         private final boolean hasNormalExit;
+        private final String CDS_DISABLED = "warning: CDS is disabled when the";
 
         public Result(CDSOptions opts, OutputAnalyzer out) throws Exception {
             options = opts;
@@ -126,7 +127,9 @@
             hasNormalExit     = (!hasMappingFailure) && (output.getExitValue() == 0);
 
             if (hasNormalExit) {
-                if ("on".equals(options.xShareMode) && output.getStderr().contains("java version")) {
+                if ("on".equals(options.xShareMode) &&
+                    output.getStderr().contains("java version") &&
+                    !output.getStderr().contains(CDS_DISABLED)) {
                     // "-showversion" is always passed in the command-line by the execXXX methods.
                     // During normal exit, we require that the VM to show that sharing was enabled.
                     output.shouldContain("sharing");
@@ -150,6 +153,26 @@
             return this;
         }
 
+        // When {--limit-modules, --patch-module, and/or --upgrade-module-path}
+        // are specified, CDS is silently disabled for both -Xshare:auto and -Xshare:on.
+        public Result assertSilentlyDisabledCDS(Checker checker) throws Exception {
+            if (hasMappingFailure) {
+                throw new RuntimeException("Unexpected mapping failure");
+            }
+            // this comes from a JVM warning message.
+            output.shouldContain(CDS_DISABLED);
+
+            checker.check(output);
+            return this;
+        }
+
+        public Result assertSilentlyDisabledCDS(int exitCode, String... matches) throws Exception {
+            return assertSilentlyDisabledCDS((out) -> {
+                out.shouldHaveExitValue(exitCode);
+                checkMatches(out, matches);
+                   });
+        }
+
         public Result ifNormalExit(Checker checker) throws Exception {
             if (hasNormalExit) {
                 checker.check(output);