changeset 54927:1512d88b24c6

8207812: Implement Dynamic CDS Archive Summary: Improve the usability of AppCDS Reviewed-by: acorn, jiangli, mseledtsov Contributed-by: ioi.lam@oracle.com, jianglizhou@google.com, calvin.cheung@oracle.com
author ccheung
date Fri, 17 May 2019 08:29:55 -0700
parents d4e7ccaf1445
children fe4c2de90b59
files make/hotspot/lib/JvmFeatures.gmk src/hotspot/share/classfile/classListParser.cpp src/hotspot/share/classfile/classLoader.cpp src/hotspot/share/classfile/classLoader.hpp src/hotspot/share/classfile/classLoader.inline.hpp src/hotspot/share/classfile/classLoaderExt.cpp src/hotspot/share/classfile/compactHashtable.cpp src/hotspot/share/classfile/compactHashtable.hpp src/hotspot/share/classfile/dictionary.cpp src/hotspot/share/classfile/klassFactory.cpp src/hotspot/share/classfile/sharedPathsMiscInfo.cpp src/hotspot/share/classfile/sharedPathsMiscInfo.hpp src/hotspot/share/classfile/stringTable.cpp src/hotspot/share/classfile/symbolTable.cpp src/hotspot/share/classfile/symbolTable.hpp src/hotspot/share/classfile/systemDictionaryShared.cpp src/hotspot/share/classfile/systemDictionaryShared.hpp src/hotspot/share/classfile/verificationType.cpp src/hotspot/share/include/cds.h src/hotspot/share/jfr/recorder/jfrRecorder.cpp src/hotspot/share/logging/logTag.hpp src/hotspot/share/memory/allocation.hpp src/hotspot/share/memory/dynamicArchive.cpp src/hotspot/share/memory/dynamicArchive.hpp src/hotspot/share/memory/filemap.cpp src/hotspot/share/memory/filemap.hpp src/hotspot/share/memory/heapShared.cpp src/hotspot/share/memory/heapShared.hpp src/hotspot/share/memory/memRegion.cpp src/hotspot/share/memory/metaspace.cpp src/hotspot/share/memory/metaspaceClosure.cpp src/hotspot/share/memory/metaspaceClosure.hpp src/hotspot/share/memory/metaspaceShared.cpp src/hotspot/share/memory/metaspaceShared.hpp src/hotspot/share/memory/universe.cpp src/hotspot/share/oops/constMethod.hpp src/hotspot/share/oops/constantPool.cpp src/hotspot/share/oops/cpCache.cpp src/hotspot/share/oops/instanceKlass.cpp src/hotspot/share/oops/klass.cpp src/hotspot/share/oops/method.cpp src/hotspot/share/oops/method.hpp src/hotspot/share/oops/symbol.cpp src/hotspot/share/oops/symbol.hpp src/hotspot/share/prims/cdsoffsets.cpp src/hotspot/share/prims/whitebox.cpp src/hotspot/share/runtime/arguments.cpp src/hotspot/share/runtime/arguments.hpp src/hotspot/share/runtime/globals.hpp src/hotspot/share/runtime/java.cpp src/hotspot/share/runtime/mutexLocker.cpp src/hotspot/share/runtime/mutexLocker.hpp src/hotspot/share/runtime/thread.cpp test/hotspot/jtreg/TEST.groups test/hotspot/jtreg/runtime/appcds/AppendClasspath.java test/hotspot/jtreg/runtime/appcds/BootClassPathMismatch.java test/hotspot/jtreg/runtime/appcds/CDSandJFR.java test/hotspot/jtreg/runtime/appcds/CaseSensitiveClassPath.java test/hotspot/jtreg/runtime/appcds/CommandLineFlagCombo.java test/hotspot/jtreg/runtime/appcds/CommandLineFlagComboNegative.java test/hotspot/jtreg/runtime/appcds/DirClasspathTest.java test/hotspot/jtreg/runtime/appcds/JvmtiAddPath.java test/hotspot/jtreg/runtime/appcds/LotsOfClasses.java test/hotspot/jtreg/runtime/appcds/PackageSealing.java test/hotspot/jtreg/runtime/appcds/ProhibitedPackage.java test/hotspot/jtreg/runtime/appcds/SharedArchiveConsistency.java test/hotspot/jtreg/runtime/appcds/TestCommon.java test/hotspot/jtreg/runtime/appcds/TraceLongClasspath.java test/hotspot/jtreg/runtime/appcds/WrongClasspath.java test/hotspot/jtreg/runtime/appcds/cdsutils/DynamicDumpHelper.java test/hotspot/jtreg/runtime/appcds/customLoader/ClassListFormatA.java test/hotspot/jtreg/runtime/appcds/customLoader/ClassListFormatB.java test/hotspot/jtreg/runtime/appcds/customLoader/ClassListFormatBase.java test/hotspot/jtreg/runtime/appcds/customLoader/ClassListFormatC.java test/hotspot/jtreg/runtime/appcds/customLoader/ClassListFormatD.java test/hotspot/jtreg/runtime/appcds/customLoader/ClassListFormatE.java test/hotspot/jtreg/runtime/appcds/customLoader/HelloCustom.java test/hotspot/jtreg/runtime/appcds/customLoader/HelloCustom_JFR.java test/hotspot/jtreg/runtime/appcds/customLoader/ProhibitedPackageNamesTest.java test/hotspot/jtreg/runtime/appcds/customLoader/test-classes/HelloUnload.java test/hotspot/jtreg/runtime/appcds/dynamicArchive/AppendClasspath.java test/hotspot/jtreg/runtime/appcds/dynamicArchive/ArchiveConsistency.java test/hotspot/jtreg/runtime/appcds/dynamicArchive/ArrayKlasses.java test/hotspot/jtreg/runtime/appcds/dynamicArchive/ClassResolutionFailure.java test/hotspot/jtreg/runtime/appcds/dynamicArchive/DynamicArchiveTestBase.java test/hotspot/jtreg/runtime/appcds/dynamicArchive/DynamicFlag.java test/hotspot/jtreg/runtime/appcds/dynamicArchive/DynamicLotsOfClasses.java test/hotspot/jtreg/runtime/appcds/dynamicArchive/ExcludedClasses.java test/hotspot/jtreg/runtime/appcds/dynamicArchive/HelloDynamic.java test/hotspot/jtreg/runtime/appcds/dynamicArchive/HelloDynamicCustom.java test/hotspot/jtreg/runtime/appcds/dynamicArchive/HelloDynamicCustomUnload.java test/hotspot/jtreg/runtime/appcds/dynamicArchive/JITInteraction.java test/hotspot/jtreg/runtime/appcds/dynamicArchive/MainModuleOnly.java test/hotspot/jtreg/runtime/appcds/dynamicArchive/MethodSorting.java test/hotspot/jtreg/runtime/appcds/dynamicArchive/MissingArchive.java test/hotspot/jtreg/runtime/appcds/dynamicArchive/NoClassToArchive.java test/hotspot/jtreg/runtime/appcds/dynamicArchive/SharedArchiveFileOption.java test/hotspot/jtreg/runtime/appcds/dynamicArchive/UnsupportedBaseArchive.java test/hotspot/jtreg/runtime/appcds/dynamicArchive/UnusedCPDuringDump.java test/hotspot/jtreg/runtime/appcds/dynamicArchive/WrongTopClasspath.java test/hotspot/jtreg/runtime/appcds/dynamicArchive/test-classes/ArrayKlassesApp.java test/hotspot/jtreg/runtime/appcds/dynamicArchive/test-classes/ExcludedClassesApp.java test/hotspot/jtreg/runtime/appcds/dynamicArchive/test-classes/LoadClasses.java test/hotspot/jtreg/runtime/appcds/dynamicArchive/test-classes/MethodSortingApp.java test/hotspot/jtreg/runtime/appcds/dynamicArchive/test-classes/MissingDependent.java test/hotspot/jtreg/runtime/appcds/dynamicArchive/test-classes/StrConcatApp.java test/hotspot/jtreg/runtime/appcds/dynamicArchive/test-classes/TestJIT.java test/hotspot/jtreg/runtime/appcds/jigsaw/PatchModule/MismatchedPatchModule.java test/hotspot/jtreg/runtime/appcds/jigsaw/PatchModule/PatchJavaBase.java test/hotspot/jtreg/runtime/appcds/jigsaw/PatchModule/PatchMain.java test/hotspot/jtreg/runtime/appcds/jigsaw/modulepath/AddModules.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/overridetests/OverrideTests.java test/hotspot/jtreg/runtime/appcds/jvmti/dumpingWithAgent/DumpingWithJavaAgent.java test/hotspot/jtreg/runtime/appcds/jvmti/transformRelatedClasses/TransformRelatedClassesAppCDS.java test/hotspot/jtreg/runtime/appcds/test-classes/DummyClassHelper.java test/hotspot/jtreg/runtime/appcds/test-classes/GenericTestApp.java test/lib/jdk/test/lib/cds/CDSTestUtils.java test/lib/sun/hotspot/WhiteBox.java
diffstat 120 files changed, 6318 insertions(+), 855 deletions(-) [+]
line wrap: on
line diff
--- a/make/hotspot/lib/JvmFeatures.gmk	Fri May 17 10:48:02 2019 -0400
+++ b/make/hotspot/lib/JvmFeatures.gmk	Fri May 17 08:29:55 2019 -0700
@@ -111,6 +111,7 @@
   JVM_EXCLUDE_FILES += \
       classListParser.cpp \
       classLoaderExt.cpp \
+      dynamicArchive.cpp \
       filemap.cpp \
       heapShared.cpp \
       metaspaceShared.cpp \
--- a/src/hotspot/share/classfile/classListParser.cpp	Fri May 17 10:48:02 2019 -0400
+++ b/src/hotspot/share/classfile/classListParser.cpp	Fri May 17 08:29:55 2019 -0700
@@ -295,14 +295,14 @@
   if (!is_id_specified()) {
     error("If source location is specified, id must be also specified");
   }
-  InstanceKlass* k = ClassLoaderExt::load_class(class_name, _source, CHECK_NULL);
-
   if (strncmp(_class_name, "java/", 5) == 0) {
     log_info(cds)("Prohibited package for non-bootstrap classes: %s.class from %s",
           _class_name, _source);
     return NULL;
   }
 
+  InstanceKlass* k = ClassLoaderExt::load_class(class_name, _source, CHECK_NULL);
+
   if (k != NULL) {
     if (k->local_interfaces()->length() != _interfaces->length()) {
       print_specified_interfaces();
@@ -461,4 +461,3 @@
   ShouldNotReachHere();
   return NULL;
 }
-
--- a/src/hotspot/share/classfile/classLoader.cpp	Fri May 17 10:48:02 2019 -0400
+++ b/src/hotspot/share/classfile/classLoader.cpp	Fri May 17 08:29:55 2019 -0700
@@ -36,6 +36,7 @@
 #include "classfile/klassFactory.hpp"
 #include "classfile/symbolTable.hpp"
 #include "classfile/systemDictionary.hpp"
+#include "classfile/systemDictionaryShared.hpp"
 #include "classfile/vmSymbols.hpp"
 #include "compiler/compileBroker.hpp"
 #include "interpreter/bytecodeStream.hpp"
@@ -468,7 +469,7 @@
 
 #if INCLUDE_CDS
 void ClassLoader::exit_with_path_failure(const char* error, const char* message) {
-  assert(DumpSharedSpaces, "only called at dump time");
+  assert(DumpSharedSpaces || DynamicDumpSharedSpaces, "only called at dump time");
   tty->print_cr("Hint: enable -Xlog:class+path=info to diagnose the failure");
   vm_exit_during_initialization(error, message);
 }
@@ -534,7 +535,7 @@
     trace_class_path("bootstrap loader class path=", sys_class_path);
   }
 #if INCLUDE_CDS
-  if (DumpSharedSpaces) {
+  if (DumpSharedSpaces || DynamicDumpSharedSpaces) {
     _shared_paths_misc_info->add_boot_classpath(sys_class_path);
   }
 #endif
@@ -550,16 +551,16 @@
   return _shared_paths_misc_info->buffer();
 }
 
-bool ClassLoader::check_shared_paths_misc_info(void *buf, int size) {
+bool ClassLoader::check_shared_paths_misc_info(void *buf, int size, bool is_static) {
   SharedPathsMiscInfo* checker = new SharedPathsMiscInfo((char*)buf, size);
-  bool result = checker->check();
+  bool result = checker->check(is_static);
   delete checker;
   return result;
 }
 
 void ClassLoader::setup_app_search_path(const char *class_path) {
 
-  assert(DumpSharedSpaces, "Sanity");
+  assert(DumpSharedSpaces || DynamicDumpSharedSpaces, "Sanity");
 
   Thread* THREAD = Thread::current();
   int len = (int)strlen(class_path);
@@ -587,7 +588,7 @@
 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");
+  assert(DumpSharedSpaces || DynamicDumpSharedSpaces, "dump time only");
 
   // The entry does not exist, add to the list
   if (_module_path_entries == NULL) {
@@ -601,7 +602,7 @@
 
 // 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");
+  assert(DumpSharedSpaces || DynamicDumpSharedSpaces, "dump time only");
   struct stat st;
   if (os::stat(path, &st) != 0) {
     tty->print_cr("os::stat error %d (%s). CDS dump aborted (path was \"%s\").",
@@ -709,7 +710,7 @@
   bool set_base_piece = true;
 
 #if INCLUDE_CDS
-  if (DumpSharedSpaces) {
+  if (DumpSharedSpaces || DynamicDumpSharedSpaces) {
     if (!Arguments::has_jimage()) {
       vm_exit_during_initialization("CDS is not supported in exploded JDK build", NULL);
     }
@@ -976,7 +977,7 @@
     return true;
   } else {
 #if INCLUDE_CDS
-    if (DumpSharedSpaces) {
+    if (DumpSharedSpaces || DynamicDumpSharedSpaces) {
       _shared_paths_misc_info->add_nonexist_path(path);
     }
 #endif
@@ -1334,6 +1335,10 @@
     // appear in the _patch_mod_entries. The runtime shared class visibility
     // check will determine if a shared class is visible based on the runtime
     // environemnt, including the runtime --patch-module setting.
+    //
+    // DynamicDumpSharedSpaces requires UseSharedSpaces to be enabled. Since --patch-module
+    // is not supported with UseSharedSpaces, it is not supported with DynamicDumpSharedSpaces.
+    assert(!DynamicDumpSharedSpaces, "sanity");
     if (!DumpSharedSpaces) {
       stream = search_module_entries(_patch_mod_entries, class_name, file_name, CHECK_NULL);
     }
@@ -1423,7 +1428,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, TRAPS) {
-  assert(DumpSharedSpaces, "sanity");
+  assert(DumpSharedSpaces || DynamicDumpSharedSpaces, "sanity");
   assert(stream != NULL, "sanity");
 
   if (ik->is_unsafe_anonymous()) {
@@ -1513,6 +1518,8 @@
     // user defined classloader.
     if (classpath_index < 0) {
       assert(ik->shared_classpath_index() < 0, "Sanity");
+      ik->set_shared_classpath_index(UNREGISTERED_INDEX);
+      SystemDictionaryShared::set_shared_class_misc_info(ik, (ClassFileStream*)stream);
       return;
     }
   } else {
@@ -1595,7 +1602,7 @@
   load_jimage_library();
 #if INCLUDE_CDS
   // initialize search path
-  if (DumpSharedSpaces) {
+  if (DumpSharedSpaces || DynamicDumpSharedSpaces) {
     _shared_paths_misc_info = new SharedPathsMiscInfo();
   }
 #endif
@@ -1604,14 +1611,14 @@
 
 #if INCLUDE_CDS
 void ClassLoader::initialize_shared_path() {
-  if (DumpSharedSpaces) {
+  if (DumpSharedSpaces || DynamicDumpSharedSpaces) {
     ClassLoaderExt::setup_search_paths();
     _shared_paths_misc_info->write_jint(0); // see comments in SharedPathsMiscInfo::check()
   }
 }
 
 void ClassLoader::initialize_module_path(TRAPS) {
-  if (DumpSharedSpaces) {
+  if (DumpSharedSpaces || DynamicDumpSharedSpaces) {
     ClassLoaderExt::setup_module_paths(THREAD);
     FileMapInfo::allocate_shared_path_table();
   }
@@ -1677,6 +1684,7 @@
   // entries will be added to the exploded build array.
   if (!has_jrt_entry()) {
     assert(!DumpSharedSpaces, "DumpSharedSpaces not supported with exploded module builds");
+    assert(!DynamicDumpSharedSpaces, "DynamicDumpSharedSpaces not supported with exploded module builds");
     assert(!UseSharedSpaces, "UsedSharedSpaces not supported with exploded module builds");
     // Set up the boot loader's _exploded_entries list.  Note that this gets
     // done before loading any classes, by the same thread that will
--- a/src/hotspot/share/classfile/classLoader.hpp	Fri May 17 10:48:02 2019 -0400
+++ b/src/hotspot/share/classfile/classLoader.hpp	Fri May 17 08:29:55 2019 -0700
@@ -398,7 +398,8 @@
   // 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");
+    assert(DumpSharedSpaces || DynamicDumpSharedSpaces,
+           "Should only be called at CDS dump time");
     int num_entries = 0;
     ClassPathEntry* e= ClassLoader::_module_path_entries;
     while (e != NULL) {
@@ -410,7 +411,7 @@
   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 bool  check_shared_paths_misc_info(void* info, int size, bool is_static);
   static void  exit_with_path_failure(const char* error, const char* message);
   static char* skip_uri_protocol(char* source);
   static void  record_result(InstanceKlass* ik, const ClassFileStream* stream, TRAPS);
--- a/src/hotspot/share/classfile/classLoader.inline.hpp	Fri May 17 10:48:02 2019 -0400
+++ b/src/hotspot/share/classfile/classLoader.inline.hpp	Fri May 17 08:29:55 2019 -0700
@@ -62,7 +62,8 @@
 // entries during shared classpath setup time.
 
 inline int ClassLoader::num_boot_classpath_entries() {
-  assert(DumpSharedSpaces, "Should only be called at CDS dump time");
+  assert(DumpSharedSpaces || DynamicDumpSharedSpaces,
+         "Should only be called at CDS dump time");
   assert(has_jrt_entry(), "must have a java runtime image");
   int num_entries = 1; // count the runtime image
   ClassPathEntry* e = ClassLoader::_first_append_entry;
@@ -84,7 +85,8 @@
 // Helper function used by CDS code to get the number of app classpath
 // entries during shared classpath setup time.
 inline int ClassLoader::num_app_classpath_entries() {
-  assert(DumpSharedSpaces, "Should only be called at CDS dump time");
+  assert(DumpSharedSpaces || DynamicDumpSharedSpaces,
+         "Should only be called at CDS dump time");
   int num_entries = 0;
   ClassPathEntry* e= ClassLoader::_app_classpath_entries;
   while (e != NULL) {
--- a/src/hotspot/share/classfile/classLoaderExt.cpp	Fri May 17 10:48:02 2019 -0400
+++ b/src/hotspot/share/classfile/classLoaderExt.cpp	Fri May 17 08:29:55 2019 -0700
@@ -62,7 +62,8 @@
 }
 
 void ClassLoaderExt::setup_app_search_path() {
-  assert(DumpSharedSpaces, "this function is only used with -Xshare:dump");
+  assert(DumpSharedSpaces || DynamicDumpSharedSpaces,
+         "this function is only used at CDS dump time");
   _app_class_paths_start_index = ClassLoader::num_boot_classpath_entries();
   char* app_class_path = os::strdup(Arguments::get_appclasspath());
 
@@ -92,7 +93,8 @@
   }
 }
 void ClassLoaderExt::setup_module_paths(TRAPS) {
-  assert(DumpSharedSpaces, "this function is only used with -Xshare:dump");
+  assert(DumpSharedSpaces || DynamicDumpSharedSpaces,
+         "this function is only used with CDS dump time");
   _app_module_paths_start_index = ClassLoader::num_boot_classpath_entries() +
                               ClassLoader::num_app_classpath_entries();
   Handle system_class_loader (THREAD, SystemDictionary::java_system_loader());
@@ -227,7 +229,7 @@
 void ClassLoaderExt::record_result(const s2 classpath_index,
                                    InstanceKlass* result,
                                    TRAPS) {
-  assert(DumpSharedSpaces, "Sanity");
+  assert(DumpSharedSpaces || DynamicDumpSharedSpaces, "Sanity");
 
   // We need to remember where the class comes from during dumping.
   oop loader = result->class_loader();
@@ -301,8 +303,6 @@
     tty->print_cr("Preload Error: Failed to load %s", class_name);
     return NULL;
   }
-  result->set_shared_classpath_index(UNREGISTERED_INDEX);
-  SystemDictionaryShared::set_shared_class_misc_info(result, stream);
   return result;
 }
 
--- a/src/hotspot/share/classfile/compactHashtable.cpp	Fri May 17 10:48:02 2019 -0400
+++ b/src/hotspot/share/classfile/compactHashtable.cpp	Fri May 17 08:29:55 2019 -0700
@@ -27,6 +27,7 @@
 #include "classfile/compactHashtable.hpp"
 #include "classfile/javaClasses.hpp"
 #include "logging/logMessage.hpp"
+#include "memory/dynamicArchive.hpp"
 #include "memory/heapShared.inline.hpp"
 #include "memory/metadataFactory.hpp"
 #include "memory/metaspaceShared.hpp"
@@ -39,12 +40,14 @@
 //
 // The compact hash table writer implementations
 //
-CompactHashtableWriter::CompactHashtableWriter(int num_buckets,
+CompactHashtableWriter::CompactHashtableWriter(int num_entries,
                                                CompactHashtableStats* stats) {
-  assert(DumpSharedSpaces, "dump-time only");
-  assert(num_buckets > 0, "no buckets");
-  _num_buckets = num_buckets;
-  _num_entries = 0;
+  assert(DumpSharedSpaces || DynamicDumpSharedSpaces, "dump-time only");
+  assert(num_entries >= 0, "sanity");
+  _num_buckets = calculate_num_buckets(num_entries);
+  assert(_num_buckets > 0, "no buckets");
+
+  _num_entries_written = 0;
   _buckets = NEW_C_HEAP_ARRAY(GrowableArray<Entry>*, _num_buckets, mtSymbol);
   for (int i=0; i<_num_buckets; i++) {
     _buckets[i] = new (ResourceObj::C_HEAP, mtSymbol) GrowableArray<Entry>(0, true, mtSymbol);
@@ -67,11 +70,24 @@
   FREE_C_HEAP_ARRAY(GrowableArray<Entry>*, _buckets);
 }
 
+size_t CompactHashtableWriter::estimate_size(int num_entries) {
+  int num_buckets = calculate_num_buckets(num_entries);
+  size_t bucket_bytes = MetaspaceShared::ro_array_bytesize<u4>(num_buckets + 1);
+
+  // In worst case, we have no VALUE_ONLY_BUCKET_TYPE, so each entry takes 2 slots
+  int entries_space = 2 * num_entries;
+  size_t entry_bytes = MetaspaceShared::ro_array_bytesize<u4>(entries_space);
+
+  return bucket_bytes
+       + entry_bytes
+       + SimpleCompactHashtable::calculate_header_size();
+}
+
 // Add a symbol entry to the temporary hash table
 void CompactHashtableWriter::add(unsigned int hash, u4 value) {
   int index = hash % _num_buckets;
   _buckets[index]->append_if_missing(Entry(hash, value));
-  _num_entries++;
+  _num_entries_written++;
 }
 
 void CompactHashtableWriter::allocate_table() {
@@ -81,7 +97,7 @@
     int bucket_size = bucket->length();
     if (bucket_size == 1) {
       entries_space++;
-    } else {
+    } else if (bucket_size > 1) {
       entries_space += 2 * bucket_size;
     }
   }
@@ -96,7 +112,7 @@
 
   _stats->bucket_count    = _num_buckets;
   _stats->bucket_bytes    = _compact_buckets->size() * BytesPerWord;
-  _stats->hashentry_count = _num_entries;
+  _stats->hashentry_count = _num_entries_written;
   _stats->hashentry_bytes = _compact_entries->size() * BytesPerWord;
 }
 
@@ -144,19 +160,19 @@
   dump_table(&summary);
 
   int table_bytes = _stats->bucket_bytes + _stats->hashentry_bytes;
-  address base_address = address(MetaspaceShared::shared_rs()->base());
-  cht->init(base_address,  _num_entries, _num_buckets,
+  address base_address = address(SharedBaseAddress);
+  cht->init(base_address,  _num_entries_written, _num_buckets,
             _compact_buckets->data(), _compact_entries->data());
 
   LogMessage(cds, hashtables) msg;
   if (msg.is_info()) {
     double avg_cost = 0.0;
-    if (_num_entries > 0) {
-      avg_cost = double(table_bytes)/double(_num_entries);
+    if (_num_entries_written > 0) {
+      avg_cost = double(table_bytes)/double(_num_entries_written);
     }
     msg.info("Shared %s table stats -------- base: " PTR_FORMAT,
                          table_name, (intptr_t)base_address);
-    msg.info("Number of entries       : %9d", _num_entries);
+    msg.info("Number of entries       : %9d", _num_entries_written);
     msg.info("Total bytes used        : %9d", table_bytes);
     msg.info("Average bytes per entry : %9.3f", avg_cost);
     msg.info("Average bucket size     : %9.3f", summary.avg());
@@ -174,7 +190,28 @@
 // The CompactHashtable implementation
 //
 
+void SimpleCompactHashtable::init(address base_address, u4 entry_count, u4 bucket_count, u4* buckets, u4* entries) {
+  _bucket_count = bucket_count;
+  _entry_count = entry_count;
+  _base_address = base_address;
+  if (DynamicDumpSharedSpaces) {
+    _buckets = DynamicArchive::buffer_to_target(buckets);
+    _entries = DynamicArchive::buffer_to_target(entries);
+  } else {
+    _buckets = buckets;
+    _entries = entries;
+  }
+}
+
+size_t SimpleCompactHashtable::calculate_header_size() {
+  // We have 5 fields. Each takes up sizeof(intptr_t). See WriteClosure::do_u4
+  size_t bytes = sizeof(intptr_t) * 5;
+  return bytes;
+}
+
 void SimpleCompactHashtable::serialize_header(SerializeClosure* soc) {
+  // NOTE: if you change this function, you MUST change the number 5 in
+  // calculate_header_size() accordingly.
   soc->do_ptr((void**)&_base_address);
   soc->do_u4(&_entry_count);
   soc->do_u4(&_bucket_count);
--- a/src/hotspot/share/classfile/compactHashtable.hpp	Fri May 17 10:48:02 2019 -0400
+++ b/src/hotspot/share/classfile/compactHashtable.hpp	Fri May 17 08:29:55 2019 -0700
@@ -100,7 +100,7 @@
   }; // class CompactHashtableWriter::Entry
 
 private:
-  int _num_entries;
+  int _num_entries_written;
   int _num_buckets;
   int _num_empty_buckets;
   int _num_value_only_buckets;
@@ -112,7 +112,7 @@
 
 public:
   // This is called at dump-time only
-  CompactHashtableWriter(int num_buckets, CompactHashtableStats* stats);
+  CompactHashtableWriter(int num_entries, CompactHashtableStats* stats);
   ~CompactHashtableWriter();
 
   void add(unsigned int hash, u4 value);
@@ -120,18 +120,16 @@
 private:
   void allocate_table();
   void dump_table(NumberSeq* summary);
+  static int calculate_num_buckets(int num_entries) {
+    int num_buckets = num_entries / SharedSymbolTableBucketSize;
+    // calculation of num_buckets can result in zero buckets, we need at least one
+    return (num_buckets < 1) ? 1 : num_buckets;
+  }
 
 public:
   void dump(SimpleCompactHashtable *cht, const char* table_name);
 
-  static int default_num_buckets(size_t num_entries) {
-    return default_num_buckets((int)num_entries);
-  }
-  static int default_num_buckets(int num_entries) {
-    int num_buckets = num_entries / SharedSymbolTableBucketSize;
-    // calculation of num_buckets can result in zero buckets, we need at least one
-    return (num_buckets < 1) ? 1 : num_buckets;
-  }
+  static size_t estimate_size(int num_entries);
 };
 #endif // INCLUDE_CDS
 
@@ -214,13 +212,7 @@
     _entries = 0;
   }
 
-  void init(address base_address, u4 entry_count, u4 bucket_count, u4* buckets, u4* entries) {
-    _base_address = base_address;
-    _bucket_count = bucket_count;
-    _entry_count = entry_count;
-    _buckets = buckets;
-    _entries = entries;
-  }
+  void init(address base_address, u4 entry_count, u4 bucket_count, u4* buckets, u4* entries);
 
   // Read/Write the table's header from/to the CDS archive
   void serialize_header(SerializeClosure* soc) NOT_CDS_RETURN;
@@ -228,6 +220,8 @@
   inline bool empty() {
     return (_entry_count == 0);
   }
+
+  static size_t calculate_header_size();
 };
 
 template <
--- a/src/hotspot/share/classfile/dictionary.cpp	Fri May 17 10:48:02 2019 -0400
+++ b/src/hotspot/share/classfile/dictionary.cpp	Fri May 17 08:29:55 2019 -0700
@@ -246,7 +246,7 @@
 
 // Used to scan and relocate the classes during CDS archive dump.
 void Dictionary::classes_do(MetaspaceClosure* it) {
-  assert(DumpSharedSpaces, "dump-time only");
+  assert(DumpSharedSpaces || DynamicDumpSharedSpaces, "dump-time only");
   for (int index = 0; index < table_size(); index++) {
     for (DictionaryEntry* probe = bucket(index);
                           probe != NULL;
@@ -312,7 +312,6 @@
   }
 }
 
-
 InstanceKlass* Dictionary::find_class(int index, unsigned int hash,
                                       Symbol* name) {
   assert_locked_or_safepoint(SystemDictionary_lock);
--- a/src/hotspot/share/classfile/klassFactory.cpp	Fri May 17 10:48:02 2019 -0400
+++ b/src/hotspot/share/classfile/klassFactory.cpp	Fri May 17 08:29:55 2019 -0700
@@ -218,7 +218,7 @@
   JFR_ONLY(ON_KLASS_CREATION(result, parser, THREAD);)
 
 #if INCLUDE_CDS
-  if (DumpSharedSpaces) {
+  if (DumpSharedSpaces || DynamicDumpSharedSpaces) {
     ClassLoader::record_result(result, stream, THREAD);
   }
 #endif // INCLUDE_CDS
--- a/src/hotspot/share/classfile/sharedPathsMiscInfo.cpp	Fri May 17 10:48:02 2019 -0400
+++ b/src/hotspot/share/classfile/sharedPathsMiscInfo.cpp	Fri May 17 08:29:55 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2019, 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
@@ -104,7 +104,7 @@
   }
 }
 
-bool SharedPathsMiscInfo::check() {
+bool SharedPathsMiscInfo::check(bool is_static) {
   // The whole buffer must be 0 terminated so that we can use strlen and strcmp
   // without fear.
   _end_ptr -= sizeof(jint);
@@ -116,9 +116,10 @@
   }
 
   jshort cur_index = 0;
-  jshort max_cp_index = FileMapInfo::current_info()->header()->max_used_path_index();
-  jshort module_paths_start_index =
-    FileMapInfo::current_info()->header()->app_module_paths_start_index();
+  FileMapHeader* header = is_static ? FileMapInfo::current_info()->header() :
+                                      FileMapInfo::dynamic_info()->header();
+  jshort max_cp_index = header->max_used_path_index();
+  jshort module_paths_start_index = header->app_module_paths_start_index();
   while (_cur_ptr < _end_ptr) {
     jint type;
     const char* path = _cur_ptr;
@@ -136,7 +137,7 @@
     }
     // skip checking the class path(s) which was not referenced during CDS dump
     if ((cur_index <= max_cp_index) || (cur_index >= module_paths_start_index)) {
-      if (!check(type, path)) {
+      if (!check(type, path, is_static)) {
         if (!PrintSharedArchiveAndExit) {
           return false;
         }
@@ -171,7 +172,7 @@
   return p;
 }
 
-bool SharedPathsMiscInfo::check(jint type, const char* path) {
+bool SharedPathsMiscInfo::check(jint type, const char* path, bool is_static) {
   assert(UseSharedSpaces, "runtime only");
   switch (type) {
   case BOOT_PATH:
@@ -196,7 +197,9 @@
       char* rp = skip_first_path_entry(runtime_boot_path);
       char* dp = skip_first_path_entry(path);
 
-      bool relaxed_check = !FileMapInfo::current_info()->header()->has_platform_or_app_classes();
+      bool relaxed_check = is_static ?
+                             !FileMapInfo::current_info()->header()->has_platform_or_app_classes() :
+                             !FileMapInfo::dynamic_info()->header()->has_platform_or_app_classes();
       if (dp == NULL && rp == NULL) {
         break;   // ok, both runtime and dump time boot paths have modules_images only
       } else if (dp == NULL && rp != NULL && relaxed_check) {
--- a/src/hotspot/share/classfile/sharedPathsMiscInfo.hpp	Fri May 17 10:48:02 2019 -0400
+++ b/src/hotspot/share/classfile/sharedPathsMiscInfo.hpp	Fri May 17 08:29:55 2019 -0700
@@ -67,7 +67,7 @@
 
 protected:
   static bool fail(const char* msg, const char* name = NULL);
-  bool check(jint type, const char* path);
+  bool check(jint type, const char* path, bool is_static);
 
 public:
   enum {
@@ -162,7 +162,7 @@
   }
 
 public:
-  bool check();
+  bool check(bool is_static);
 };
 
 #endif // SHARE_CLASSFILE_SHAREDPATHSMISCINFO_HPP
--- a/src/hotspot/share/classfile/stringTable.cpp	Fri May 17 10:48:02 2019 -0400
+++ b/src/hotspot/share/classfile/stringTable.cpp	Fri May 17 08:29:55 2019 -0700
@@ -779,9 +779,7 @@
   assert(HeapShared::is_heap_object_archiving_allowed(), "must be");
 
   _shared_table.reset();
-  int num_buckets = CompactHashtableWriter::default_num_buckets(_items_count);
-  CompactHashtableWriter writer(num_buckets,
-                                &MetaspaceShared::stats()->string);
+  CompactHashtableWriter writer(_items_count, &MetaspaceShared::stats()->string);
 
   // Copy the interned strings into the "string space" within the java heap
   copy_shared_string_table(&writer);
--- a/src/hotspot/share/classfile/symbolTable.cpp	Fri May 17 10:48:02 2019 -0400
+++ b/src/hotspot/share/classfile/symbolTable.cpp	Fri May 17 08:29:55 2019 -0700
@@ -28,6 +28,7 @@
 #include "classfile/javaClasses.hpp"
 #include "classfile/symbolTable.hpp"
 #include "memory/allocation.inline.hpp"
+#include "memory/dynamicArchive.hpp"
 #include "memory/metaspaceClosure.hpp"
 #include "memory/metaspaceShared.hpp"
 #include "memory/resourceArea.hpp"
@@ -69,6 +70,11 @@
   symbol_equals_compact_hashtable_entry
 > _shared_table;
 
+static OffsetCompactHashtable<
+  const char*, Symbol*,
+  symbol_equals_compact_hashtable_entry
+> _dynamic_shared_table;
+
 // --------------------------------------------------------------------------
 
 typedef ConcurrentHashTable<Symbol*,
@@ -109,9 +115,11 @@
   java_lang_String::hash_code((const jbyte*)s, len);
 }
 
+#if INCLUDE_CDS
 static uintx hash_shared_symbol(const char* s, int len) {
   return java_lang_String::hash_code((const jbyte*)s, len);
 }
+#endif
 
 class SymbolTableConfig : public SymbolTableHash::BaseConfig {
 private:
@@ -213,7 +221,7 @@
   assert (len <= Symbol::max_length(), "should be checked by caller");
 
   Symbol* sym;
-  if (DumpSharedSpaces) {
+  if (DumpSharedSpaces || DynamicDumpSharedSpaces) {
     c_heap = false;
   }
   if (c_heap) {
@@ -254,6 +262,7 @@
   // all symbols from shared table
   SharedSymbolIterator iter(cl);
   _shared_table.iterate(&iter);
+  _dynamic_shared_table.iterate(&iter);
 
   // all symbols from the dynamic table
   SymbolsDo sd(cl);
@@ -275,7 +284,7 @@
 };
 
 void SymbolTable::metaspace_pointers_do(MetaspaceClosure* it) {
-  assert(DumpSharedSpaces, "called only during dump time");
+  assert(DumpSharedSpaces || DynamicDumpSharedSpaces, "called only during dump time");
   MetaspacePointersDo mpd(it);
   _local_table->do_safepoint_scan(mpd);
 }
@@ -287,19 +296,24 @@
   return sym;
 }
 
+#if INCLUDE_CDS
 Symbol* SymbolTable::lookup_shared(const char* name,
                                    int len, unsigned int hash) {
+  Symbol* sym = NULL;
   if (!_shared_table.empty()) {
     if (_alt_hash) {
       // hash_code parameter may use alternate hashing algorithm but the shared table
       // always uses the same original hash code.
       hash = hash_shared_symbol(name, len);
     }
-    return _shared_table.lookup(name, hash, len);
-  } else {
-    return NULL;
+    sym = _shared_table.lookup(name, hash, len);
+    if (sym == NULL && DynamicArchive::is_mapped()) {
+      sym = _dynamic_shared_table.lookup(name, hash, len);
+    }
   }
+  return sym;
 }
+#endif
 
 Symbol* SymbolTable::lookup_common(const char* name,
                             int len, unsigned int hash) {
@@ -588,6 +602,9 @@
     unsigned int fixed_hash = hash_shared_symbol((const char*)sym->bytes(), sym->utf8_length());
     assert(fixed_hash == hash_symbol((const char*)sym->bytes(), sym->utf8_length(), false),
            "must not rehash during dumping");
+    if (DynamicDumpSharedSpaces) {
+      sym = DynamicArchive::original_to_target(sym);
+    }
     _writer->add(fixed_hash, MetaspaceShared::object_delta_u4(sym));
     return true;
   }
@@ -598,30 +615,43 @@
   _local_table->do_safepoint_scan(copy);
 }
 
-void SymbolTable::write_to_archive() {
+size_t SymbolTable::estimate_size_for_archive() {
+  return CompactHashtableWriter::estimate_size(int(_items_count));
+}
+
+void SymbolTable::write_to_archive(bool is_static_archive) {
   _shared_table.reset();
+  _dynamic_shared_table.reset();
 
-  int num_buckets = CompactHashtableWriter::default_num_buckets(
-      _items_count);
-  CompactHashtableWriter writer(num_buckets,
+  CompactHashtableWriter writer(int(_items_count),
                                 &MetaspaceShared::stats()->symbol);
   copy_shared_symbol_table(&writer);
-  writer.dump(&_shared_table, "symbol");
+  if (is_static_archive) {
+    writer.dump(&_shared_table, "symbol");
 
-  // Verify table is correct
-  Symbol* sym = vmSymbols::java_lang_Object();
-  const char* name = (const char*)sym->bytes();
-  int len = sym->utf8_length();
-  unsigned int hash = hash_symbol(name, len, _alt_hash);
-  assert(sym == _shared_table.lookup(name, hash, len), "sanity");
+    // Verify table is correct
+    Symbol* sym = vmSymbols::java_lang_Object();
+    const char* name = (const char*)sym->bytes();
+    int len = sym->utf8_length();
+    unsigned int hash = hash_symbol(name, len, _alt_hash);
+    assert(sym == _shared_table.lookup(name, hash, len), "sanity");
+  } else {
+    writer.dump(&_dynamic_shared_table, "symbol");
+  }
 }
 
-void SymbolTable::serialize_shared_table_header(SerializeClosure* soc) {
-  _shared_table.serialize_header(soc);
-
+void SymbolTable::serialize_shared_table_header(SerializeClosure* soc,
+                                                bool is_static_archive) {
+  OffsetCompactHashtable<const char*, Symbol*, symbol_equals_compact_hashtable_entry> * table;
+  if (is_static_archive) {
+    table = &_shared_table;
+  } else {
+    table = &_dynamic_shared_table;
+  }
+  table->serialize_header(soc);
   if (soc->writing()) {
     // Sanity. Make sure we don't use the shared table at dump time
-    _shared_table.reset();
+    table->reset();
   }
 }
 #endif //INCLUDE_CDS
--- a/src/hotspot/share/classfile/symbolTable.hpp	Fri May 17 10:48:02 2019 -0400
+++ b/src/hotspot/share/classfile/symbolTable.hpp	Fri May 17 08:29:55 2019 -0700
@@ -137,7 +137,7 @@
                           const char** name, int* lengths,
                           int* cp_indices, unsigned int* hashValues);
 
-  static Symbol* lookup_shared(const char* name, int len, unsigned int hash);
+  static Symbol* lookup_shared(const char* name, int len, unsigned int hash) NOT_CDS_RETURN_(NULL);
   static Symbol* lookup_dynamic(const char* name, int len, unsigned int hash);
   static Symbol* lookup_common(const char* name, int len, unsigned int hash);
 
@@ -209,8 +209,10 @@
 private:
   static void copy_shared_symbol_table(CompactHashtableWriter* ch_table);
 public:
-  static void write_to_archive() NOT_CDS_RETURN;
-  static void serialize_shared_table_header(SerializeClosure* soc) NOT_CDS_RETURN;
+  static size_t estimate_size_for_archive() NOT_CDS_RETURN_(0);
+  static void write_to_archive(bool is_static_archive = true) NOT_CDS_RETURN;
+  static void serialize_shared_table_header(SerializeClosure* soc,
+                                            bool is_static_archive = true) NOT_CDS_RETURN;
   static void metaspace_pointers_do(MetaspaceClosure* it);
 
   // Jcmd
--- a/src/hotspot/share/classfile/systemDictionaryShared.cpp	Fri May 17 10:48:02 2019 -0400
+++ b/src/hotspot/share/classfile/systemDictionaryShared.cpp	Fri May 17 08:29:55 2019 -0700
@@ -44,6 +44,7 @@
 #include "memory/oopFactory.hpp"
 #include "memory/resourceArea.hpp"
 #include "memory/universe.hpp"
+#include "memory/dynamicArchive.hpp"
 #include "oops/instanceKlass.hpp"
 #include "oops/klass.inline.hpp"
 #include "oops/objArrayOop.inline.hpp"
@@ -61,9 +62,10 @@
 objArrayOop SystemDictionaryShared::_shared_protection_domains  =  NULL;
 objArrayOop SystemDictionaryShared::_shared_jar_urls            =  NULL;
 objArrayOop SystemDictionaryShared::_shared_jar_manifests       =  NULL;
-DEBUG_ONLY(bool SystemDictionaryShared::_checked_excluded_classes = false;)
+DEBUG_ONLY(bool SystemDictionaryShared::_no_class_loading_should_happen = false;)
 
 class DumpTimeSharedClassInfo: public CHeapObj<mtClass> {
+  bool                         _excluded;
 public:
   struct DTConstraint {
     Symbol* _name;
@@ -76,7 +78,6 @@
   int                          _id;
   int                          _clsfile_size;
   int                          _clsfile_crc32;
-  bool                         _excluded;
   GrowableArray<DTConstraint>* _verifier_constraints;
   GrowableArray<char>*         _verifier_constraint_flags;
 
@@ -115,6 +116,15 @@
       }
     }
   }
+
+  void set_excluded() {
+    _excluded = true;
+  }
+
+  bool is_excluded() {
+    // _klass may become NULL due to DynamicArchiveBuilder::set_to_null
+    return _excluded || _klass == NULL;
+  }
 };
 
 class DumpTimeSharedClassTable: public ResourceHashtable<
@@ -131,8 +141,8 @@
   DumpTimeSharedClassInfo* find_or_allocate_info_for(InstanceKlass* k) {
     DumpTimeSharedClassInfo* p = get(k);
     if (p == NULL) {
-      assert(!SystemDictionaryShared::checked_excluded_classes(),
-             "no new classes can be added after check_excluded_classes");
+      assert(!SystemDictionaryShared::no_class_loading_should_happen(),
+             "no new classes can be loaded while dumping archive");
       put(k, DumpTimeSharedClassInfo());
       p = get(k);
       assert(p != NULL, "sanity");
@@ -146,16 +156,20 @@
   public:
     CountClassByCategory(DumpTimeSharedClassTable* table) : _table(table) {}
     bool do_entry(InstanceKlass* k, DumpTimeSharedClassInfo& info) {
-      if (SystemDictionaryShared::is_builtin(k)) {
-        ++ _table->_builtin_count;
-      } else {
-        ++ _table->_unregistered_count;
+      if (!info.is_excluded()) {
+        if (info.is_builtin()) {
+          ++ _table->_builtin_count;
+        } else {
+          ++ _table->_unregistered_count;
+        }
       }
       return true; // keep on iterating
     }
   };
 
   void update_counts() {
+    _builtin_count = 0;
+    _unregistered_count = 0;
     CountClassByCategory counter(this);
     iterate(&counter);
   }
@@ -250,26 +264,36 @@
     return (char*)(address(this) + verifier_constraint_flags_offset());
   }
 
+  static u4 object_delta_u4(Symbol* sym) {
+    if (DynamicDumpSharedSpaces) {
+      sym = DynamicArchive::original_to_target(sym);
+    }
+    return MetaspaceShared::object_delta_u4(sym);
+  }
+
   void init(DumpTimeSharedClassInfo& info) {
     _klass = info._klass;
-    _num_constraints = info.num_constraints();
     if (!SystemDictionaryShared::is_builtin(_klass)) {
       CrcInfo* c = crc();
       c->_clsfile_size = info._clsfile_size;
       c->_clsfile_crc32 = info._clsfile_crc32;
     }
+    _num_constraints = info.num_constraints();
     if (_num_constraints > 0) {
       RTConstraint* constraints = verifier_constraints();
       char* flags = verifier_constraint_flags();
       int i;
       for (i = 0; i < _num_constraints; i++) {
-        constraints[i]._name      = MetaspaceShared::object_delta_u4(info._verifier_constraints->at(i)._name);
-        constraints[i]._from_name = MetaspaceShared::object_delta_u4(info._verifier_constraints->at(i)._from_name);
+        constraints[i]._name      = object_delta_u4(info._verifier_constraints->at(i)._name);
+        constraints[i]._from_name = object_delta_u4(info._verifier_constraints->at(i)._from_name);
       }
       for (i = 0; i < _num_constraints; i++) {
         flags[i] = info._verifier_constraint_flags->at(i);
       }
     }
+    if (DynamicDumpSharedSpaces) {
+      _klass = DynamicArchive::original_to_target(info._klass);
+    }
   }
 
   bool matches(int clsfile_size, int clsfile_crc32) const {
@@ -307,7 +331,12 @@
     return *info_pointer_addr(klass);
   }
   static void set_for(InstanceKlass* klass, RunTimeSharedClassInfo* record) {
-    *info_pointer_addr(klass) = record;
+    if (DynamicDumpSharedSpaces) {
+      klass = DynamicArchive::original_to_buffer(klass);
+      *info_pointer_addr(klass) = DynamicArchive::buffer_to_target(record);
+    } else {
+      *info_pointer_addr(klass) = record;
+    }
   }
 
   // Used by RunTimeSharedDictionary to implement OffsetCompactHashtable::EQUALS
@@ -323,8 +352,12 @@
   RunTimeSharedClassInfo::EQUALS> {};
 
 static DumpTimeSharedClassTable* _dumptime_table = NULL;
+// SystemDictionaries in the base layer static archive
 static RunTimeSharedDictionary _builtin_dictionary;
 static RunTimeSharedDictionary _unregistered_dictionary;
+// SystemDictionaries in the top layer dynamic archive
+static RunTimeSharedDictionary _dynamic_builtin_dictionary;
+static RunTimeSharedDictionary _dynamic_unregistered_dictionary;
 
 oop SystemDictionaryShared::shared_protection_domain(int index) {
   return _shared_protection_domains->obj_at(index);
@@ -710,6 +743,17 @@
   return false;
 }
 
+bool SystemDictionaryShared::has_platform_or_app_classes() {
+  if (FileMapInfo::current_info()->header()->has_platform_or_app_classes()) {
+    return true;
+  }
+  if (DynamicArchive::is_mapped() &&
+      FileMapInfo::dynamic_info()->header()->has_platform_or_app_classes()) {
+    return true;
+  }
+  return false;
+}
+
 // The following stack shows how this code is reached:
 //
 //   [0] SystemDictionaryShared::find_or_load_shared_class()
@@ -747,7 +791,7 @@
                  Symbol* name, Handle class_loader, TRAPS) {
   InstanceKlass* k = NULL;
   if (UseSharedSpaces) {
-    if (!FileMapInfo::current_info()->header()->has_platform_or_app_classes()) {
+    if (!has_platform_or_app_classes()) {
       return NULL;
     }
 
@@ -864,11 +908,17 @@
 
   const RunTimeSharedClassInfo* record = find_record(&_unregistered_dictionary, class_name);
   if (record == NULL) {
-    return NULL;
+    if (DynamicArchive::is_mapped()) {
+      record = find_record(&_dynamic_unregistered_dictionary, class_name);
+    }
+    if (record == NULL) {
+      return NULL;
+    }
   }
 
   int clsfile_size  = cfs->length();
   int clsfile_crc32 = ClassLoader::crc32(0, (const char*)cfs->buffer(), cfs->length());
+
   if (!record->matches(clsfile_size, clsfile_crc32)) {
     return NULL;
   }
@@ -971,6 +1021,7 @@
 }
 
 DumpTimeSharedClassInfo* SystemDictionaryShared::find_or_allocate_info_for(InstanceKlass* k) {
+  MutexLocker ml(DumpTimeTable_lock, Mutex::_no_safepoint_check_flag);
   if (_dumptime_table == NULL) {
     _dumptime_table = new (ResourceObj::C_HEAP, mtClass)DumpTimeSharedClassTable();
   }
@@ -978,7 +1029,7 @@
 }
 
 void SystemDictionaryShared::set_shared_class_misc_info(InstanceKlass* k, ClassFileStream* cfs) {
-  assert(DumpSharedSpaces, "only when dumping");
+  assert(DumpSharedSpaces || DynamicDumpSharedSpaces, "only when dumping");
   assert(!is_builtin(k), "must be unregistered class");
   DumpTimeSharedClassInfo* info = find_or_allocate_info_for(k);
   info->_clsfile_size  = cfs->length();
@@ -990,6 +1041,28 @@
 }
 
 void SystemDictionaryShared::remove_dumptime_info(InstanceKlass* k) {
+  MutexLocker ml(DumpTimeTable_lock, Mutex::_no_safepoint_check_flag);
+  DumpTimeSharedClassInfo* p = _dumptime_table->get(k);
+  if (p == NULL) {
+    return;
+  }
+  if (p->_verifier_constraints != NULL) {
+    for (int i = 0; i < p->_verifier_constraints->length(); i++) {
+      DumpTimeSharedClassInfo::DTConstraint constraint = p->_verifier_constraints->at(i);
+      if (constraint._name != NULL ) {
+        constraint._name->decrement_refcount();
+      }
+      if (constraint._from_name != NULL ) {
+        constraint._from_name->decrement_refcount();
+      }
+    }
+    FREE_C_HEAP_ARRAY(DTConstraint, p->_verifier_constraints);
+    p->_verifier_constraints = NULL;
+  }
+  if (p->_verifier_constraint_flags != NULL) {
+    FREE_C_HEAP_ARRAY(char, p->_verifier_constraint_flags);
+    p->_verifier_constraint_flags = NULL;
+  }
   _dumptime_table->remove(k);
 }
 
@@ -1010,9 +1083,11 @@
 
 bool SystemDictionaryShared::should_be_excluded(InstanceKlass* k) {
   if (k->class_loader_data()->is_unsafe_anonymous()) {
+    warn_excluded(k, "Unsafe anonymous class");
     return true; // unsafe anonymous classes are not archived, skip
   }
   if (k->is_in_error_state()) {
+    warn_excluded(k, "In error state");
     return true;
   }
   if (k->shared_classpath_index() < 0 && is_builtin(k)) {
@@ -1036,6 +1111,44 @@
     warn_excluded(k, "JFR event class");
     return true;
   }
+  if (k->init_state() < InstanceKlass::linked) {
+    // In static dumping, we will attempt to link all classes. Those that fail to link will
+    // be marked as in error state.
+    assert(DynamicDumpSharedSpaces, "must be");
+
+    // TODO -- rethink how this can be handled.
+    // We should try to link ik, however, we can't do it here because
+    // 1. We are at VM exit
+    // 2. linking a class may cause other classes to be loaded, which means
+    //    a custom ClassLoader.loadClass() may be called, at a point where the
+    //    class loader doesn't expect it.
+    warn_excluded(k, "Not linked");
+    return true;
+  }
+  if (k->major_version() < 50 /*JAVA_6_VERSION*/) {
+    ResourceMark rm;
+    log_warning(cds)("Pre JDK 6 class not supported by CDS: %u.%u %s",
+                     k->major_version(),  k->minor_version(), k->name()->as_C_string());
+    return true;
+  }
+
+  InstanceKlass* super = k->java_super();
+  if (super != NULL && should_be_excluded(super)) {
+    ResourceMark rm;
+    log_warning(cds)("Skipping %s: super class %s is excluded", k->name()->as_C_string(), super->name()->as_C_string());
+    return true;
+  }
+
+  Array<InstanceKlass*>* interfaces = k->local_interfaces();
+  int len = interfaces->length();
+  for (int i = 0; i < len; i++) {
+    InstanceKlass* intf = interfaces->at(i);
+    if (should_be_excluded(intf)) {
+      log_warning(cds)("Skipping %s: interface %s is excluded", k->name()->as_C_string(), intf->name()->as_C_string());
+      return true;
+    }
+  }
+
   return false;
 }
 
@@ -1044,8 +1157,9 @@
   ResourceMark rm;
   const char* name = k->name()->as_C_string();
   DumpTimeSharedClassInfo* info = _dumptime_table->get(k);
+  assert(_no_class_loading_should_happen, "class loading must be disabled");
   guarantee(info != NULL, "Class %s must be entered into _dumptime_table", name);
-  guarantee(!info->_excluded, "Should not attempt to archive excluded class %s", name);
+  guarantee(!info->is_excluded(), "Should not attempt to archive excluded class %s", name);
   if (is_builtin(k)) {
     guarantee(k->loader_type() != 0,
               "Class loader type must be set for BUILTIN class %s", name);
@@ -1059,7 +1173,7 @@
 public:
   bool do_entry(InstanceKlass* k, DumpTimeSharedClassInfo& info) {
     if (SystemDictionaryShared::should_be_excluded(k)) {
-      info._excluded = true;
+      info.set_excluded();
     }
     return true; // keep on iterating
   }
@@ -1068,13 +1182,13 @@
 void SystemDictionaryShared::check_excluded_classes() {
   ExcludeDumpTimeSharedClasses excl;
   _dumptime_table->iterate(&excl);
-  DEBUG_ONLY(_checked_excluded_classes = true;)
+  _dumptime_table->update_counts();
 }
 
 bool SystemDictionaryShared::is_excluded_class(InstanceKlass* k) {
-  assert(_checked_excluded_classes, "sanity");
-  assert(DumpSharedSpaces, "only when dumping");
-  return find_or_allocate_info_for(k)->_excluded;
+  assert(_no_class_loading_should_happen, "sanity");
+  assert(DumpSharedSpaces || DynamicDumpSharedSpaces, "only when dumping");
+  return find_or_allocate_info_for(k)->is_excluded();
 }
 
 class IterateDumpTimeSharedClassTable : StackObj {
@@ -1083,7 +1197,7 @@
   IterateDumpTimeSharedClassTable(MetaspaceClosure* it) : _it(it) {}
 
   bool do_entry(InstanceKlass* k, DumpTimeSharedClassInfo& info) {
-    if (!info._excluded) {
+    if (!info.is_excluded()) {
       info.metaspace_pointers_do(_it);
     }
     return true; // keep on iterating
@@ -1097,18 +1211,27 @@
 
 bool SystemDictionaryShared::add_verification_constraint(InstanceKlass* k, Symbol* name,
          Symbol* from_name, bool from_field_is_protected, bool from_is_array, bool from_is_object) {
-  assert(DumpSharedSpaces, "called at dump time only");
+  assert(DumpSharedSpaces || DynamicDumpSharedSpaces, "called at dump time only");
   DumpTimeSharedClassInfo* info = find_or_allocate_info_for(k);
   info->add_verification_constraint(k, name, from_name, from_field_is_protected,
                                     from_is_array, from_is_object);
-  if (is_builtin(k)) {
-    // For builtin class loaders, we can try to complete the verification check at dump time,
-    // because we can resolve all the constraint classes.
+
+  if (DynamicDumpSharedSpaces) {
+    // For dynamic dumping, we can resolve all the constraint classes for all class loaders during
+    // the initial run prior to creating the archive before vm exit. We will also perform verification
+    // check when running with the archive.
     return false;
   } else {
-    // For non-builtin class loaders, we cannot complete the verification check at dump time,
-    // because at dump time we don't know how to resolve classes for such loaders.
-    return true;
+    if (is_builtin(k)) {
+      // For builtin class loaders, we can try to complete the verification check at dump time,
+      // because we can resolve all the constraint classes. We will also perform verification check
+      // when running with the archive.
+      return false;
+    } else {
+      // For non-builtin class loaders, we cannot complete the verification check at dump time,
+      // because at dump time we don't know how to resolve classes for such loaders.
+      return true;
+    }
   }
 }
 
@@ -1139,9 +1262,9 @@
 
   if (log_is_enabled(Trace, cds, verification)) {
     ResourceMark rm;
-    log_trace(cds, verification)("add_verification_constraint: %s: %s must be subclass of %s",
+    log_trace(cds, verification)("add_verification_constraint: %s: %s must be subclass of %s [0x%x]",
                                  k->external_name(), from_name->as_klass_external_name(),
-                                 name->as_klass_external_name());
+                                 name->as_klass_external_name(), c);
   }
 }
 
@@ -1157,6 +1280,13 @@
       Symbol* from_name = record->get_constraint_from_name(i);
       char c            = record->get_constraint_flag(i);
 
+      if (log_is_enabled(Trace, cds, verification)) {
+        ResourceMark rm(THREAD);
+        log_trace(cds, verification)("check_verification_constraint: %s: %s must be subclass of %s [0x%x]",
+                                     klass->external_name(), from_name->as_klass_external_name(),
+                                     name->as_klass_external_name(), c);
+      }
+
       bool from_field_is_protected = (c & SystemDictionaryShared::FROM_FIELD_IS_PROTECTED) ? true : false;
       bool from_is_array           = (c & SystemDictionaryShared::FROM_IS_ARRAY)           ? true : false;
       bool from_is_object          = (c & SystemDictionaryShared::FROM_IS_OBJECT)          ? true : false;
@@ -1178,22 +1308,72 @@
   }
 }
 
+class EstimateSizeForArchive : StackObj {
+  size_t _shared_class_info_size;
+  int _num_builtin_klasses;
+  int _num_unregistered_klasses;
+
+public:
+  EstimateSizeForArchive() {
+    _shared_class_info_size = 0;
+    _num_builtin_klasses = 0;
+    _num_unregistered_klasses = 0;
+  }
+
+  bool do_entry(InstanceKlass* k, DumpTimeSharedClassInfo& info) {
+    if (!info.is_excluded()) {
+      size_t byte_size = RunTimeSharedClassInfo::byte_size(info._klass, info.num_constraints());
+      _shared_class_info_size += align_up(byte_size, BytesPerWord);
+    }
+    return true; // keep on iterating
+  }
+
+  size_t total() {
+    return _shared_class_info_size;
+  }
+};
+
+size_t SystemDictionaryShared::estimate_size_for_archive() {
+  EstimateSizeForArchive est;
+  _dumptime_table->iterate(&est);
+  return est.total() +
+    CompactHashtableWriter::estimate_size(_dumptime_table->count_of(true)) +
+    CompactHashtableWriter::estimate_size(_dumptime_table->count_of(false));
+}
+
 class CopySharedClassInfoToArchive : StackObj {
   CompactHashtableWriter* _writer;
   bool _is_builtin;
 public:
-  CopySharedClassInfoToArchive(CompactHashtableWriter* writer, bool is_builtin)
+  CopySharedClassInfoToArchive(CompactHashtableWriter* writer,
+                               bool is_builtin,
+                               bool is_static_archive)
     : _writer(writer), _is_builtin(is_builtin) {}
 
   bool do_entry(InstanceKlass* k, DumpTimeSharedClassInfo& info) {
-    if (!info._excluded && info.is_builtin() == _is_builtin) {
+    if (!info.is_excluded() && info.is_builtin() == _is_builtin) {
       size_t byte_size = RunTimeSharedClassInfo::byte_size(info._klass, info.num_constraints());
-      RunTimeSharedClassInfo* record =
-        (RunTimeSharedClassInfo*)MetaspaceShared::read_only_space_alloc(byte_size);
+      RunTimeSharedClassInfo* record;
+      record = (RunTimeSharedClassInfo*)MetaspaceShared::read_only_space_alloc(byte_size);
       record->init(info);
 
-      unsigned int hash = primitive_hash<Symbol*>(info._klass->name());
-      _writer->add(hash, MetaspaceShared::object_delta_u4(record));
+      unsigned int hash;
+      Symbol* name = info._klass->name();
+      if (DynamicDumpSharedSpaces) {
+        name = DynamicArchive::original_to_target(name);
+      }
+      hash = primitive_hash<Symbol*>(name);
+      u4 delta;
+      if (DynamicDumpSharedSpaces) {
+        delta = MetaspaceShared::object_delta_u4(DynamicArchive::buffer_to_target(record));
+      } else {
+        delta = MetaspaceShared::object_delta_u4(record);
+      }
+      _writer->add(hash, delta);
+      if (log_is_enabled(Trace, cds, hashtables)) {
+        ResourceMark rm;
+        log_trace(cds,hashtables)("%s dictionary: %s", (_is_builtin ? "builtin" : "unregistered"), info._klass->external_name());
+      }
 
       // Save this for quick runtime lookup of InstanceKlass* -> RunTimeSharedClassInfo*
       RunTimeSharedClassInfo::set_for(info._klass, record);
@@ -1202,25 +1382,36 @@
   }
 };
 
-void SystemDictionaryShared::write_dictionary(RunTimeSharedDictionary* dictionary, bool is_builtin) {
+void SystemDictionaryShared::write_dictionary(RunTimeSharedDictionary* dictionary,
+                                              bool is_builtin,
+                                              bool is_static_archive) {
   CompactHashtableStats stats;
   dictionary->reset();
-  int num_buckets = CompactHashtableWriter::default_num_buckets(_dumptime_table->count_of(is_builtin));
-  CompactHashtableWriter writer(num_buckets, &stats);
-  CopySharedClassInfoToArchive copy(&writer, is_builtin);
+  CompactHashtableWriter writer(_dumptime_table->count_of(is_builtin), &stats);
+  CopySharedClassInfoToArchive copy(&writer, is_builtin, is_static_archive);
   _dumptime_table->iterate(&copy);
   writer.dump(dictionary, is_builtin ? "builtin dictionary" : "unregistered dictionary");
 }
 
-void SystemDictionaryShared::write_to_archive() {
-  _dumptime_table->update_counts();
-  write_dictionary(&_builtin_dictionary, true);
-  write_dictionary(&_unregistered_dictionary, false);
+void SystemDictionaryShared::write_to_archive(bool is_static_archive) {
+  if (is_static_archive) {
+    write_dictionary(&_builtin_dictionary, true);
+    write_dictionary(&_unregistered_dictionary, false);
+  } else {
+    write_dictionary(&_dynamic_builtin_dictionary, true);
+    write_dictionary(&_dynamic_unregistered_dictionary, false);
+  }
 }
 
-void SystemDictionaryShared::serialize_dictionary_headers(SerializeClosure* soc) {
-  _builtin_dictionary.serialize_header(soc);
-  _unregistered_dictionary.serialize_header(soc);
+void SystemDictionaryShared::serialize_dictionary_headers(SerializeClosure* soc,
+                                                          bool is_static_archive) {
+  if (is_static_archive) {
+    _builtin_dictionary.serialize_header(soc);
+    _unregistered_dictionary.serialize_header(soc);
+  } else {
+    _dynamic_builtin_dictionary.serialize_header(soc);
+    _dynamic_unregistered_dictionary.serialize_header(soc);
+  }
 }
 
 const RunTimeSharedClassInfo*
@@ -1237,9 +1428,16 @@
   const RunTimeSharedClassInfo* record = find_record(&_builtin_dictionary, name);
   if (record) {
     return record->_klass;
-  } else {
-    return NULL;
   }
+
+  if (DynamicArchive::is_mapped()) {
+    record = find_record(&_dynamic_builtin_dictionary, name);
+    if (record) {
+      return record->_klass;
+    }
+  }
+
+  return NULL;
 }
 
 void SystemDictionaryShared::update_shared_entry(InstanceKlass* k, int id) {
@@ -1266,14 +1464,31 @@
     SharedDictionaryPrinter p(st);
     _builtin_dictionary.iterate(&p);
     _unregistered_dictionary.iterate(&p);
+    if (DynamicArchive::is_mapped()) {
+      _dynamic_builtin_dictionary.iterate(&p);
+      _unregistered_dictionary.iterate(&p);
+    }
   }
 }
 
-void SystemDictionaryShared::print() { print_on(tty); }
-
 void SystemDictionaryShared::print_table_statistics(outputStream* st) {
   if (UseSharedSpaces) {
     _builtin_dictionary.print_table_statistics(st, "Builtin Shared Dictionary");
     _unregistered_dictionary.print_table_statistics(st, "Unregistered Shared Dictionary");
+    if (DynamicArchive::is_mapped()) {
+      _dynamic_builtin_dictionary.print_table_statistics(st, "Dynamic Builtin Shared Dictionary");
+      _dynamic_unregistered_dictionary.print_table_statistics(st, "Unregistered Shared Dictionary");
+    }
   }
 }
+
+bool SystemDictionaryShared::empty_dumptime_table() {
+  if (_dumptime_table == NULL) {
+    return true;
+  }
+  _dumptime_table->update_counts();
+  if (_dumptime_table->count_of(true) == 0 && _dumptime_table->count_of(false) == 0){
+    return true;
+  }
+  return false;
+}
--- a/src/hotspot/share/classfile/systemDictionaryShared.hpp	Fri May 17 10:48:02 2019 -0400
+++ b/src/hotspot/share/classfile/systemDictionaryShared.hpp	Fri May 17 08:29:55 2019 -0700
@@ -109,6 +109,7 @@
 class RunTimeSharedDictionary;
 
 class SystemDictionaryShared: public SystemDictionary {
+  friend class ExcludeDumpTimeSharedClasses;
 public:
   enum {
     FROM_FIELD_IS_PROTECTED = 1 << 0,
@@ -211,16 +212,21 @@
                                  const ClassFileStream* cfs,
                                  TRAPS);
   static DumpTimeSharedClassInfo* find_or_allocate_info_for(InstanceKlass* k);
-  static void write_dictionary(RunTimeSharedDictionary* dictionary, bool is_builtin);
+  static void write_dictionary(RunTimeSharedDictionary* dictionary,
+                               bool is_builtin,
+                               bool is_static_archive = true);
   static bool is_jfr_event_class(InstanceKlass *k);
   static void warn_excluded(InstanceKlass* k, const char* reason);
+  static bool should_be_excluded(InstanceKlass* k);
 
-  DEBUG_ONLY(static bool _checked_excluded_classes;)
+  DEBUG_ONLY(static bool _no_class_loading_should_happen;)
 public:
   static InstanceKlass* find_builtin_class(Symbol* class_name);
 
   static const RunTimeSharedClassInfo* find_record(RunTimeSharedDictionary* dict, Symbol* name);
 
+  static bool has_platform_or_app_classes();
+
   // Called by PLATFORM/APP loader only
   static InstanceKlass* find_or_load_shared_class(Symbol* class_name,
                                                Handle class_loader,
@@ -288,18 +294,34 @@
   static bool is_builtin(InstanceKlass* k) {
     return (k->shared_classpath_index() != UNREGISTERED_INDEX);
   }
-  static bool should_be_excluded(InstanceKlass* k);
   static void check_excluded_classes();
   static void validate_before_archiving(InstanceKlass* k);
   static bool is_excluded_class(InstanceKlass* k);
   static void dumptime_classes_do(class MetaspaceClosure* it);
-  static void write_to_archive();
-  static void serialize_dictionary_headers(class SerializeClosure* soc);
-  static void print();
+  static size_t estimate_size_for_archive();
+  static void write_to_archive(bool is_static_archive = true);
+  static void serialize_dictionary_headers(class SerializeClosure* soc,
+                                           bool is_static_archive = true);
+  static void print() { return print_on(tty); }
   static void print_on(outputStream* st) NOT_CDS_RETURN;
   static void print_table_statistics(outputStream* st) NOT_CDS_RETURN;
+  static bool empty_dumptime_table() NOT_CDS_RETURN_(true);
 
-  DEBUG_ONLY(static bool checked_excluded_classes() {return _checked_excluded_classes;})
+  DEBUG_ONLY(static bool no_class_loading_should_happen() {return _no_class_loading_should_happen;})
+
+#ifdef ASSERT
+  class NoClassLoadingMark: public StackObj {
+  public:
+    NoClassLoadingMark() {
+      assert(!_no_class_loading_should_happen, "must not be nested");
+      _no_class_loading_should_happen = true;
+    }
+    ~NoClassLoadingMark() {
+      _no_class_loading_should_happen = false;
+    }
+  };
+#endif
+
 };
 
 #endif // SHARE_CLASSFILE_SYSTEMDICTIONARYSHARED_HPP
--- a/src/hotspot/share/classfile/verificationType.cpp	Fri May 17 10:48:02 2019 -0400
+++ b/src/hotspot/share/classfile/verificationType.cpp	Fri May 17 08:29:55 2019 -0700
@@ -94,12 +94,14 @@
       return true;
     }
 
-    if (DumpSharedSpaces && SystemDictionaryShared::add_verification_constraint(klass,
+    if (DumpSharedSpaces || DynamicDumpSharedSpaces) {
+      if (SystemDictionaryShared::add_verification_constraint(klass,
               name(), from.name(), from_field_is_protected, from.is_array(),
               from.is_object())) {
-      // If add_verification_constraint() returns true, the resolution/check should be
-      // delayed until runtime.
-      return true;
+        // If add_verification_constraint() returns true, the resolution/check should be
+        // delayed until runtime.
+        return true;
+      }
     }
 
     return resolve_and_check_assignability(klass, name(), from.name(),
--- a/src/hotspot/share/include/cds.h	Fri May 17 10:48:02 2019 -0400
+++ b/src/hotspot/share/include/cds.h	Fri May 17 08:29:55 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2018, 2019, 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
@@ -35,6 +35,7 @@
 
 #define NUM_CDS_REGIONS 9
 #define CDS_ARCHIVE_MAGIC 0xf00baba2
+#define CDS_DYNAMIC_ARCHIVE_MAGIC 0xf00baba8
 #define CURRENT_CDS_ARCHIVE_VERSION 5
 #define INVALID_CDS_ARCHIVE_VERSION -1
 
--- a/src/hotspot/share/jfr/recorder/jfrRecorder.cpp	Fri May 17 10:48:02 2019 -0400
+++ b/src/hotspot/share/jfr/recorder/jfrRecorder.cpp	Fri May 17 08:29:55 2019 -0700
@@ -168,7 +168,7 @@
 
 static bool is_cds_dump_requested() {
   // we will not be able to launch recordings if a cds dump is being requested
-  if (DumpSharedSpaces && (JfrOptionSet::startup_recording_options() != NULL)) {
+  if ((DumpSharedSpaces || DynamicDumpSharedSpaces) && (JfrOptionSet::startup_recording_options() != NULL)) {
     warning("JFR will be disabled during CDS dumping");
     teardown_startup_support();
     return true;
--- a/src/hotspot/share/logging/logTag.hpp	Fri May 17 10:48:02 2019 -0400
+++ b/src/hotspot/share/logging/logTag.hpp	Fri May 17 08:29:55 2019 -0700
@@ -66,6 +66,7 @@
   LOG_TAG(defaultmethods) \
   LOG_TAG(director) \
   LOG_TAG(dump) \
+  LOG_TAG(dynamic) \
   LOG_TAG(ergo) \
   LOG_TAG(event) \
   LOG_TAG(exceptions) \
--- a/src/hotspot/share/memory/allocation.hpp	Fri May 17 10:48:02 2019 -0400
+++ b/src/hotspot/share/memory/allocation.hpp	Fri May 17 08:29:55 2019 -0700
@@ -254,10 +254,9 @@
   // into a single contiguous memory block, so we can use these
   // two pointers to quickly determine if something is in the
   // shared metaspace.
-  //
   // When CDS is not enabled, both pointers are set to NULL.
-  static void* _shared_metaspace_base; // (inclusive) low address
-  static void* _shared_metaspace_top;  // (exclusive) high address
+  static void* _shared_metaspace_base;  // (inclusive) low address
+  static void* _shared_metaspace_top;   // (exclusive) high address
 
  public:
 
@@ -269,7 +268,8 @@
   static bool is_shared(const MetaspaceObj* p) {
     // If no shared metaspace regions are mapped, _shared_metaspace_{base,top} will
     // both be NULL and all values of p will be rejected quickly.
-    return (((void*)p) < _shared_metaspace_top && ((void*)p) >= _shared_metaspace_base);
+    return (((void*)p) < _shared_metaspace_top &&
+            ((void*)p) >= _shared_metaspace_base);
   }
   bool is_shared() const { return MetaspaceObj::is_shared(this); }
 
@@ -279,6 +279,12 @@
     _shared_metaspace_base = base;
     _shared_metaspace_top = top;
   }
+
+  static void expand_shared_metaspace_range(void* top) {
+    assert(top >= _shared_metaspace_top, "must be");
+    _shared_metaspace_top = top;
+  }
+
   static void* shared_metaspace_base() { return _shared_metaspace_base; }
   static void* shared_metaspace_top()  { return _shared_metaspace_top;  }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/memory/dynamicArchive.cpp	Fri May 17 08:29:55 2019 -0700
@@ -0,0 +1,1147 @@
+/*
+ * Copyright (c) 2019, 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.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "jvm.h"
+#include "classfile/classLoaderData.inline.hpp"
+#include "classfile/symbolTable.hpp"
+#include "classfile/systemDictionary.hpp"
+#include "classfile/systemDictionaryShared.hpp"
+#include "logging/log.hpp"
+#include "memory/metadataFactory.hpp"
+#include "memory/metaspace.hpp"
+#include "memory/metaspaceClosure.hpp"
+#include "memory/metaspaceShared.hpp"
+#include "memory/resourceArea.hpp"
+#include "memory/dynamicArchive.hpp"
+#include "oops/compressedOops.hpp"
+#include "oops/objArrayKlass.hpp"
+#include "prims/jvmtiRedefineClasses.hpp"
+#include "runtime/handles.inline.hpp"
+#include "runtime/os.inline.hpp"
+#include "runtime/sharedRuntime.hpp"
+#include "runtime/vmThread.hpp"
+#include "runtime/vmOperations.hpp"
+#include "utilities/bitMap.inline.hpp"
+
+#ifndef O_BINARY       // if defined (Win32) use binary files.
+#define O_BINARY 0     // otherwise do nothing.
+#endif
+
+class DynamicArchiveBuilder : ResourceObj {
+  CHeapBitMap _ptrmap;
+  static unsigned my_hash(const address& a) {
+    return primitive_hash<address>(a);
+  }
+  static bool my_equals(const address& a0, const address& a1) {
+    return primitive_equals<address>(a0, a1);
+  }
+  typedef ResourceHashtable<
+      address, address,
+      DynamicArchiveBuilder::my_hash,   // solaris compiler doesn't like: primitive_hash<address>
+      DynamicArchiveBuilder::my_equals, // solaris compiler doesn't like: primitive_equals<address>
+      16384, ResourceObj::C_HEAP> RelocationTable;
+  RelocationTable _new_loc_table;
+
+  intx _buffer_to_target_delta;
+
+  DumpRegion* _current_dump_space;
+
+  static size_t reserve_alignment() {
+    return Metaspace::reserve_alignment();
+  }
+
+  static const int _total_dump_regions = 3;
+  int _num_dump_regions_used;
+
+public:
+  void mark_pointer(address* ptr_loc) {
+    if (is_in_buffer_space(ptr_loc)) {
+      size_t idx = pointer_delta(ptr_loc, _alloc_bottom, sizeof(address));
+      _ptrmap.set_bit(idx);
+    }
+  }
+
+  DumpRegion* current_dump_space() const {
+    return _current_dump_space;
+  }
+
+  bool is_in_buffer_space(address p) const {
+    return (_alloc_bottom <= p && p < (address)current_dump_space()->top());
+  }
+
+  template <typename T> bool is_in_target_space(T target_obj) const {
+    address buff_obj = address(target_obj) - _buffer_to_target_delta;
+    return is_in_buffer_space(buff_obj);
+  }
+
+  template <typename T> bool is_in_buffer_space(T obj) const {
+    return is_in_buffer_space(address(obj));
+  }
+
+  template <typename T> T to_target_no_check(T obj) const {
+    return (T)(address(obj) + _buffer_to_target_delta);
+  }
+
+  template <typename T> T to_target(T obj) const {
+    assert(is_in_buffer_space(obj), "must be");
+    return (T)(address(obj) + _buffer_to_target_delta);
+  }
+
+  template <typename T> T get_new_loc(T obj) {
+    address* pp = _new_loc_table.get((address)obj);
+    if (pp == NULL) {
+      // Excluded klasses are not copied
+      return NULL;
+    } else {
+      return (T)*pp;
+    }
+  }
+
+  address get_new_loc(MetaspaceClosure::Ref* ref) {
+    return get_new_loc(ref->obj());
+  }
+
+  template <typename T> bool has_new_loc(T obj) {
+    address* pp = _new_loc_table.get((address)obj);
+    return pp != NULL;
+  }
+
+protected:
+  enum FollowMode {
+    make_a_copy, point_to_it, set_to_null
+  };
+
+public:
+  void copy(MetaspaceClosure::Ref* ref, bool read_only) {
+    int bytes = ref->size() * BytesPerWord;
+    address old_obj = ref->obj();
+    address new_obj = copy_impl(ref, read_only, bytes);
+
+    assert(new_obj != NULL, "must be");
+    assert(new_obj != old_obj, "must be");
+    bool isnew = _new_loc_table.put(old_obj, new_obj);
+    assert(isnew, "must be");
+  }
+
+  // Make a shallow copy of each eligible MetaspaceObj into the buffer.
+  class ShallowCopier: public UniqueMetaspaceClosure {
+    DynamicArchiveBuilder* _builder;
+    bool _read_only;
+  public:
+    ShallowCopier(DynamicArchiveBuilder* shuffler, bool read_only)
+      : _builder(shuffler), _read_only(read_only) {}
+
+    virtual bool do_unique_ref(Ref* orig_obj, bool read_only) {
+      // This method gets called on each *original* object
+      // reachable from _builder->iterate_roots(). Each orig_obj is
+      // called exactly once.
+      FollowMode mode = _builder->follow_ref(orig_obj);
+
+      if (mode == point_to_it) {
+        if (read_only == _read_only) {
+          log_debug(cds, dynamic)("ptr : " PTR_FORMAT " %s", p2i(orig_obj->obj()),
+                                  MetaspaceObj::type_name(orig_obj->msotype()));
+          address p = orig_obj->obj();
+          bool isnew = _builder->_new_loc_table.put(p, p);
+          assert(isnew, "must be");
+        }
+        return false;
+      }
+
+      if (mode == set_to_null) {
+        log_debug(cds, dynamic)("nul : " PTR_FORMAT " %s", p2i(orig_obj->obj()),
+                                MetaspaceObj::type_name(orig_obj->msotype()));
+        return false;
+      }
+
+      if (read_only == _read_only) {
+        // Make a shallow copy of orig_obj in a buffer (maintained
+        // by copy_impl in a subclass of DynamicArchiveBuilder).
+        _builder->copy(orig_obj, read_only);
+      }
+      return true;
+    }
+  };
+
+  // Relocate all embedded pointer fields within a MetaspaceObj's shallow copy
+  class ShallowCopyEmbeddedRefRelocator: public UniqueMetaspaceClosure {
+    DynamicArchiveBuilder* _builder;
+  public:
+    ShallowCopyEmbeddedRefRelocator(DynamicArchiveBuilder* shuffler)
+      : _builder(shuffler) {}
+
+    // This method gets called on each *original* object reachable
+    // from _builder->iterate_roots(). Each orig_obj is
+    // called exactly once.
+    virtual bool do_unique_ref(Ref* orig_ref, bool read_only) {
+      FollowMode mode = _builder->follow_ref(orig_ref);
+
+      if (mode == point_to_it) {
+        // We did not make a copy of this object
+        // and we have nothing to update
+        assert(_builder->get_new_loc(orig_ref) == NULL ||
+               _builder->get_new_loc(orig_ref) == orig_ref->obj(), "must be");
+        return false;
+      }
+
+      if (mode == set_to_null) {
+        // We did not make a copy of this object
+        // and we have nothing to update
+        assert(!_builder->has_new_loc(orig_ref->obj()), "must not be copied or pointed to");
+        return false;
+      }
+
+      // - orig_obj points to the original object.
+      // - new_obj points to the shallow copy (created by ShallowCopier)
+      //   of orig_obj. new_obj is NULL if the orig_obj is excluded
+      address orig_obj = orig_ref->obj();
+      address new_obj  = _builder->get_new_loc(orig_ref);
+
+      assert(new_obj != orig_obj, "must be");
+#ifdef ASSERT
+      if (new_obj == NULL) {
+        if (orig_ref->msotype() == MetaspaceObj::ClassType) {
+          Klass* k = (Klass*)orig_obj;
+          assert(k->is_instance_klass() &&
+                 SystemDictionaryShared::is_excluded_class(InstanceKlass::cast(k)),
+                 "orig_obj must be excluded Class");
+        }
+      }
+#endif
+
+      log_debug(cds, dynamic)("Relocating " PTR_FORMAT " %s", p2i(new_obj),
+                              MetaspaceObj::type_name(orig_ref->msotype()));
+      if (new_obj != NULL) {
+        EmbeddedRefUpdater updater(_builder, orig_obj, new_obj);
+        orig_ref->metaspace_pointers_do(&updater);
+      }
+
+      return true; // keep recursing until every object is visited exactly once.
+    }
+  };
+
+  class EmbeddedRefUpdater: public MetaspaceClosure {
+    DynamicArchiveBuilder* _builder;
+    address _orig_obj;
+    address _new_obj;
+  public:
+    EmbeddedRefUpdater(DynamicArchiveBuilder* shuffler, address orig_obj, address new_obj) :
+      _builder(shuffler), _orig_obj(orig_obj), _new_obj(new_obj) {}
+
+    // This method gets called once for each pointer field F of orig_obj.
+    // We update new_obj->F to point to the new location of orig_obj->F.
+    //
+    // Example: Klass*  0x100 is copied to 0x400
+    //          Symbol* 0x200 is copied to 0x500
+    //
+    // Let orig_obj == 0x100; and
+    //     new_obj  == 0x400; and
+    //     ((Klass*)orig_obj)->_name == 0x200;
+    // Then this function effectively assigns
+    //     ((Klass*)new_obj)->_name = 0x500;
+    virtual bool do_ref(Ref* ref, bool read_only) {
+      address new_pointee = NULL;
+
+      if (ref->not_null()) {
+        address old_pointee = ref->obj();
+
+        FollowMode mode = _builder->follow_ref(ref);
+        if (mode == point_to_it) {
+          new_pointee = old_pointee;
+        } else if (mode == set_to_null) {
+          new_pointee = NULL;
+        } else {
+          new_pointee = _builder->get_new_loc(old_pointee);
+        }
+      }
+
+      const char* kind = MetaspaceObj::type_name(ref->msotype());
+      // offset of this field inside the original object
+      intx offset = (address)ref->addr() - _orig_obj;
+      _builder->update_pointer((address*)(_new_obj + offset), new_pointee, kind, offset);
+
+      // We can't mark the pointer here, because DynamicArchiveBuilder::sort_methods
+      // may re-layout the [iv]tables, which would change the offset(s) in an InstanceKlass
+      // that would contain pointers. Therefore, we must mark the pointers after
+      // sort_methods(), using PointerMarker.
+      return false; // Do not recurse.
+    }
+  };
+
+  class ExternalRefUpdater: public MetaspaceClosure {
+    DynamicArchiveBuilder* _builder;
+
+  public:
+    ExternalRefUpdater(DynamicArchiveBuilder* shuffler) : _builder(shuffler) {}
+
+    virtual bool do_ref(Ref* ref, bool read_only) {
+      // ref is a pointer that lives OUTSIDE of the buffer, but points to an object inside the buffer
+      if (ref->not_null()) {
+        address new_loc = _builder->get_new_loc(ref);
+        const char* kind = MetaspaceObj::type_name(ref->msotype());
+        _builder->update_pointer(ref->addr(), new_loc, kind, 0);
+        _builder->mark_pointer(ref->addr());
+      }
+      return false; // Do not recurse.
+    }
+  };
+
+  class PointerMarker: public UniqueMetaspaceClosure {
+    DynamicArchiveBuilder* _builder;
+
+  public:
+    PointerMarker(DynamicArchiveBuilder* shuffler) : _builder(shuffler) {}
+
+    virtual bool do_unique_ref(Ref* ref, bool read_only) {
+      if (_builder->is_in_buffer_space(ref->obj())) {
+        EmbeddedRefMarker ref_marker(_builder);
+        ref->metaspace_pointers_do(&ref_marker);
+        return true; // keep recursing until every buffered object is visited exactly once.
+      } else {
+        return false;
+      }
+    }
+  };
+
+  class EmbeddedRefMarker: public MetaspaceClosure {
+    DynamicArchiveBuilder* _builder;
+
+  public:
+    EmbeddedRefMarker(DynamicArchiveBuilder* shuffler) : _builder(shuffler) {}
+    virtual bool do_ref(Ref* ref, bool read_only) {
+      if (ref->not_null() && _builder->is_in_buffer_space(ref->obj())) {
+        _builder->mark_pointer(ref->addr());
+      }
+      return false; // Do not recurse.
+    }
+  };
+
+  void update_pointer(address* addr, address value, const char* kind, uintx offset, bool is_mso_pointer=true) {
+    // Propagate the the mask bits to the new value -- see comments above MetaspaceClosure::obj()
+    if (is_mso_pointer) {
+      const uintx FLAG_MASK = 0x03;
+      uintx mask_bits = uintx(*addr) & FLAG_MASK;
+      value = (address)(uintx(value) | mask_bits);
+    }
+
+    if (*addr != value) {
+      log_debug(cds, dynamic)("Update (%18s*) %3d [" PTR_FORMAT "] " PTR_FORMAT " -> " PTR_FORMAT,
+                              kind, int(offset), p2i(addr), p2i(*addr), p2i(value));
+      *addr = value;
+    }
+  }
+
+private:
+  GrowableArray<Symbol*>* _symbols; // symbols to dump
+  GrowableArray<InstanceKlass*>* _klasses; // klasses to dump
+
+  void append(InstanceKlass* k) { _klasses->append(k); }
+  void append(Symbol* s)        { _symbols->append(s); }
+
+  class GatherKlassesAndSymbols : public UniqueMetaspaceClosure {
+    DynamicArchiveBuilder* _builder;
+    bool _read_only;
+
+  public:
+    GatherKlassesAndSymbols(DynamicArchiveBuilder* builder)
+      : _builder(builder) {}
+
+    virtual bool do_unique_ref(Ref* ref, bool read_only) {
+      if (_builder->follow_ref(ref) != make_a_copy) {
+        return false;
+      }
+      if (ref->msotype() == MetaspaceObj::ClassType) {
+        Klass* klass = (Klass*)ref->obj();
+        assert(klass->is_klass(), "must be");
+        if (klass->is_instance_klass()) {
+          InstanceKlass* ik = InstanceKlass::cast(klass);
+          assert(!SystemDictionaryShared::is_excluded_class(ik), "must be");
+          _builder->append(ik);
+          _builder->_estimated_metsapceobj_bytes += BytesPerWord; // See RunTimeSharedClassInfo::get_for()
+        }
+      } else if (ref->msotype() == MetaspaceObj::SymbolType) {
+        _builder->append((Symbol*)ref->obj());
+      }
+
+      int bytes = ref->size() * BytesPerWord;
+      _builder->_estimated_metsapceobj_bytes += bytes;
+
+      return true;
+    }
+  };
+
+  FollowMode follow_ref(MetaspaceClosure::Ref *ref) {
+    address obj = ref->obj();
+    if (MetaspaceShared::is_in_shared_metaspace(obj)) {
+      // Don't dump existing shared metadata again.
+      return point_to_it;
+    } else if (ref->msotype() == MetaspaceObj::MethodDataType) {
+      return set_to_null;
+    } else {
+      if (ref->msotype() == MetaspaceObj::ClassType) {
+        Klass* klass = (Klass*)ref->obj();
+        assert(klass->is_klass(), "must be");
+        if (klass->is_instance_klass()) {
+          InstanceKlass* ik = InstanceKlass::cast(klass);
+          if (SystemDictionaryShared::is_excluded_class(ik)) {
+            ResourceMark rm;
+            log_debug(cds, dynamic)("Skipping class (excluded): %s", klass->external_name());
+            return set_to_null;
+          }
+        } else if (klass->is_array_klass()) {
+          // Don't support archiving of array klasses for now.
+          ResourceMark rm;
+          log_debug(cds, dynamic)("Skipping class (array): %s", klass->external_name());
+          return set_to_null;
+        }
+      }
+
+      return make_a_copy;
+    }
+  }
+
+  address copy_impl(MetaspaceClosure::Ref* ref, bool read_only, int bytes) {
+    if (ref->msotype() == MetaspaceObj::ClassType) {
+      // Save a pointer immediate in front of an InstanceKlass, so
+      // we can do a quick lookup from InstanceKlass* -> RunTimeSharedClassInfo*
+      // without building another hashtable. See RunTimeSharedClassInfo::get_for()
+      // in systemDictionaryShared.cpp.
+      address obj = ref->obj();
+      Klass* klass = (Klass*)obj;
+      if (klass->is_instance_klass()) {
+        SystemDictionaryShared::validate_before_archiving(InstanceKlass::cast(klass));
+        current_dump_space()->allocate(sizeof(address), BytesPerWord);
+      }
+    }
+    address p = (address)current_dump_space()->allocate(bytes);
+    address obj = ref->obj();
+    log_debug(cds, dynamic)("COPY: " PTR_FORMAT " ==> " PTR_FORMAT " %5d %s",
+                            p2i(obj), p2i(p), bytes,
+                            MetaspaceObj::type_name(ref->msotype()));
+    memcpy(p, obj, bytes);
+
+    intptr_t* cloned_vtable = MetaspaceShared::fix_cpp_vtable_for_dynamic_archive(ref->msotype(), p);
+    if (cloned_vtable != NULL) {
+      update_pointer((address*)p, (address)cloned_vtable, "vtb", 0, /*is_mso_pointer*/false);
+    }
+
+    return (address)p;
+  }
+
+  DynamicArchiveHeader *_header;
+  address _alloc_bottom;
+  address _last_verified_top;
+  size_t _other_region_used_bytes;
+
+  // Conservative estimate for number of bytes needed for:
+  size_t _estimated_metsapceobj_bytes;   // all archived MetsapceObj's.
+  size_t _estimated_hashtable_bytes;     // symbol table and dictionaries
+  size_t _estimated_trampoline_bytes;    // method entry trampolines
+
+  size_t estimate_archive_size();
+  size_t estimate_trampoline_size();
+  size_t estimate_class_file_size();
+  address reserve_space_and_init_buffer_to_target_delta();
+  void init_header(address addr);
+  void make_trampolines();
+  void make_klasses_shareable();
+  void sort_methods(InstanceKlass* ik) const;
+  void set_symbols_permanent();
+  void relocate_buffer_to_target();
+  void write_archive(char* read_only_tables_start);
+
+  void init_first_dump_space(address reserved_bottom) {
+    address first_space_base = reserved_bottom;
+    DumpRegion* rw_space = MetaspaceShared::read_write_dump_space();
+    MetaspaceShared::init_shared_dump_space(rw_space, first_space_base);
+    _current_dump_space = rw_space;
+    _last_verified_top = first_space_base;
+    _num_dump_regions_used = 1;
+  }
+
+public:
+  DynamicArchiveBuilder() {
+    _klasses = new (ResourceObj::C_HEAP, mtClass) GrowableArray<InstanceKlass*>(100, true, mtInternal);
+    _symbols = new (ResourceObj::C_HEAP, mtClass) GrowableArray<Symbol*>(1000, true, mtInternal);
+
+    _estimated_metsapceobj_bytes = 0;
+    _estimated_hashtable_bytes = 0;
+    _estimated_trampoline_bytes = 0;
+
+    _num_dump_regions_used = 0;
+  }
+
+  void start_dump_space(DumpRegion* next) {
+    address bottom = _last_verified_top;
+    address top = (address)(current_dump_space()->top());
+    _other_region_used_bytes += size_t(top - bottom);
+
+    MetaspaceShared::pack_dump_space(current_dump_space(), next, MetaspaceShared::shared_rs());
+    _current_dump_space = next;
+    _num_dump_regions_used ++;
+
+    _last_verified_top = (address)(current_dump_space()->top());
+  }
+
+  void verify_estimate_size(size_t estimate, const char* which) {
+    address bottom = _last_verified_top;
+    address top = (address)(current_dump_space()->top());
+    size_t used = size_t(top - bottom) + _other_region_used_bytes;
+    int diff = int(estimate) - int(used);
+
+    log_info(cds)("%s estimate = %lu used = %lu; diff = %d bytes", which, estimate, used, diff);
+    assert(diff >= 0, "Estimate is too small");
+
+    _last_verified_top = top;
+    _other_region_used_bytes = 0;
+  }
+
+  // Do this before and after the archive dump to see if any corruption
+  // is caused by dynamic dumping.
+  void verify_universe(const char* info) {
+    if (VerifyBeforeExit) {
+      log_info(cds)("Verify %s", info);
+      HandleMark hm;
+      // Among other things, this ensures that Eden top is correct.
+      Universe::heap()->prepare_for_verify();
+      Universe::verify(info);
+    }
+  }
+
+  void doit() {
+    verify_universe("Before CDS dynamic dump");
+    DEBUG_ONLY(SystemDictionaryShared::NoClassLoadingMark nclm);
+    SystemDictionaryShared::check_excluded_classes();
+
+    {
+      ResourceMark rm;
+      GatherKlassesAndSymbols gatherer(this);
+
+      SystemDictionaryShared::dumptime_classes_do(&gatherer);
+      SymbolTable::metaspace_pointers_do(&gatherer);
+      FileMapInfo::metaspace_pointers_do(&gatherer);
+
+      gatherer.finish();
+    }
+
+    // rw space starts ...
+    address reserved_bottom = reserve_space_and_init_buffer_to_target_delta();
+    init_header(reserved_bottom);
+
+    verify_estimate_size(sizeof(DynamicArchiveHeader), "header");
+
+    log_info(cds, dynamic)("Copying %d klasses and %d symbols",
+                           _klasses->length(), _symbols->length());
+
+    {
+      assert(current_dump_space() == MetaspaceShared::read_write_dump_space(),
+             "Current dump space is not rw space");
+      // shallow-copy RW objects, if necessary
+      ResourceMark rm;
+      ShallowCopier rw_copier(this, false);
+      iterate_roots(&rw_copier);
+    }
+
+    // ro space starts ...
+    DumpRegion* ro_space = MetaspaceShared::read_only_dump_space();
+    {
+      start_dump_space(ro_space);
+
+      // shallow-copy RO objects, if necessary
+      ResourceMark rm;
+      ShallowCopier ro_copier(this, true);
+      iterate_roots(&ro_copier);
+    }
+
+    size_t bitmap_size = pointer_delta(current_dump_space()->top(),
+                                       _alloc_bottom, sizeof(address));
+    _ptrmap.initialize(bitmap_size);
+
+    {
+      log_info(cds)("Relocating embedded pointers ... ");
+      ResourceMark rm;
+      ShallowCopyEmbeddedRefRelocator emb_reloc(this);
+      iterate_roots(&emb_reloc);
+    }
+
+    {
+      log_info(cds)("Relocating external roots ... ");
+      ResourceMark rm;
+      ExternalRefUpdater ext_reloc(this);
+      iterate_roots(&ext_reloc);
+    }
+
+    verify_estimate_size(_estimated_metsapceobj_bytes, "MetaspaceObjs");
+
+    char* read_only_tables_start;
+    {
+      set_symbols_permanent();
+
+      // Write the symbol table and system dictionaries to the RO space.
+      // Note that these tables still point to the *original* objects
+      // (because they were not processed by ExternalRefUpdater), so
+      // they would need to call DynamicArchive::original_to_target() to
+      // get the correct addresses.
+      assert(current_dump_space() == ro_space, "Must be RO space");
+      SymbolTable::write_to_archive(false);
+      SystemDictionaryShared::write_to_archive(false);
+
+      read_only_tables_start = ro_space->top();
+      WriteClosure wc(ro_space);
+      SymbolTable::serialize_shared_table_header(&wc, false);
+      SystemDictionaryShared::serialize_dictionary_headers(&wc, false);
+    }
+
+    verify_estimate_size(_estimated_hashtable_bytes, "Hashtables");
+
+    // mc space starts ...
+    {
+      start_dump_space(MetaspaceShared::misc_code_dump_space());
+      make_trampolines();
+    }
+
+    verify_estimate_size(_estimated_trampoline_bytes, "Trampolines");
+
+    make_klasses_shareable();
+
+    {
+      log_info(cds)("Final relocation of pointers ... ");
+      ResourceMark rm;
+      PointerMarker marker(this);
+      iterate_roots(&marker);
+      relocate_buffer_to_target();
+    }
+
+    write_archive(read_only_tables_start);
+
+    assert(_num_dump_regions_used == _total_dump_regions, "must be");
+    verify_universe("After CDS dynamic dump");
+  }
+
+  void iterate_roots(MetaspaceClosure* it) {
+    int i;
+    int num_klasses = _klasses->length();
+    for (i = 0; i < num_klasses; i++) {
+      it->push(&_klasses->at(i));
+    }
+
+    int num_symbols = _symbols->length();
+    for (i = 0; i < num_symbols; i++) {
+      it->push(&_symbols->at(i));
+    }
+
+    _header->_shared_path_table.metaspace_pointers_do(it);
+
+    // Do not call these again, as we have already collected all the classes and symbols
+    // that we want to archive. Also, these calls would corrupt the tables when
+    // ExternalRefUpdater is used.
+    //
+    // SystemDictionaryShared::dumptime_classes_do(it);
+    // SymbolTable::metaspace_pointers_do(it);
+
+    it->finish();
+  }
+};
+
+size_t DynamicArchiveBuilder::estimate_archive_size() {
+  // size of the symbol table and two dictionaries, plus the RunTimeSharedClassInfo's
+  _estimated_hashtable_bytes = 0;
+  _estimated_hashtable_bytes += SymbolTable::estimate_size_for_archive();
+  _estimated_hashtable_bytes += SystemDictionaryShared::estimate_size_for_archive();
+
+  _estimated_trampoline_bytes = estimate_trampoline_size();
+
+  size_t total = 0;
+
+  total += _estimated_metsapceobj_bytes;
+  total += _estimated_hashtable_bytes;
+  total += _estimated_trampoline_bytes;
+
+  // allow fragmentation at the end of each dump region
+  total += _total_dump_regions * reserve_alignment();
+
+  return align_up(total, reserve_alignment());
+}
+
+address DynamicArchiveBuilder::reserve_space_and_init_buffer_to_target_delta() {
+  size_t total = estimate_archive_size();
+  bool large_pages = false; // No large pages when dumping the CDS archive.
+  size_t increment = align_up(1*G, reserve_alignment());
+  char* addr = (char*)align_up(CompressedKlassPointers::base() + MetaspaceSize + increment,
+                               reserve_alignment());
+
+  ReservedSpace* rs = MetaspaceShared::reserve_shared_rs(
+                          total, reserve_alignment(), large_pages, addr);
+  while (!rs->is_reserved() && (addr + increment > addr)) {
+    addr += increment;
+    rs = MetaspaceShared::reserve_shared_rs(
+           total, reserve_alignment(), large_pages, addr);
+  }
+  if (!rs->is_reserved()) {
+    log_error(cds, dynamic)("Failed to reserve %d bytes of output buffer.", (int)total);
+    vm_direct_exit(0);
+  }
+
+  address buffer_base = (address)rs->base();
+  log_info(cds, dynamic)("Reserved output buffer space at    : " PTR_FORMAT " [%d bytes]",
+                         p2i(buffer_base), (int)total);
+
+  // At run time, we will mmap the dynamic archive at target_space_bottom.
+  // However, at dump time, we may not be able to write into the target_space,
+  // as it's occupied by dynamically loaded Klasses. So we allocate a buffer
+  // at an arbitrary location chosen by the OS. We will write all the dynamically
+  // archived classes into this buffer. At the final stage of dumping, we relocate
+  // all pointers that are inside the buffer_space to point to their (runtime)
+  // target location inside thetarget_space.
+  address target_space_bottom =
+    (address)align_up(MetaspaceShared::shared_metaspace_top(), reserve_alignment());
+  _buffer_to_target_delta = intx(target_space_bottom) - intx(buffer_base);
+
+  log_info(cds, dynamic)("Target archive space at            : " PTR_FORMAT, p2i(target_space_bottom));
+  log_info(cds, dynamic)("Buffer-space to target-space delta : " PTR_FORMAT, p2i((address)_buffer_to_target_delta));
+
+  return buffer_base;
+}
+
+void DynamicArchiveBuilder::init_header(address reserved_bottom) {
+  _alloc_bottom = reserved_bottom;
+  _last_verified_top = reserved_bottom;
+  _other_region_used_bytes = 0;
+
+  init_first_dump_space(reserved_bottom);
+
+  FileMapInfo* mapinfo = new FileMapInfo(false);
+  _header = (DynamicArchiveHeader*)mapinfo->_header;
+
+  Thread* THREAD = Thread::current();
+  FileMapInfo* base_info = FileMapInfo::current_info();
+  int* crc = _header->_base_archive_crc;
+  *crc++ = base_info->crc(); // base archive header crc
+  for (int i = 0; i < MetaspaceShared::n_regions; i++) {
+    *crc++ = base_info->space_crc(i);
+  }
+  _header->populate(base_info, os::vm_allocation_granularity());
+}
+
+size_t DynamicArchiveBuilder::estimate_trampoline_size() {
+  size_t total = 0;
+  size_t each_method_bytes =
+    align_up(SharedRuntime::trampoline_size(), BytesPerWord) +
+    align_up(sizeof(AdapterHandlerEntry*), BytesPerWord);
+
+  for (int i = 0; i < _klasses->length(); i++) {
+    InstanceKlass* ik = _klasses->at(i);
+    Array<Method*>* methods = ik->methods();
+    total += each_method_bytes * methods->length();
+  }
+  return total;
+}
+
+void DynamicArchiveBuilder::make_trampolines() {
+  for (int i = 0; i < _klasses->length(); i++) {
+    InstanceKlass* ik = _klasses->at(i);
+    Array<Method*>* methods = ik->methods();
+    for (int j = 0; j < methods->length(); j++) {
+      Method* m = methods->at(j);
+      address c2i_entry_trampoline =
+        (address)MetaspaceShared::misc_code_space_alloc(SharedRuntime::trampoline_size());
+      m->set_from_compiled_entry(to_target(c2i_entry_trampoline));
+      AdapterHandlerEntry** adapter_trampoline =
+        (AdapterHandlerEntry**)MetaspaceShared::misc_code_space_alloc(sizeof(AdapterHandlerEntry*));
+      *adapter_trampoline = NULL;
+      m->set_adapter_trampoline(to_target(adapter_trampoline));
+    }
+  }
+}
+
+void DynamicArchiveBuilder::make_klasses_shareable() {
+  int i, count = _klasses->length();
+
+  for (i = 0; i < count; i++) {
+    InstanceKlass* ik = _klasses->at(i);
+    sort_methods(ik);
+  }
+
+  for (i = 0; i < count; i++) {
+    InstanceKlass* ik = _klasses->at(i);
+    ClassLoaderData *cld = ik->class_loader_data();
+    if (cld->is_boot_class_loader_data()) {
+      ik->set_class_loader_type(ClassLoader::BOOT_LOADER);
+    }
+    else if (cld->is_platform_class_loader_data()) {
+      ik->set_class_loader_type(ClassLoader::PLATFORM_LOADER);
+    }
+    else if (cld->is_system_class_loader_data()) {
+      ik->set_class_loader_type(ClassLoader::APP_LOADER);
+    }
+
+    MetaspaceShared::rewrite_nofast_bytecodes_and_calculate_fingerprints(ik);
+    ik->remove_unshareable_info();
+
+    assert(ik->array_klasses() == NULL, "sanity");
+
+    if (log_is_enabled(Debug, cds, dynamic)) {
+      ResourceMark rm;
+      log_debug(cds, dynamic)("klasses[%4i] = " PTR_FORMAT " %s", i, p2i(to_target(ik)), ik->external_name());
+    }
+  }
+}
+
+// The address order of the copied Symbols may be different than when the original
+// klasses were created. Re-sort all the tables. See Method::sort_methods().
+void DynamicArchiveBuilder::sort_methods(InstanceKlass* ik) const {
+  assert(ik != NULL, "DynamicArchiveBuilder currently doesn't support dumping the base archive");
+  if (MetaspaceShared::is_in_shared_metaspace(ik)) {
+    // We have reached a supertype that's already in the base archive
+    return;
+  }
+
+  if (ik->java_mirror() == NULL) {
+    // NULL mirror means this class has already been visited and methods are already sorted
+    return;
+  }
+  ik->remove_java_mirror();
+
+  if (log_is_enabled(Debug, cds, dynamic)) {
+    ResourceMark rm;
+    log_debug(cds, dynamic)("sorting methods for " PTR_FORMAT " %s", p2i(to_target(ik)), ik->external_name());
+  }
+
+  // Make sure all supertypes have been sorted
+  sort_methods(ik->java_super());
+  Array<InstanceKlass*>* interfaces = ik->local_interfaces();
+  int len = interfaces->length();
+  for (int i = 0; i < len; i++) {
+    sort_methods(interfaces->at(i));
+  }
+
+#ifdef ASSERT
+  {
+    for (int m = 0; m < ik->methods()->length(); m++) {
+      Symbol* name = ik->methods()->at(m)->name();
+      assert(MetaspaceShared::is_in_shared_metaspace(name) || is_in_buffer_space(name), "must be");
+    }
+  }
+#endif
+
+  Thread* THREAD = Thread::current();
+  Method::sort_methods(ik->methods());
+  if (ik->default_methods() != NULL) {
+    Method::sort_methods(ik->default_methods(), /*set_idnums=*/false);
+  }
+  ik->vtable().initialize_vtable(true, THREAD); assert(!HAS_PENDING_EXCEPTION, "cannot fail");
+  ik->itable().initialize_itable(true, THREAD); assert(!HAS_PENDING_EXCEPTION, "cannot fail");
+}
+
+void DynamicArchiveBuilder::set_symbols_permanent() {
+  int count = _symbols->length();
+  for (int i=0; i<count; i++) {
+    Symbol* s = _symbols->at(i);
+    s->set_permanent();
+
+    if (log_is_enabled(Trace, cds, dynamic)) {
+      ResourceMark rm;
+      log_trace(cds, dynamic)("symbols[%4i] = " PTR_FORMAT " %s", i, p2i(to_target(s)), s->as_quoted_ascii());
+    }
+  }
+}
+
+class RelocateBufferToTarget: public BitMapClosure {
+  DynamicArchiveBuilder *_builder;
+  address* _buffer_bottom;
+  intx _buffer_to_target_delta;
+ public:
+  RelocateBufferToTarget(DynamicArchiveBuilder* builder, address* bottom, intx delta) :
+    _builder(builder), _buffer_bottom(bottom), _buffer_to_target_delta(delta) {}
+
+  bool do_bit(size_t offset) {
+    address* p = _buffer_bottom + offset;
+    assert(_builder->is_in_buffer_space(p), "pointer must live in buffer space");
+
+    address old_ptr = *p;
+    if (_builder->is_in_buffer_space(old_ptr)) {
+      address new_ptr = old_ptr + _buffer_to_target_delta;
+      log_trace(cds, dynamic)("Final patch: @%6d [" PTR_FORMAT " -> " PTR_FORMAT "] " PTR_FORMAT " => " PTR_FORMAT,
+                              (int)offset, p2i(p), p2i(_builder->to_target(p)),
+                              p2i(old_ptr), p2i(new_ptr));
+      *p = new_ptr;
+    }
+
+    return true; // keep iterating
+  }
+};
+
+
+void DynamicArchiveBuilder::relocate_buffer_to_target() {
+  RelocateBufferToTarget patcher(this, (address*)_alloc_bottom, _buffer_to_target_delta);
+  _ptrmap.iterate(&patcher);
+
+  Array<u8>* table = _header->_shared_path_table.table();
+  table = to_target(table);
+ _header->_shared_path_table.set_table(table);
+}
+
+static void write_archive_info(FileMapInfo* dynamic_info, DynamicArchiveHeader *header) {
+  dynamic_info->write_header();
+  dynamic_info->align_file_position();
+  dynamic_info->write_region(MetaspaceShared::rw,
+                             MetaspaceShared::read_write_dump_space()->base(),
+                             MetaspaceShared::read_write_dump_space()->used(),
+                             /*read_only=*/false,/*allow_exec=*/false);
+  dynamic_info->write_region(MetaspaceShared::ro,
+                             MetaspaceShared::read_only_dump_space()->base(),
+                             MetaspaceShared::read_only_dump_space()->used(),
+                             /*read_only=*/true, /*allow_exec=*/false);
+  dynamic_info->write_region(MetaspaceShared::mc,
+                             MetaspaceShared::misc_code_dump_space()->base(),
+                             MetaspaceShared::misc_code_dump_space()->used(),
+                             /*read_only=*/false,/*allow_exec=*/true);
+}
+
+void DynamicArchiveBuilder::write_archive(char* read_only_tables_start) {
+  int num_klasses = _klasses->length();
+  int num_symbols = _symbols->length();
+
+  _header->_read_only_tables_start = to_target(read_only_tables_start);
+
+  FileMapInfo* dynamic_info = FileMapInfo::dynamic_info();
+  assert(dynamic_info != NULL, "Sanity");
+
+  // Populate the file offsets, region crcs, etc. No data is written out.
+  write_archive_info(dynamic_info, _header);
+
+  // the header will no longer change. Compute its crc.
+  dynamic_info->set_header_crc(dynamic_info->compute_header_crc());
+
+  // Now write the archived data including the file offsets.
+  const char* archive_name = Arguments::GetSharedDynamicArchivePath();
+  dynamic_info->open_for_write(archive_name);
+  write_archive_info(dynamic_info, _header);
+  dynamic_info->close();
+
+
+  address base = to_target(_alloc_bottom);
+  address top  = address(current_dump_space()->top()) + _buffer_to_target_delta;
+  int file_size = int(top - base);
+
+  log_info(cds, dynamic)("Written dynamic archive " PTR_FORMAT " - " PTR_FORMAT " [%d bytes header, %d bytes total]",
+                         p2i(base), p2i(top), (int)_header->_header_size, file_size);
+  log_info(cds, dynamic)("%d klasses; %d symbols", num_klasses, num_symbols);
+}
+
+
+class VM_PopulateDynamicDumpSharedSpace: public VM_Operation {
+  DynamicArchiveBuilder* _builder;
+public:
+  VM_PopulateDynamicDumpSharedSpace(DynamicArchiveBuilder* builder) : _builder(builder) {}
+  VMOp_Type type() const { return VMOp_PopulateDumpSharedSpace; }
+  void doit() {
+    ResourceMark rm;
+    if (SystemDictionaryShared::empty_dumptime_table()) {
+      log_warning(cds, dynamic)("There is no class to be included in the dynamic archive.");
+      return;
+    }
+    if (AllowArchivingWithJavaAgent) {
+      warning("This archive was created with AllowArchivingWithJavaAgent. It should be used "
+              "for testing purposes only and should not be used in a production environment");
+    }
+    FileMapInfo::check_nonempty_dir_in_shared_path_table();
+
+    _builder->doit();
+  }
+};
+
+
+void DynamicArchive::dump() {
+  if (Arguments::GetSharedDynamicArchivePath() == NULL) {
+    log_warning(cds, dynamic)("SharedDynamicArchivePath is not specified");
+    return;
+  }
+
+  DynamicArchiveBuilder builder;
+  _builder = &builder;
+  VM_PopulateDynamicDumpSharedSpace op(&builder);
+  VMThread::execute(&op);
+  _builder = NULL;
+}
+
+address DynamicArchive::original_to_buffer_impl(address orig_obj) {
+  assert(DynamicDumpSharedSpaces, "must be");
+  address buff_obj = _builder->get_new_loc(orig_obj);
+  assert(buff_obj != NULL, "orig_obj must be used by the dynamic archive");
+  assert(buff_obj != orig_obj, "call this only when you know orig_obj must be copied and not just referenced");
+  assert(_builder->is_in_buffer_space(buff_obj), "must be");
+  return buff_obj;
+}
+
+address DynamicArchive::buffer_to_target_impl(address buff_obj) {
+  assert(DynamicDumpSharedSpaces, "must be");
+  assert(_builder->is_in_buffer_space(buff_obj), "must be");
+  return _builder->to_target(buff_obj);
+}
+
+address DynamicArchive::original_to_target_impl(address orig_obj) {
+  assert(DynamicDumpSharedSpaces, "must be");
+  if (MetaspaceShared::is_in_shared_metaspace(orig_obj)) {
+    // This happens when the top archive points to a Symbol* in the base archive.
+    return orig_obj;
+  }
+  address buff_obj = _builder->get_new_loc(orig_obj);
+  assert(buff_obj != NULL, "orig_obj must be used by the dynamic archive");
+  if (buff_obj == orig_obj) {
+    // We are storing a pointer to an original object into the dynamic buffer. E.g.,
+    // a Symbol* that used by both the base and top archives.
+    assert(MetaspaceShared::is_in_shared_metaspace(orig_obj), "must be");
+    return orig_obj;
+  } else {
+    return _builder->to_target(buff_obj);
+  }
+}
+
+uintx DynamicArchive::object_delta_uintx(void* buff_obj) {
+  assert(DynamicDumpSharedSpaces, "must be");
+  address target_obj = _builder->to_target_no_check(address(buff_obj));
+  assert(uintx(target_obj) >= SharedBaseAddress, "must be");
+  return uintx(target_obj) - SharedBaseAddress;
+}
+
+bool DynamicArchive::is_in_target_space(void *obj) {
+  assert(DynamicDumpSharedSpaces, "must be");
+  return _builder->is_in_target_space(obj);
+}
+
+
+static DynamicArchiveHeader *_dynamic_header = NULL;
+DynamicArchiveBuilder* DynamicArchive::_builder = NULL;
+
+void DynamicArchive::map_failed(FileMapInfo* mapinfo) {
+  if (mapinfo->_header != NULL) {
+    os::free(mapinfo->_header);
+  }
+  delete mapinfo;
+}
+
+// Returns the top of the mapped address space
+address DynamicArchive::map() {
+  assert(UseSharedSpaces, "Sanity");
+
+  // Create the dynamic archive map info
+  FileMapInfo* mapinfo;
+  const char* filename = Arguments::GetSharedDynamicArchivePath();
+  struct stat st;
+  address result;
+  if ((filename != NULL) && (os::stat(filename, &st) == 0)) {
+    mapinfo = new FileMapInfo(false);
+    if (!mapinfo->open_for_read(filename)) {
+      result = NULL;
+    }
+    result = map_impl(mapinfo);
+    if (result == NULL) {
+      map_failed(mapinfo);
+      mapinfo->restore_shared_path_table();
+    }
+  } else {
+    if (filename != NULL) {
+      log_warning(cds, dynamic)("specified dynamic archive doesn't exist: %s", filename);
+    }
+    result = NULL;
+  }
+  return result;
+}
+
+address DynamicArchive::map_impl(FileMapInfo* mapinfo) {
+
+
+  // Read header
+  if (!mapinfo->initialize(false)) {
+    return NULL;
+  }
+
+  _dynamic_header = (DynamicArchiveHeader*)mapinfo->header();
+
+  int regions[] = {MetaspaceShared::rw,
+                   MetaspaceShared::ro,
+                   MetaspaceShared::mc};
+
+  size_t len = sizeof(regions)/sizeof(int);
+  char* saved_base[] = {NULL, NULL, NULL};
+  char* top = mapinfo->map_regions(regions, saved_base, len);
+  if (top == NULL) {
+    mapinfo->unmap_regions(regions, saved_base, len);
+    FileMapInfo::fail_continue("Unable to use dynamic archive. Failed map_region for using -Xshare:on.");
+    return NULL;
+  }
+
+  if (!validate(mapinfo)) {
+    return NULL;
+  }
+
+  if (_dynamic_header == NULL) {
+    return NULL;
+  }
+
+  intptr_t* buffer = (intptr_t*)_dynamic_header->_read_only_tables_start;
+  ReadClosure rc(&buffer);
+  SymbolTable::serialize_shared_table_header(&rc, false);
+  SystemDictionaryShared::serialize_dictionary_headers(&rc, false);
+
+  return (address)top;
+}
+
+bool DynamicArchive::validate(FileMapInfo* dynamic_info) {
+  // Check if the recorded base archive matches with the current one
+  FileMapInfo* base_info = FileMapInfo::current_info();
+  DynamicArchiveHeader* dynamic_header = (DynamicArchiveHeader*)dynamic_info->header();
+  int* crc = dynamic_header->_base_archive_crc;
+
+  // Check the header crc
+  if (*crc++ != base_info->crc()) {
+    FileMapInfo::fail_continue("Archive header checksum verification failed.");
+    return false;
+  }
+
+  // Check each space's crc
+  for (int i = 0; i < MetaspaceShared::n_regions; i++) {
+    if (*crc++ != base_info->space_crc(i)) {
+      FileMapInfo::fail_continue("Archive region #%d checksum verification failed.", i);
+      return false;
+    }
+  }
+
+  // Validate the dynamic archived shared path table, and set the global
+  // _shared_path_table to that.
+  if (!dynamic_info->validate_shared_path_table()) {
+    return false;
+  }
+  return true;
+}
+
+bool DynamicArchive::is_mapped() {
+  return (_dynamic_header != NULL);
+}
+
+void DynamicArchive::disable() {
+  _dynamic_header = NULL;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/memory/dynamicArchive.hpp	Fri May 17 08:29:55 2019 -0700
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2019, 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.
+ *
+ */
+
+#ifndef SHARE_VM_MEMORY_DYNAMICARCHIVE_HPP
+#define SHARE_VM_MEMORY_DYNAMICARCHIVE_HPP
+
+#if INCLUDE_CDS
+
+#include "classfile/compactHashtable.hpp"
+#include "memory/allocation.hpp"
+#include "memory/filemap.hpp"
+#include "memory/memRegion.hpp"
+#include "memory/virtualspace.hpp"
+#include "oops/oop.hpp"
+#include "utilities/exceptions.hpp"
+#include "utilities/macros.hpp"
+#include "utilities/resourceHash.hpp"
+
+// We want to include all archive header information in the dynamic archive.
+// This helps simplify the process if the base layer archive is missing at
+// dynamic archiving time.
+struct DynamicArchiveHeader : public FileMapHeader {
+  // crc for the base archive header and regions
+  int _base_archive_crc[MetaspaceShared::n_regions+1];
+};
+
+class DynamicArchive : AllStatic {
+  static class DynamicArchiveBuilder* _builder;
+  static address original_to_target_impl(address orig_obj);
+  static address original_to_buffer_impl(address orig_obj);
+  static address buffer_to_target_impl(address buff_obj);
+
+public:
+  static void dump();
+
+  // obj is a copy of a MetaspaceObj, stored in the dumping buffer.
+  //
+  // The return value is the runtime targeted location of this object as
+  // mapped from the dynamic archive.
+  template <typename T> static T buffer_to_target(T buff_obj) {
+    return (T)buffer_to_target_impl(address(buff_obj));
+  }
+
+  // obj is an original MetaspaceObj used by the JVM (e.g., a valid Symbol* in the
+  // SymbolTable).
+  //
+  // The return value is the runtime targeted location of this object as
+  // mapped from the dynamic archive.
+  template <typename T> static T original_to_target(T obj) {
+    return (T)original_to_target_impl(address(obj));
+  }
+
+  // obj is an original MetaspaceObj use by the JVM (e.g., a valid Symbol* in the
+  // SymbolTable).
+  //
+  // The return value is the location of this object in the dump time
+  // buffer space
+  template <typename T> static T original_to_buffer(T obj) {
+    return (T)original_to_buffer_impl(address(obj));
+  }
+
+  // Delta of this object from SharedBaseAddress
+  static uintx object_delta_uintx(void* buff_obj);
+
+  // Does obj point to an address inside the runtime target space of the dynamic
+  // archive?
+  static bool is_in_target_space(void *obj);
+
+  static address map();
+  static bool is_mapped();
+  static bool validate(FileMapInfo* dynamic_info);
+  static void disable();
+private:
+  static address map_impl(FileMapInfo* mapinfo);
+  static void map_failed(FileMapInfo* mapinfo);
+};
+#endif // INCLUDE_CDS
+#endif // SHARE_VM_MEMORY_DYNAMICARCHIVE_HPP
--- a/src/hotspot/share/memory/filemap.cpp	Fri May 17 10:48:02 2019 -0400
+++ b/src/hotspot/share/memory/filemap.cpp	Fri May 17 08:29:55 2019 -0700
@@ -34,6 +34,7 @@
 #include "logging/log.hpp"
 #include "logging/logStream.hpp"
 #include "logging/logMessage.hpp"
+#include "memory/dynamicArchive.hpp"
 #include "memory/filemap.hpp"
 #include "memory/heapShared.inline.hpp"
 #include "memory/iterator.inline.hpp"
@@ -42,6 +43,7 @@
 #include "memory/metaspaceShared.hpp"
 #include "memory/oopFactory.hpp"
 #include "memory/universe.hpp"
+#include "oops/compressedOops.hpp"
 #include "oops/compressedOops.inline.hpp"
 #include "oops/objArrayOop.hpp"
 #include "oops/oop.inline.hpp"
@@ -101,7 +103,12 @@
 void FileMapInfo::fail_continue(const char *msg, ...) {
   va_list ap;
   va_start(ap, msg);
-  MetaspaceShared::set_archive_loading_failed();
+  if (_dynamic_archive_info == NULL) {
+    MetaspaceShared::set_archive_loading_failed();
+  } else {
+    // _dynamic_archive_info has been setup after mapping the base archive
+    DynamicArchive::disable();
+  }
   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
@@ -120,9 +127,15 @@
         ls.vprint_cr(msg, ap);
       }
     }
-    UseSharedSpaces = false;
-    assert(current_info() != NULL, "singleton must be registered");
-    current_info()->close();
+    if (_dynamic_archive_info == NULL) {
+      UseSharedSpaces = false;
+      assert(current_info() != NULL, "singleton must be registered");
+      current_info()->close();
+    } else {
+      // We are failing when loading the top archive, but the base archive should
+      // continue to work.
+      log_warning(cds, dynamic)("Unable to use shared archive. The top archive failed to load: %s", _dynamic_archive_info->_full_path);
+    }
   }
   va_end(ap);
 }
@@ -159,20 +172,36 @@
   }
 }
 
-FileMapInfo::FileMapInfo() {
-  assert(_current_info == NULL, "must be singleton"); // not thread safe
-  _current_info = this;
+FileMapInfo::FileMapInfo(bool is_static) {
   memset((void*)this, 0, sizeof(FileMapInfo));
+  _is_static = is_static;
+  size_t header_size;
+  if (is_static) {
+    assert(_current_info == NULL, "must be singleton"); // not thread safe
+    _current_info = this;
+    header_size = sizeof(FileMapHeader);
+  } else {
+    assert(_dynamic_archive_info == NULL, "must be singleton"); // not thread safe
+    _dynamic_archive_info = this;
+    header_size = sizeof(DynamicArchiveHeader);
+  }
+  _header = (FileMapHeader*)os::malloc(header_size, mtInternal);
+  memset((void*)_header, 0, header_size);
+  _header->_header_size = header_size;
+  _header->_version = INVALID_CDS_ARCHIVE_VERSION;
+  _header->_has_platform_or_app_classes = true;
   _file_offset = 0;
   _file_open = false;
-  _header = (FileMapHeader*)os::malloc(sizeof(FileMapHeader), mtInternal);
-  _header->_version = INVALID_CDS_ARCHIVE_VERSION;
-  _header->_has_platform_or_app_classes = true;
 }
 
 FileMapInfo::~FileMapInfo() {
-  assert(_current_info == this, "must be singleton"); // not thread safe
-  _current_info = NULL;
+  if (_is_static) {
+    assert(_current_info == this, "must be singleton"); // not thread safe
+    _current_info = NULL;
+  } else {
+    assert(_dynamic_archive_info == this, "must be singleton"); // not thread safe
+    _dynamic_archive_info = NULL;
+  }
 }
 
 void FileMapInfo::populate_header(size_t alignment) {
@@ -180,7 +209,11 @@
 }
 
 void FileMapHeader::populate(FileMapInfo* mapinfo, size_t alignment) {
-  _magic = CDS_ARCHIVE_MAGIC;
+  if (DynamicDumpSharedSpaces) {
+    _magic = CDS_DYNAMIC_ARCHIVE_MAGIC;
+  } else {
+    _magic = CDS_ARCHIVE_MAGIC;
+  }
   _version = CURRENT_CDS_ARCHIVE_VERSION;
   _alignment = alignment;
   _obj_alignment = ObjectAlignmentInBytes;
@@ -191,9 +224,7 @@
   _max_heap_size = MaxHeapSize;
   _narrow_klass_base = CompressedKlassPointers::base();
   _narrow_klass_shift = CompressedKlassPointers::shift();
-  _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;
   if (HeapShared::is_heap_object_archiving_allowed()) {
     _heap_reserved = Universe::heap()->reserved_region();
   }
@@ -208,6 +239,7 @@
   ClassLoaderExt::finalize_shared_paths_misc_info();
   _app_class_paths_start_index = ClassLoaderExt::app_class_paths_start_index();
   _app_module_paths_start_index = ClassLoaderExt::app_module_paths_start_index();
+  _num_module_paths = ClassLoader::num_module_path_entries();
   _max_used_path_index = ClassLoaderExt::max_used_path_index();
 
   _verify_local = BytecodeVerificationLocal;
@@ -215,10 +247,13 @@
   _has_platform_or_app_classes = ClassLoaderExt::has_platform_or_app_classes();
   _shared_base_address = SharedBaseAddress;
   _allow_archiving_with_java_agent = AllowArchivingWithJavaAgent;
+  // the following 2 fields will be set in write_header for dynamic archive header
+  _base_archive_name_size = 0;
+  _base_archive_is_default = false;
 }
 
 void SharedClassPathEntry::init(const char* name, bool is_modules_image, TRAPS) {
-  assert(DumpSharedSpaces, "dump time only");
+  assert(DumpSharedSpaces || DynamicDumpSharedSpaces, "dump time only");
   _timestamp = 0;
   _filesize  = 0;
 
@@ -297,6 +332,7 @@
     // If PrintSharedArchiveAndExit is enabled, don't report failure to the
     // caller. Please see above comments for more details.
     ok = true;
+    MetaspaceShared::set_archive_loading_failed();
   }
   return ok;
 }
@@ -306,8 +342,27 @@
   it->push(&_manifest);
 }
 
+void SharedPathTable::metaspace_pointers_do(MetaspaceClosure* it) {
+  it->push(&_table);
+  for (int i=0; i<_size; i++) {
+    path_at(i)->metaspace_pointers_do(it);
+  }
+}
+
+void SharedPathTable::dumptime_init(ClassLoaderData* loader_data, Thread* THREAD) {
+  size_t entry_size = sizeof(SharedClassPathEntry);
+  int num_boot_classpath_entries = ClassLoader::num_boot_classpath_entries();
+  int num_app_classpath_entries = ClassLoader::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;
+
+  _table = MetadataFactory::new_array<u8>(loader_data, (int)(bytes + 7 / 8), THREAD);
+  _size = num_entries;
+}
+
 void FileMapInfo::allocate_shared_path_table() {
-  assert(DumpSharedSpaces, "Sanity");
+  assert(DumpSharedSpaces || DynamicDumpSharedSpaces, "Sanity");
 
   Thread* THREAD = Thread::current();
   ClassLoaderData* loader_data = ClassLoaderData::the_null_class_loader_data();
@@ -316,16 +371,7 @@
   assert(jrt != NULL,
          "No modular java runtime image present when allocating the CDS classpath entry table");
 
-  size_t entry_size = sizeof(SharedClassPathEntry); // 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_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;
-
-  _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;
+  _shared_path_table.dumptime_init(loader_data, THREAD);
 
   // 1. boot class path
   int i = 0;
@@ -343,7 +389,7 @@
     cpe = ClassLoader::get_next_boot_classpath_entry(cpe);
     i++;
   }
-  assert(i == num_boot_classpath_entries,
+  assert(i == ClassLoader::num_boot_classpath_entries(),
          "number of boot class path entry mismatch");
 
   // 2. app class path
@@ -369,15 +415,15 @@
     mpe = mpe->next();
     i++;
   }
-  assert(i == num_entries, "number of shared path entry mismatch");
+  assert(i == _shared_path_table.size(), "number of shared path entry mismatch");
 }
 
 void FileMapInfo::check_nonempty_dir_in_shared_path_table() {
-  assert(DumpSharedSpaces, "dump time only");
+  assert(DumpSharedSpaces || DynamicDumpSharedSpaces, "dump time only");
 
   bool has_nonempty_dir = false;
 
-  int last = _shared_path_table_size - 1;
+  int last = _shared_path_table.size() - 1;
   if (last > ClassLoaderExt::max_used_path_index()) {
      // no need to check any path beyond max_used_path_index
      last = ClassLoaderExt::max_used_path_index();
@@ -479,9 +525,29 @@
   assert(UseSharedSpaces, "runtime only");
 
   _validating_shared_path_table = true;
+
+  // Load the shared path table info from the archive header
   _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;
+  if (DynamicDumpSharedSpaces) {
+    // Only support dynamic dumping with the usage of the default CDS archive
+    // or a simple base archive.
+    // If the base layer archive contains additional path component besides
+    // the runtime image and the -cp, dynamic dumping is disabled.
+    //
+    // When dynamic archiving is enabled, the _shared_path_table is overwritten
+    // to include the application path and stored in the top layer archive.
+    assert(shared_path(0)->is_modules_image(), "first shared_path must be the modules image");
+    if (_header->_app_class_paths_start_index > 1) {
+      DynamicDumpSharedSpaces = false;
+      warning(
+        "Dynamic archiving is disabled because base layer archive has appended boot classpath");
+    }
+    if (_header->_num_module_paths > 0) {
+      DynamicDumpSharedSpaces = false;
+      warning(
+        "Dynamic archiving is disabled because base layer archive has module path");
+    }
+  }
 
   int module_paths_start_index = _header->_app_module_paths_start_index;
 
@@ -491,14 +557,18 @@
       if (shared_path(i)->validate()) {
         log_info(class, path)("ok");
       } else {
-        assert(!UseSharedSpaces, "UseSharedSpaces should be disabled");
+        if (_dynamic_archive_info != NULL && _dynamic_archive_info->_is_static) {
+          assert(!UseSharedSpaces, "UseSharedSpaces should be disabled");
+        }
         return false;
       }
     } else if (i >= module_paths_start_index) {
       if (shared_path(i)->validate(false /* not a class path entry */)) {
         log_info(class, path)("ok");
       } else {
-        assert(!UseSharedSpaces, "UseSharedSpaces should be disabled");
+        if (_dynamic_archive_info != NULL && _dynamic_archive_info->_is_static) {
+          assert(!UseSharedSpaces, "UseSharedSpaces should be disabled");
+        }
         return false;
       }
     }
@@ -510,18 +580,151 @@
   if (_classpath_entries_for_jvmti != NULL) {
     os::free(_classpath_entries_for_jvmti);
   }
-  size_t sz = sizeof(ClassPathEntry*) *  _shared_path_table_size;
+  size_t sz = sizeof(ClassPathEntry*) * get_number_of_shared_paths();
   _classpath_entries_for_jvmti = (ClassPathEntry**)os::malloc(sz, mtClass);
-  memset(_classpath_entries_for_jvmti, 0, sz);
+  memset((void*)_classpath_entries_for_jvmti, 0, sz);
 #endif
 
   return true;
 }
 
+bool FileMapInfo::same_files(const char* file1, const char* file2) {
+  if (strcmp(file1, file2) == 0) {
+    return true;
+  }
+
+  bool is_same = false;
+  // if the two paths diff only in case
+  struct stat st1;
+  struct stat st2;
+  int ret1;
+  int ret2;
+  ret1 = os::stat(file1, &st1);
+  ret2 = os::stat(file2, &st2);
+  if (ret1 < 0 || ret2 < 0) {
+    // one of the files is invalid. So they are not the same.
+    is_same = false;
+  } else if (st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino) {
+    // different files
+    is_same = false;
+#ifndef _WINDOWS
+  } else if (st1.st_dev == st2.st_dev && st1.st_ino == st2.st_ino) {
+    // same files
+    is_same = true;
+#else
+  } else if ((st1.st_size == st2.st_size) && (st1.st_ctime == st2.st_ctime) &&
+             (st1.st_mtime == st2.st_mtime)) {
+    // same files
+    is_same = true;
+#endif
+  }
+  return is_same;
+}
+
+bool FileMapInfo::check_archive(const char* archive_name, bool is_static) {
+  int fd = os::open(archive_name, O_RDONLY | O_BINARY, 0);
+  if (fd < 0) {
+    // do not vm_exit_during_initialization here because Arguments::init_shared_archive_paths()
+    // requires a shared archive name. The open_for_read() function will log a message regarding
+    // failure in opening a shared archive.
+    return false;
+  }
+
+  size_t sz = is_static ? sizeof(FileMapHeader) : sizeof(DynamicArchiveHeader);
+  void* header = os::malloc(sz, mtInternal);
+  memset(header, 0, sz);
+  size_t n = os::read(fd, header, (unsigned int)sz);
+  if (n != sz) {
+    os::free(header);
+    os::close(fd);
+    vm_exit_during_initialization("Unable to read header from shared archive", archive_name);
+    return false;
+  }
+  if (is_static) {
+    FileMapHeader* static_header = (FileMapHeader*)header;
+    if (static_header->_magic != CDS_ARCHIVE_MAGIC) {
+      os::free(header);
+      os::close(fd);
+      vm_exit_during_initialization("Not a base shared archive", archive_name);
+      return false;
+    }
+  } else {
+    DynamicArchiveHeader* dynamic_header = (DynamicArchiveHeader*)header;
+    if (dynamic_header->_magic != CDS_DYNAMIC_ARCHIVE_MAGIC) {
+      os::free(header);
+      os::close(fd);
+      vm_exit_during_initialization("Not a top shared archive", archive_name);
+      return false;
+    }
+  }
+  os::free(header);
+  os::close(fd);
+  return true;
+}
+
+bool FileMapInfo::get_base_archive_name_from_header(const char* archive_name,
+                                                    int* size, char** base_archive_name) {
+  int fd = os::open(archive_name, O_RDONLY | O_BINARY, 0);
+  if (fd < 0) {
+    *size = 0;
+    return false;
+  }
+
+  // read the header as a dynamic archive header
+  size_t sz = sizeof(DynamicArchiveHeader);
+  DynamicArchiveHeader* dynamic_header = (DynamicArchiveHeader*)os::malloc(sz, mtInternal);
+  size_t n = os::read(fd, dynamic_header, (unsigned int)sz);
+  if (n != sz) {
+    fail_continue("Unable to read the file header.");
+    os::free(dynamic_header);
+    os::close(fd);
+    return false;
+  }
+  if (dynamic_header->_magic != CDS_DYNAMIC_ARCHIVE_MAGIC) {
+    // Not a dynamic header, no need to proceed further.
+    *size = 0;
+    os::free(dynamic_header);
+    os::close(fd);
+    return false;
+  }
+  if (dynamic_header->_base_archive_is_default) {
+    *base_archive_name = Arguments::get_default_shared_archive_path();
+  } else {
+    // skip over the _paths_misc_info
+    sz = dynamic_header->_paths_misc_info_size;
+    lseek(fd, (long)sz, SEEK_CUR);
+    // read the base archive name
+    size_t name_size = dynamic_header->_base_archive_name_size;
+    if (name_size == 0) {
+      os::free(dynamic_header);
+      os::close(fd);
+      return false;
+    }
+    *base_archive_name = NEW_C_HEAP_ARRAY(char, name_size, mtInternal);
+    n = os::read(fd, *base_archive_name, (unsigned int)name_size);
+    if (n != name_size) {
+      fail_continue("Unable to read the base archive name from the header.");
+      FREE_C_HEAP_ARRAY(char, *base_archive_name);
+      *base_archive_name = NULL;
+      os::free(dynamic_header);
+      os::close(fd);
+      return false;
+    }
+  }
+
+  os::free(dynamic_header);
+  os::close(fd);
+  return true;
+}
+
+void FileMapInfo::restore_shared_path_table() {
+  _shared_path_table = _current_info->_header->_shared_path_table;
+}
+
 // Read the FileMapInfo information from the file.
 
-bool FileMapInfo::init_from_file(int fd) {
-  size_t sz = sizeof(FileMapHeader);
+bool FileMapInfo::init_from_file(int fd, bool is_static) {
+  size_t sz = is_static ? sizeof(FileMapHeader) : sizeof(DynamicArchiveHeader);
   size_t n = os::read(fd, _header, (unsigned int)sz);
   if (n != sz) {
     fail_continue("Unable to read the file header.");
@@ -531,14 +734,10 @@
     fail_continue("The shared archive file has the wrong version.");
     return false;
   }
-  _file_offset = (long)n;
+  _file_offset = n;
 
   size_t info_size = _header->_paths_misc_info_size;
-  _paths_misc_info = NEW_C_HEAP_ARRAY_RETURN_NULL(char, info_size, mtClass);
-  if (_paths_misc_info == NULL) {
-    fail_continue("Unable to read the file header.");
-    return false;
-  }
+  _paths_misc_info = NEW_C_HEAP_ARRAY(char, info_size, mtClass);
   n = os::read(fd, _paths_misc_info, (unsigned int)info_size);
   if (n != info_size) {
     fail_continue("Unable to read the shared path info header.");
@@ -546,29 +745,45 @@
     _paths_misc_info = NULL;
     return false;
   }
+  _file_offset += n + _header->_base_archive_name_size; // accounts for the size of _base_archive_name
 
-  size_t len = lseek(fd, 0, SEEK_END);
-  CDSFileMapRegion* si = space_at(MetaspaceShared::last_valid_region);
-  // The last space might be empty
-  if (si->_file_offset > len || len - si->_file_offset < si->_used) {
-    fail_continue("The shared archive file has been truncated.");
-    return false;
+  if (is_static) {
+    if (_header->_magic != CDS_ARCHIVE_MAGIC) {
+      fail_continue("Incorrect static archive magic number");
+      return false;
+    }
+    // just checking the last region is sufficient since the archive is written
+    // in sequential order
+    size_t len = lseek(fd, 0, SEEK_END);
+    CDSFileMapRegion* si = space_at(MetaspaceShared::last_valid_region);
+    // The last space might be empty
+    if (si->_file_offset > len || len - si->_file_offset < si->_used) {
+      fail_continue("The shared archive file has been truncated.");
+      return false;
+    }
+
+    SharedBaseAddress = _header->_shared_base_address;
   }
 
-  _file_offset += (long)n;
-  SharedBaseAddress = _header->_shared_base_address;
   return true;
 }
 
 
 // Read the FileMapInfo information from the file.
-bool FileMapInfo::open_for_read() {
-  _full_path = Arguments::GetSharedArchivePath();
+bool FileMapInfo::open_for_read(const char* path) {
+  if (_file_open) {
+    return true;
+  }
+  if (path == NULL) {
+    _full_path = Arguments::GetSharedArchivePath();
+  } else {
+    _full_path = path;
+  }
   int fd = os::open(_full_path, O_RDONLY | O_BINARY, 0);
   if (fd < 0) {
     if (errno == ENOENT) {
       // Not locating the shared archive is ok.
-      fail_continue("Specified shared archive not found.");
+      fail_continue("Specified shared archive not found (%s).", _full_path);
     } else {
       fail_continue("Failed to open shared archive file (%s).",
                     os::strerror(errno));
@@ -581,11 +796,14 @@
   return true;
 }
 
-
 // Write the FileMapInfo information to the file.
 
-void FileMapInfo::open_for_write() {
-  _full_path = Arguments::GetSharedArchivePath();
+void FileMapInfo::open_for_write(const char* path) {
+  if (path == NULL) {
+    _full_path = Arguments::GetSharedArchivePath();
+  } else {
+    _full_path = path;
+  }
   LogMessage(cds) msg;
   if (msg.is_info()) {
     msg.info("Dumping shared data to file: ");
@@ -593,7 +811,7 @@
   }
 
 #ifdef _WINDOWS  // On Windows, need WRITE permission to remove the file.
-  chmod(_full_path, _S_IREAD | _S_IWRITE);
+    chmod(_full_path, _S_IREAD | _S_IWRITE);
 #endif
 
   // Use remove() to delete the existing file because, on Unix, this will
@@ -617,40 +835,59 @@
 
   _header->_paths_misc_info_size = info_size;
 
-  align_file_position();
-  write_bytes(_header, sizeof(FileMapHeader));
+  char* base_archive_name = NULL;
+  if (_header->_magic == CDS_DYNAMIC_ARCHIVE_MAGIC) {
+    base_archive_name = (char*)Arguments::GetSharedArchivePath();
+    _header->_base_archive_name_size = (int)strlen(base_archive_name) + 1;
+    _header->_base_archive_is_default = FLAG_IS_DEFAULT(SharedArchiveFile);
+  }
+
+  assert(is_file_position_aligned(), "must be");
+  write_bytes(_header, _header->_header_size);
   write_bytes(ClassLoader::get_shared_paths_misc_info(), (size_t)info_size);
+  if (base_archive_name != NULL) {
+    write_bytes(base_archive_name, (size_t)_header->_base_archive_name_size);
+  }
   align_file_position();
 }
 
-
 // Dump region to file.
-
+// This is called twice for each region during archiving, once before
+// the archive file is open (_file_open is false) and once after.
 void FileMapInfo::write_region(int region, char* base, size_t size,
                                bool read_only, bool allow_exec) {
+  assert(DumpSharedSpaces || DynamicDumpSharedSpaces, "Dump time only");
+
   CDSFileMapRegion* si = space_at(region);
+  char* target_base = base;
+  if (DynamicDumpSharedSpaces) {
+    target_base = DynamicArchive::buffer_to_target(base);
+  }
 
   if (_file_open) {
     guarantee(si->_file_offset == _file_offset, "file offset mismatch.");
     log_info(cds)("Shared file region %d: " SIZE_FORMAT_HEX_W(08)
                   " bytes, addr " INTPTR_FORMAT " file offset " SIZE_FORMAT_HEX_W(08),
-                  region, size, p2i(base), _file_offset);
+                  region, size, p2i(target_base), _file_offset);
   } else {
     si->_file_offset = _file_offset;
   }
+
   if (HeapShared::is_heap_region(region)) {
-    assert((base - (char*)CompressedOops::base()) % HeapWordSize == 0, "Sanity");
-    if (base != NULL) {
-      si->_addr._offset = (intx)CompressedOops::encode_not_null((oop)base);
+    assert((target_base - (char*)CompressedKlassPointers::base()) % HeapWordSize == 0, "Sanity");
+    if (target_base != NULL) {
+      si->_addr._offset = (intx)CompressedOops::encode_not_null((oop)target_base);
     } else {
       si->_addr._offset = 0;
     }
   } else {
-    si->_addr._base = base;
+    si->_addr._base = target_base;
   }
   si->_used = size;
   si->_read_only = read_only;
   si->_allow_exec = allow_exec;
+
+  // Use the current 'base' when computing the CRC value and writing out data
   si->_crc = ClassLoader::crc32(0, base, (jint)size);
   if (base != NULL) {
     write_bytes_aligned(base, size);
@@ -734,8 +971,7 @@
   if (_file_open) {
     size_t n = os::write(_fd, buffer, (unsigned int)nbytes);
     if (n != nbytes) {
-      // It is dangerous to leave the corrupted shared archive file around,
-      // close and remove the file. See bug 6372906.
+      // If the shared archive is corrupted, close it and remove it.
       close();
       remove(_full_path);
       fail_stop("Unable to write to shared archive file.");
@@ -744,6 +980,10 @@
   _file_offset += nbytes;
 }
 
+bool FileMapInfo::is_file_position_aligned() const {
+  return _file_offset == align_up(_file_offset,
+                                  os::vm_allocation_granularity());
+}
 
 // Align file position to an allocation unit boundary.
 
@@ -843,6 +1083,30 @@
 static const char* shared_region_name[] = { "MiscData", "ReadWrite", "ReadOnly", "MiscCode", "OptionalData",
                                             "String1", "String2", "OpenArchive1", "OpenArchive2" };
 
+char* FileMapInfo::map_regions(int regions[], char* saved_base[], size_t len) {
+  char* prev_top = NULL;
+  char* curr_base;
+  char* curr_top;
+  int i = 0;
+  for (i = 0; i < (int)len; i++) {
+    curr_base = map_region(regions[i], &curr_top);
+    if (curr_base == NULL) {
+      return NULL;
+    }
+    if (i > 0) {
+      // We require that mc->rw->ro->md->od to be laid out consecutively, with no
+      // gaps between them. That way, we can ensure that the OS won't be able to
+      // allocate any new memory spaces inside _shared_metaspace_{base,top}, which
+      // would mess up the simple comparision in MetaspaceShared::is_in_shared_metaspace().
+      assert(curr_base == prev_top, "must be");
+    }
+    log_info(cds)("Mapped region #%d at base %p top %p", regions[i], curr_base, curr_top);
+    saved_base[i] = curr_base;
+    prev_top = curr_top;
+  }
+  return curr_top;
+}
+
 char* FileMapInfo::map_region(int i, char** top_ret) {
   assert(!HeapShared::is_heap_region(i), "sanity");
   CDSFileMapRegion* si = space_at(i);
@@ -869,6 +1133,7 @@
                               si->_allow_exec);
   if (base == NULL || base != requested_addr) {
     fail_continue("Unable to map %s shared space at required address.", shared_region_name[i]);
+    _memory_mapping_failed = true;
     return NULL;
   }
 #ifdef _WINDOWS
@@ -885,6 +1150,18 @@
   return base;
 }
 
+size_t FileMapInfo::read_bytes(void* buffer, size_t count) {
+  assert(_file_open, "Archive file is not open");
+  size_t n = os::read(_fd, buffer, (unsigned int)count);
+  if (n != count) {
+    // Close the file if there's a problem reading it.
+    close();
+    return 0;
+  }
+  _file_offset += count;
+  return count;
+}
+
 address FileMapInfo::decode_start_address(CDSFileMapRegion* spc, bool with_current_oop_encoding_mode) {
   if (with_current_oop_encoding_mode) {
     return (address)CompressedOops::decode_not_null(offset_of_space(spc));
@@ -1126,13 +1403,13 @@
                     p2i(addr), regions[i].byte_size());
       return false;
     }
-  }
 
-  if (!verify_mapped_heap_regions(first, region_num)) {
-    // dealloc the regions from java heap
-    dealloc_archive_heap_regions(regions, region_num, is_open_archive);
-    log_info(cds)("UseSharedSpaces: mapped heap regions are corrupt");
-    return false;
+    if (VerifySharedSpaces && !region_crc_check(addr, regions[i].byte_size(), si->_crc)) {
+      // dealloc the regions from java heap
+      dealloc_archive_heap_regions(regions, region_num, is_open_archive);
+      log_info(cds)("UseSharedSpaces: mapped heap regions are corrupt");
+      return false;
+    }
   }
 
   // the shared heap data is mapped successfully
@@ -1141,18 +1418,6 @@
   return true;
 }
 
-bool FileMapInfo::verify_mapped_heap_regions(int first, int num) {
-  assert(num > 0, "sanity");
-  if (VerifySharedSpaces) {
-    for (int i = first; i < first + num; i++) {
-      if (!verify_region_checksum(i)) {
-        return false;
-      }
-    }
-  }
-  return true;
-}
-
 void FileMapInfo::patch_archived_heap_embedded_pointers() {
   if (!_heap_pointers_need_patching) {
     return;
@@ -1205,6 +1470,15 @@
 }
 #endif // INCLUDE_CDS_JAVA_HEAP
 
+bool FileMapInfo::region_crc_check(char* buf, size_t size, int expected_crc) {
+  int crc = ClassLoader::crc32(0, buf, (jint)size);
+  if (crc != expected_crc) {
+    fail_continue("Checksum verification failed.");
+    return false;
+  }
+  return true;
+}
+
 bool FileMapInfo::verify_region_checksum(int i) {
   assert(VerifySharedSpaces, "sanity");
 
@@ -1213,19 +1487,16 @@
   if (sz == 0) {
     return true; // no data
   }
-  if ((HeapShared::is_closed_archive_heap_region(i) &&
-       !HeapShared::closed_archive_heap_region_mapped()) ||
-      (HeapShared::is_open_archive_heap_region(i) &&
-       !HeapShared::open_archive_heap_region_mapped())) {
-    return true; // archived heap data is not mapped
+
+  return region_crc_check(region_addr(i), sz, space_at(i)->_crc);
+}
+
+void FileMapInfo::unmap_regions(int regions[], char* saved_base[], size_t len) {
+  for (int i = 0; i < (int)len; i++) {
+    if (saved_base[i] != NULL) {
+      unmap_region(regions[i]);
+    }
   }
-  const char* buf = region_addr(i);
-  int crc = ClassLoader::crc32(0, buf, (jint)sz);
-  if (crc != space_at(i)->_crc) {
-    fail_continue("Checksum verification failed.");
-    return false;
-  }
-  return true;
 }
 
 // Unmap a memory region in the address space.
@@ -1253,19 +1524,15 @@
 }
 
 void FileMapInfo::metaspace_pointers_do(MetaspaceClosure* it) {
-  it->push(&_shared_path_table);
-  for (int i=0; i<_shared_path_table_size; i++) {
-    shared_path(i)->metaspace_pointers_do(it);
-  }
+  _shared_path_table.metaspace_pointers_do(it);
 }
 
-
 FileMapInfo* FileMapInfo::_current_info = NULL;
+FileMapInfo* FileMapInfo::_dynamic_archive_info = NULL;
 bool FileMapInfo::_heap_pointers_need_patching = false;
-Array<u8>* FileMapInfo::_shared_path_table = NULL;
-int FileMapInfo::_shared_path_table_size = 0;
-size_t FileMapInfo::_shared_path_entry_size = 0x1234baad;
+SharedPathTable FileMapInfo::_shared_path_table;
 bool FileMapInfo::_validating_shared_path_table = false;
+bool FileMapInfo::_memory_mapping_failed = false;
 
 // Open the shared archive file, read and validate the header
 // information (version, boot classpath, etc.).  If initialization
@@ -1277,7 +1544,7 @@
 // [1] validate_header() - done here. This checks the header, including _paths_misc_info.
 // [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() {
+bool FileMapInfo::initialize(bool is_static) {
   assert(UseSharedSpaces, "UseSharedSpaces expected.");
 
   if (JvmtiExport::should_post_class_file_load_hook() && JvmtiExport::has_early_class_hook_env()) {
@@ -1293,8 +1560,8 @@
     return false;
   }
 
-  init_from_file(_fd);
-  if (!validate_header()) {
+  init_from_file(_fd, is_static);
+  if (!validate_header(is_static)) {
     return false;
   }
   return true;
@@ -1315,7 +1582,7 @@
   char* start = (char*)this;
   // start computing from the field after _crc
   char* buf = (char*)&_crc + sizeof(_crc);
-  size_t sz = sizeof(FileMapHeader) - (buf - start);
+  size_t sz = _header_size - (buf - start);
   int crc = ClassLoader::crc32(0, buf, (jint)sz);
   return crc;
 }
@@ -1336,7 +1603,7 @@
     FileMapInfo::fail_continue("The shared archive file is the wrong version.");
     return false;
   }
-  if (_magic != CDS_ARCHIVE_MAGIC) {
+  if (_magic != CDS_ARCHIVE_MAGIC && _magic != CDS_DYNAMIC_ARCHIVE_MAGIC) {
     FileMapInfo::fail_continue("The shared archive file has a bad magic number.");
     return false;
   }
@@ -1401,11 +1668,11 @@
   return true;
 }
 
-bool FileMapInfo::validate_header() {
+bool FileMapInfo::validate_header(bool is_static) {
   bool status = _header->validate();
 
   if (status) {
-    if (!ClassLoader::check_shared_paths_misc_info(_paths_misc_info, _header->_paths_misc_info_size)) {
+    if (!ClassLoader::check_shared_paths_misc_info(_paths_misc_info, _header->_paths_misc_info_size, is_static)) {
       if (!PrintSharedArchiveAndExit) {
         fail_continue("shared class paths mismatch (hint: enable -Xlog:class+path=info to diagnose the failure)");
         status = false;
@@ -1435,7 +1702,7 @@
 
 // Unmap mapped regions of shared space.
 void FileMapInfo::stop_sharing_and_unmap(const char* msg) {
-  MetaspaceObj::set_shared_metaspace_range(NULL, NULL);
+  MetaspaceShared::set_shared_metaspace_range(NULL, NULL);
 
   FileMapInfo *map_info = FileMapInfo::current_info();
   if (map_info) {
@@ -1502,7 +1769,7 @@
 ClassFileStream* FileMapInfo::open_stream_for_jvmti(InstanceKlass* ik, Handle class_loader, TRAPS) {
   int path_index = ik->shared_classpath_index();
   assert(path_index >= 0, "should be called for shared built-in classes only");
-  assert(path_index < (int)_shared_path_table_size, "sanity");
+  assert(path_index < (int)get_number_of_shared_paths(), "sanity");
 
   ClassPathEntry* cpe = get_classpath_entry_for_jvmti(path_index, CHECK_NULL);
   assert(cpe != NULL, "must be");
--- a/src/hotspot/share/memory/filemap.hpp	Fri May 17 10:48:02 2019 -0400
+++ b/src/hotspot/share/memory/filemap.hpp	Fri May 17 08:29:55 2019 -0700
@@ -93,7 +93,32 @@
   size_t  _oopmap_size_in_bits;
 };
 
+class SharedPathTable {
+  Array<u8>* _table;
+  int _size;
+public:
+  void dumptime_init(ClassLoaderData* loader_data, Thread* THREAD);
+  void metaspace_pointers_do(MetaspaceClosure* it);
+
+  int size() {
+    return _size;
+  }
+  SharedClassPathEntry* path_at(int index) {
+    if (index < 0) {
+      return NULL;
+    }
+    assert(index < _size, "sanity");
+    char* p = (char*)_table->data();
+    p += sizeof(SharedClassPathEntry) * index;
+    return (SharedClassPathEntry*)p;
+  }
+  Array<u8>* table() {return _table;}
+  void set_table(Array<u8>* table) {_table = table;}
+
+};
+
 struct FileMapHeader : public CDSFileMapHeaderBase {
+  size_t _header_size;
   size_t _alignment;                // how shared archive should be aligned
   int    _obj_alignment;            // value of ObjectAlignmentInBytes
   address _narrow_oop_base;         // compressed oop encoding base
@@ -110,12 +135,16 @@
   size_t  _core_spaces_size;        // number of bytes allocated by the core spaces
                                     // (mc, md, ro, rw and od).
   MemRegion _heap_reserved;         // reserved region for the entire heap at dump time.
+  bool _base_archive_is_default;    // indicates if the base archive is the system default one
 
   // The following fields are all sanity checks for whether this archive
   // will function correctly with this JVM and the bootclasspath it's
   // invoked with.
   char  _jvm_ident[JVM_IDENT_MAX];      // identifier for jvm
 
+  // size of the base archive name including NULL terminator
+  int _base_archive_name_size;
+
   // The _paths_misc_info is a variable-size structure that records "miscellaneous"
   // information during dumping. It is generated and validated by the
   // SharedPathsMiscInfo class. See SharedPathsMiscInfo.hpp for
@@ -140,12 +169,11 @@
   // 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 _shared_path_table_size;
-  size_t _shared_path_entry_size;
-  Array<u8>* _shared_path_table;
+  SharedPathTable _shared_path_table;
 
   jshort _app_class_paths_start_index;  // Index of first app classpath entry
   jshort _app_module_paths_start_index; // Index of first module path entry
+  jshort _num_module_paths;             // number of module path entries
   jshort _max_used_path_index;          // max path index referenced during CDS dump
   bool   _verify_local;                 // BytecodeVerificationLocal setting
   bool   _verify_remote;                // BytecodeVerificationRemote setting
@@ -161,13 +189,14 @@
   jshort app_module_paths_start_index() { return _app_module_paths_start_index; }
 
   bool validate();
-  void populate(FileMapInfo* info, size_t alignment);
   int compute_crc();
 
   CDSFileMapRegion* space_at(int i) {
     assert(i >= 0 && i < NUM_CDS_REGIONS, "invalid region");
     return &_space[i];
   }
+public:
+  void populate(FileMapInfo* info, size_t alignment);
 };
 
 class FileMapInfo : public CHeapObj<mtInternal> {
@@ -176,14 +205,14 @@
   friend class VMStructs;
   friend struct FileMapHeader;
 
+  bool    _is_static;
   bool    _file_open;
   int     _fd;
   size_t  _file_offset;
 
 private:
-  static Array<u8>*            _shared_path_table;
-  static int                   _shared_path_table_size;
-  static size_t                _shared_path_entry_size;
+  // TODO: Probably change the following to be non-static
+  static SharedPathTable       _shared_path_table;
   static bool                  _validating_shared_path_table;
 
   // FileMapHeader describes the shared space data in the file to be
@@ -202,24 +231,31 @@
 
   const char* _full_path;
   char* _paths_misc_info;
+  char* _base_archive_name;
 
   static FileMapInfo* _current_info;
+  static FileMapInfo* _dynamic_archive_info;
   static bool _heap_pointers_need_patching;
-
-  bool  init_from_file(int fd);
-  void  align_file_position();
-  bool  validate_header_impl();
+  static bool _memory_mapping_failed;
+  static bool get_base_archive_name_from_header(const char* archive_name,
+                                                int* size, char** base_archive_name);
+  static bool check_archive(const char* archive_name, bool is_static);
+  static bool  same_files(const char* file1, const char* file2);
+  void restore_shared_path_table();
+  bool  init_from_file(int fd, bool is_static);
   static void metaspace_pointers_do(MetaspaceClosure* it);
 
 public:
-  FileMapInfo();
+  FileMapInfo(bool is_static);
   ~FileMapInfo();
 
   int    compute_header_crc()         { return _header->compute_crc(); }
   void   set_header_crc(int crc)      { _header->_crc = crc; }
+  int    space_crc(int i)             { return space_at(i)->_crc; }
   void   populate_header(size_t alignment);
-  bool   validate_header();
+  bool   validate_header(bool is_static);
   void   invalidate();
+  int    crc()                        { return _header->_crc; }
   int    version()                    { return _header->_version; }
   size_t alignment()                  { return _header->_alignment; }
   CompressedOops::Mode narrow_oop_mode() { return _header->_narrow_oop_mode; }
@@ -234,6 +270,9 @@
   char* read_only_tables_start()              { return _header->_read_only_tables_start; }
   void set_read_only_tables_start(char* p)    { _header->_read_only_tables_start = p; }
 
+  bool  is_file_position_aligned() const;
+  void  align_file_position();
+
   address cds_i2i_entry_code_buffers() {
     return _header->_cds_i2i_entry_code_buffers;
   }
@@ -254,12 +293,21 @@
     NOT_CDS(return NULL;)
   }
 
+  static void set_current_info(FileMapInfo* info) {
+    CDS_ONLY(_current_info = info;)
+  }
+
+  static FileMapInfo* dynamic_info() {
+    CDS_ONLY(return _dynamic_archive_info;)
+    NOT_CDS(return NULL;)
+  }
+
   static void assert_mark(bool check);
 
   // File manipulation.
-  bool  initialize() NOT_CDS_RETURN_(false);
-  bool  open_for_read();
-  void  open_for_write();
+  bool  initialize(bool is_static) NOT_CDS_RETURN_(false);
+  bool  open_for_read(const char* path = NULL);
+  void  open_for_write(const char* path = NULL);
   void  write_header();
   void  write_region(int region, char* base, size_t size,
                      bool read_only, bool allow_exec);
@@ -269,6 +317,8 @@
                                     bool print_log);
   void  write_bytes(const void* buffer, size_t count);
   void  write_bytes_aligned(const void* buffer, size_t count);
+  size_t  read_bytes(void* buffer, size_t count);
+  char* map_regions(int regions[], char* saved_base[], size_t len);
   char* map_region(int i, char** top_ret);
   void  map_heap_regions_impl() NOT_CDS_JAVA_HEAP_RETURN;
   void  map_heap_regions() NOT_CDS_JAVA_HEAP_RETURN;
@@ -278,6 +328,7 @@
                                               int first_region_idx) NOT_CDS_JAVA_HEAP_RETURN;
   bool  has_heap_regions()  NOT_CDS_JAVA_HEAP_RETURN_(false);
   MemRegion get_heap_regions_range_with_current_oop_encoding_mode() NOT_CDS_JAVA_HEAP_RETURN_(MemRegion());
+  void  unmap_regions(int regions[], char* saved_base[], size_t len);
   void  unmap_region(int i);
   bool  verify_region_checksum(int i);
   void  close();
@@ -291,7 +342,10 @@
   // Errors.
   static void fail_stop(const char *msg, ...) ATTRIBUTE_PRINTF(1, 2);
   static void fail_continue(const char *msg, ...) ATTRIBUTE_PRINTF(1, 2);
-
+  static bool memory_mapping_failed() {
+    CDS_ONLY(return _memory_mapping_failed;)
+    NOT_CDS(return false;)
+  }
   bool is_in_shared_region(const void* p, int idx) NOT_CDS_RETURN_(false);
 
   // Stop CDS sharing and unmap CDS regions.
@@ -307,13 +361,7 @@
 #endif
 
   static SharedClassPathEntry* shared_path(int index) {
-    if (index < 0) {
-      return NULL;
-    }
-    assert(index < _shared_path_table_size, "sanity");
-    char* p = (char*)_shared_path_table->data();
-    p += _shared_path_entry_size * index;
-    return (SharedClassPathEntry*)p;
+    return _shared_path_table.path_at(index);
   }
 
   static const char* shared_path_name(int index) {
@@ -322,7 +370,7 @@
   }
 
   static int get_number_of_shared_paths() {
-    return _shared_path_table_size;
+    return _shared_path_table.size();
   }
 
   char* region_addr(int idx);
@@ -330,7 +378,7 @@
  private:
   bool  map_heap_data(MemRegion **heap_mem, int first, int max, int* num,
                       bool is_open = false) NOT_CDS_JAVA_HEAP_RETURN_(false);
-  bool  verify_mapped_heap_regions(int first, int num) NOT_CDS_JAVA_HEAP_RETURN_(false);
+  bool  region_crc_check(char* buf, size_t size, int expected_crc) NOT_CDS_RETURN_(false);
   void  dealloc_archive_heap_regions(MemRegion* regions, int num, bool is_open) NOT_CDS_JAVA_HEAP_RETURN;
 
   CDSFileMapRegion* space_at(int i) {
--- a/src/hotspot/share/memory/heapShared.cpp	Fri May 17 10:48:02 2019 -0400
+++ b/src/hotspot/share/memory/heapShared.cpp	Fri May 17 08:29:55 2019 -0700
@@ -418,8 +418,7 @@
 
   _run_time_subgraph_info_table.reset();
 
-  int num_buckets = CompactHashtableWriter::default_num_buckets(d_table->_count);
-  CompactHashtableWriter writer(num_buckets, &stats);
+  CompactHashtableWriter writer(d_table->_count, &stats);
   CopyKlassSubGraphInfoToArchive copy(&writer);
   d_table->iterate(&copy);
 
--- a/src/hotspot/share/memory/heapShared.hpp	Fri May 17 10:48:02 2019 -0400
+++ b/src/hotspot/share/memory/heapShared.hpp	Fri May 17 08:29:55 2019 -0700
@@ -286,16 +286,6 @@
                                idx <= MetaspaceShared::last_open_archive_heap_region));
     NOT_CDS_JAVA_HEAP_RETURN_(false);
   }
-  static bool is_closed_archive_heap_region(int idx) {
-    CDS_JAVA_HEAP_ONLY(return (idx >= MetaspaceShared::first_closed_archive_heap_region &&
-                               idx <= MetaspaceShared::last_closed_archive_heap_region));
-    NOT_CDS_JAVA_HEAP_RETURN_(false);
-  }
-  static bool is_open_archive_heap_region(int idx) {
-    CDS_JAVA_HEAP_ONLY(return (idx >= MetaspaceShared::first_open_archive_heap_region &&
-                               idx <= MetaspaceShared::last_open_archive_heap_region));
-    NOT_CDS_JAVA_HEAP_RETURN_(false);
-  }
 
   static void set_closed_archive_heap_region_mapped() {
     CDS_JAVA_HEAP_ONLY(_closed_archive_heap_region_mapped = true);
--- a/src/hotspot/share/memory/memRegion.cpp	Fri May 17 10:48:02 2019 -0400
+++ b/src/hotspot/share/memory/memRegion.cpp	Fri May 17 08:29:55 2019 -0700
@@ -118,4 +118,3 @@
 void  MemRegion::operator delete [](void* p) {
   FreeHeap(p);
 }
-
--- a/src/hotspot/share/memory/metaspace.cpp	Fri May 17 10:48:02 2019 -0400
+++ b/src/hotspot/share/memory/metaspace.cpp	Fri May 17 08:29:55 2019 -0700
@@ -1220,6 +1220,10 @@
     MetaspaceShared::initialize_runtime_shared_and_meta_spaces();
   }
 
+  if (DynamicDumpSharedSpaces && !UseSharedSpaces) {
+    vm_exit_during_initialization("DynamicDumpSharedSpaces not supported when base CDS archive is not loaded", NULL);
+  }
+
   if (!DumpSharedSpaces && !UseSharedSpaces)
 #endif // INCLUDE_CDS
   {
--- a/src/hotspot/share/memory/metaspaceClosure.cpp	Fri May 17 10:48:02 2019 -0400
+++ b/src/hotspot/share/memory/metaspaceClosure.cpp	Fri May 17 08:29:55 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, 2019, 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,9 +34,20 @@
   *(address*)mpp() = (address)p;
 }
 
-void MetaspaceClosure::push_impl(MetaspaceClosure::Ref* ref, Writability w) {
-  if (ref->not_null()) {
+void MetaspaceClosure::push_impl(MetaspaceClosure::Ref* ref) {
+  if (_nest_level < MAX_NEST_LEVEL) {
+    do_push(ref);
+    delete ref;
+  } else {
+    ref->set_next(_pending_refs);
+    _pending_refs = ref;
+  }
+}
+
+void MetaspaceClosure::do_push(MetaspaceClosure::Ref* ref) {
+  if (ref->not_null()) { // FIXME: make this configurable, so DynamicArchiveBuilder mark all pointers
     bool read_only;
+    Writability w = ref->writability();
     switch (w) {
     case _writable:
       read_only = false;
@@ -48,12 +59,29 @@
       assert(w == _default, "must be");
       read_only = ref->is_read_only_by_default();
     }
+    _nest_level ++;
     if (do_ref(ref, read_only)) { // true means we want to iterate the embedded pointer in <ref>
       ref->metaspace_pointers_do(this);
     }
+    _nest_level --;
   }
 }
 
+void MetaspaceClosure::finish() {
+  assert(_nest_level == 0, "must be");
+  while (_pending_refs != NULL) {
+    Ref* ref = _pending_refs;
+    _pending_refs = _pending_refs->next();
+    do_push(ref);
+    delete ref;
+  }
+}
+
+MetaspaceClosure::~MetaspaceClosure() {
+  assert(_pending_refs == NULL,
+         "you must explicitly call MetaspaceClosure::finish() to process all refs!");
+}
+
 bool UniqueMetaspaceClosure::do_ref(MetaspaceClosure::Ref* ref, bool read_only) {
   bool* found = _has_been_visited.lookup(ref->obj());
   if (found != NULL) {
@@ -64,7 +92,6 @@
     if (_has_been_visited.maybe_grow(MAX_TABLE_SIZE)) {
       log_info(cds, hashtables)("Expanded _has_been_visited table to %d", _has_been_visited.table_size());
     }
-    do_unique_ref(ref, read_only);
-    return true;  // Saw this for the first time: iterate the embedded pointers.
+    return do_unique_ref(ref, read_only);
   }
 }
--- a/src/hotspot/share/memory/metaspaceClosure.hpp	Fri May 17 10:48:02 2019 -0400
+++ b/src/hotspot/share/memory/metaspaceClosure.hpp	Fri May 17 08:29:55 2019 -0700
@@ -101,9 +101,15 @@
   //         Symbol*     bar() { return (Symbol*)    _obj; }
   //
   // [2] All Array<T> dimensions are statically declared.
-  class Ref {
+  class Ref : public CHeapObj<mtInternal> {
+    Writability _writability;
+    Ref* _next;
+    // Noncopyable.
+    Ref(const Ref&);
+    Ref& operator=(const Ref&);
   protected:
     virtual void** mpp() const = 0;
+    Ref(Writability w) : _writability(w), _next(NULL) {}
   public:
     virtual bool not_null() const = 0;
     virtual int size() const = 0;
@@ -111,6 +117,7 @@
     virtual void metaspace_pointers_do_at(MetaspaceClosure *it, address new_loc) const = 0;
     virtual MetaspaceObj::Type msotype() const = 0;
     virtual bool is_read_only_by_default() const = 0;
+    virtual ~Ref() {}
 
     address obj() const {
       // In some rare cases (see CPSlot in constantPool.hpp) we store some flags in the lowest
@@ -119,8 +126,16 @@
       return (address)(p & (~FLAG_MASK));
     }
 
+    address* addr() const {
+      return (address*)mpp();
+    }
+
     void update(address new_loc) const;
 
+    Writability writability() const { return _writability; };
+    void set_next(Ref* n)           { _next = n; }
+    Ref* next() const               { return _next; }
+
   private:
     static const uintx FLAG_MASK = 0x03;
 
@@ -143,7 +158,7 @@
     }
 
   public:
-    ObjectRef(T** mpp) : _mpp(mpp) {}
+    ObjectRef(T** mpp, Writability w) : Ref(w), _mpp(mpp) {}
 
     virtual bool is_read_only_by_default() const { return T::is_read_only_by_default(); }
     virtual bool not_null()                const { return dereference() != NULL; }
@@ -170,7 +185,7 @@
     }
 
   public:
-    PrimitiveArrayRef(Array<T>** mpp) : _mpp(mpp) {}
+    PrimitiveArrayRef(Array<T>** mpp, Writability w) : Ref(w), _mpp(mpp) {}
 
     // all Arrays are read-only by default
     virtual bool is_read_only_by_default() const { return true; }
@@ -200,7 +215,7 @@
     }
 
   public:
-    PointerArrayRef(Array<T*>** mpp) : _mpp(mpp) {}
+    PointerArrayRef(Array<T*>** mpp, Writability w) : Ref(w), _mpp(mpp) {}
 
     // all Arrays are read-only by default
     virtual bool is_read_only_by_default() const { return true; }
@@ -224,9 +239,21 @@
     }
   };
 
-  void push_impl(Ref* ref, Writability w);
+  // If recursion is too deep, save the Refs in _pending_refs, and push them later using
+  // MetaspaceClosure::finish()
+  static const int MAX_NEST_LEVEL = 5;
+  Ref* _pending_refs;
+  int _nest_level;
+
+  void push_impl(Ref* ref);
+  void do_push(Ref* ref);
 
 public:
+  MetaspaceClosure(): _pending_refs(NULL), _nest_level(0) {}
+  ~MetaspaceClosure();
+
+  void finish();
+
   // returns true if we want to keep iterating the pointers embedded inside <ref>
   virtual bool do_ref(Ref* ref, bool read_only) = 0;
 
@@ -237,22 +264,19 @@
   // C++ will try to match the "most specific" template function. This one will
   // will be matched if possible (if mpp is an Array<> of any pointer type).
   template <typename T> void push(Array<T*>** mpp, Writability w = _default) {
-    PointerArrayRef<T> ref(mpp);
-    push_impl(&ref, w);
+    push_impl(new PointerArrayRef<T>(mpp, w));
   }
 
   // If the above function doesn't match (mpp is an Array<>, but T is not a pointer type), then
   // this is the second choice.
   template <typename T> void push(Array<T>** mpp, Writability w = _default) {
-    PrimitiveArrayRef<T> ref(mpp);
-    push_impl(&ref, w);
+    push_impl(new PrimitiveArrayRef<T>(mpp, w));
   }
 
   // If the above function doesn't match (mpp is not an Array<> type), then
   // this will be matched by default.
   template <class T> void push(T** mpp, Writability w = _default) {
-    ObjectRef<T> ref(mpp);
-    push_impl(&ref, w);
+    push_impl(new ObjectRef<T>(mpp, w));
   }
 };
 
@@ -266,7 +290,7 @@
 
 public:
   // Gets called the first time we discover an object.
-  virtual void do_unique_ref(Ref* ref, bool read_only) = 0;
+  virtual bool do_unique_ref(Ref* ref, bool read_only) = 0;
   UniqueMetaspaceClosure() : _has_been_visited(INITIAL_TABLE_SIZE) {}
 
 private:
--- a/src/hotspot/share/memory/metaspaceShared.cpp	Fri May 17 10:48:02 2019 -0400
+++ b/src/hotspot/share/memory/metaspaceShared.cpp	Fri May 17 08:29:55 2019 -0700
@@ -48,10 +48,12 @@
 #include "memory/metaspaceShared.hpp"
 #include "memory/resourceArea.hpp"
 #include "memory/universe.hpp"
+#include "memory/dynamicArchive.hpp"
 #include "oops/compressedOops.inline.hpp"
 #include "oops/instanceClassLoaderKlass.hpp"
 #include "oops/instanceMirrorKlass.hpp"
 #include "oops/instanceRefKlass.hpp"
+#include "oops/methodData.hpp"
 #include "oops/objArrayKlass.hpp"
 #include "oops/objArrayOop.hpp"
 #include "oops/oop.inline.hpp"
@@ -81,6 +83,7 @@
 address MetaspaceShared::_cds_i2i_entry_code_buffers = NULL;
 size_t MetaspaceShared::_cds_i2i_entry_code_buffers_size = 0;
 size_t MetaspaceShared::_core_spaces_size = 0;
+void* MetaspaceShared::_shared_metaspace_static_top = NULL;
 
 // The CDS archive is divided into the following regions:
 //     mc  - misc code (the method entry trampolines)
@@ -112,105 +115,97 @@
 // The s0/s1 and oa0/oa1 regions are populated inside HeapShared::archive_java_heap_objects.
 // Their layout is independent of the other 5 regions.
 
-class DumpRegion {
-private:
-  const char* _name;
-  char* _base;
-  char* _top;
-  char* _end;
-  bool _is_packed;
-
-  char* expand_top_to(char* newtop) {
-    assert(is_allocatable(), "must be initialized and not packed");
-    assert(newtop >= _top, "must not grow backwards");
-    if (newtop > _end) {
-      MetaspaceShared::report_out_of_space(_name, newtop - _top);
-      ShouldNotReachHere();
-    }
-    uintx delta = MetaspaceShared::object_delta_uintx(newtop);
-    if (delta > MAX_SHARED_DELTA) {
-      // This is just a sanity check and should not appear in any real world usage. This
-      // happens only if you allocate more than 2GB of shared objects and would require
-      // millions of shared classes.
-      vm_exit_during_initialization("Out of memory in the CDS archive",
-                                    "Please reduce the number of shared classes.");
-    }
-
-    MetaspaceShared::commit_shared_space_to(newtop);
-    _top = newtop;
-    return _top;
+char* DumpRegion::expand_top_to(char* newtop) {
+  assert(is_allocatable(), "must be initialized and not packed");
+  assert(newtop >= _top, "must not grow backwards");
+  if (newtop > _end) {
+    MetaspaceShared::report_out_of_space(_name, newtop - _top);
+    ShouldNotReachHere();
+  }
+  uintx delta;
+  if (DynamicDumpSharedSpaces) {
+    delta = DynamicArchive::object_delta_uintx(newtop);
+  } else {
+    delta = MetaspaceShared::object_delta_uintx(newtop);
+  }
+  if (delta > MAX_SHARED_DELTA) {
+    // This is just a sanity check and should not appear in any real world usage. This
+    // happens only if you allocate more than 2GB of shared objects and would require
+    // millions of shared classes.
+    vm_exit_during_initialization("Out of memory in the CDS archive",
+                                  "Please reduce the number of shared classes.");
   }
 
-public:
-  DumpRegion(const char* name) : _name(name), _base(NULL), _top(NULL), _end(NULL), _is_packed(false) {}
+  MetaspaceShared::commit_shared_space_to(newtop);
+  _top = newtop;
+  return _top;
+}
 
-  char* allocate(size_t num_bytes, size_t alignment=BytesPerWord) {
-    char* p = (char*)align_up(_top, alignment);
-    char* newtop = p + align_up(num_bytes, alignment);
-    expand_top_to(newtop);
-    memset(p, 0, newtop - p);
-    return p;
+char* DumpRegion::allocate(size_t num_bytes, size_t alignment) {
+  char* p = (char*)align_up(_top, alignment);
+  char* newtop = p + align_up(num_bytes, alignment);
+  expand_top_to(newtop);
+  memset(p, 0, newtop - p);
+  return p;
+}
+
+void DumpRegion::print(size_t total_bytes) const {
+  tty->print_cr("%-3s space: " SIZE_FORMAT_W(9) " [ %4.1f%% of total] out of " SIZE_FORMAT_W(9) " bytes [%5.1f%% used] at " INTPTR_FORMAT,
+                _name, used(), percent_of(used(), total_bytes), reserved(), percent_of(used(), reserved()), p2i(_base));
+}
+
+void DumpRegion::print_out_of_space_msg(const char* failing_region, size_t needed_bytes) {
+  tty->print("[%-8s] " PTR_FORMAT " - " PTR_FORMAT " capacity =%9d, allocated =%9d",
+             _name, p2i(_base), p2i(_top), int(_end - _base), int(_top - _base));
+  if (strcmp(_name, failing_region) == 0) {
+    tty->print_cr(" required = %d", int(needed_bytes));
+  } else {
+    tty->cr();
   }
+}
 
-  void append_intptr_t(intptr_t n) {
-    assert(is_aligned(_top, sizeof(intptr_t)), "bad alignment");
-    intptr_t *p = (intptr_t*)_top;
-    char* newtop = _top + sizeof(intptr_t);
-    expand_top_to(newtop);
-    *p = n;
+void DumpRegion::pack(DumpRegion* next) {
+  assert(!is_packed(), "sanity");
+  _end = (char*)align_up(_top, Metaspace::reserve_alignment());
+  _is_packed = true;
+  if (next != NULL) {
+    next->_base = next->_top = this->_end;
+    next->_end = MetaspaceShared::shared_rs()->end();
   }
+}
 
-  char* base()      const { return _base;        }
-  char* top()       const { return _top;         }
-  char* end()       const { return _end;         }
-  size_t reserved() const { return _end - _base; }
-  size_t used()     const { return _top - _base; }
-  bool is_packed()  const { return _is_packed;   }
-  bool is_allocatable() const {
-    return !is_packed() && _base != NULL;
+DumpRegion _mc_region("mc"), _ro_region("ro"), _rw_region("rw"), _md_region("md"), _od_region("od");
+size_t _total_closed_archive_region_size = 0, _total_open_archive_region_size = 0;
+
+void MetaspaceShared::init_shared_dump_space(DumpRegion* first_space, address first_space_bottom) {
+  // Start with 0 committed bytes. The memory will be committed as needed by
+  // MetaspaceShared::commit_shared_space_to().
+  if (!_shared_vs.initialize(_shared_rs, 0)) {
+    vm_exit_during_initialization("Unable to allocate memory for shared space");
   }
+  first_space->init(&_shared_rs, (char*)first_space_bottom);
+}
 
-  void print(size_t total_bytes) const {
-    tty->print_cr("%-3s space: " SIZE_FORMAT_W(9) " [ %4.1f%% of total] out of " SIZE_FORMAT_W(9) " bytes [%5.1f%% used] at " INTPTR_FORMAT,
-                  _name, used(), percent_of(used(), total_bytes), reserved(), percent_of(used(), reserved()), p2i(_base));
-  }
-  void print_out_of_space_msg(const char* failing_region, size_t needed_bytes) {
-    tty->print("[%-8s] " PTR_FORMAT " - " PTR_FORMAT " capacity =%9d, allocated =%9d",
-               _name, p2i(_base), p2i(_top), int(_end - _base), int(_top - _base));
-    if (strcmp(_name, failing_region) == 0) {
-      tty->print_cr(" required = %d", int(needed_bytes));
-    } else {
-      tty->cr();
-    }
-  }
+DumpRegion* MetaspaceShared::misc_code_dump_space() {
+  return &_mc_region;
+}
 
-  void init(const ReservedSpace* rs) {
-    _base = _top = rs->base();
-    _end = rs->end();
-  }
-  void init(char* b, char* t, char* e) {
-    _base = b;
-    _top = t;
-    _end = e;
-  }
+DumpRegion* MetaspaceShared::read_write_dump_space() {
+  return &_rw_region;
+}
 
-  void pack(DumpRegion* next = NULL) {
-    assert(!is_packed(), "sanity");
-    _end = (char*)align_up(_top, Metaspace::reserve_alignment());
-    _is_packed = true;
-    if (next != NULL) {
-      next->_base = next->_top = this->_end;
-      next->_end = MetaspaceShared::shared_rs()->end();
-    }
-  }
-  bool contains(char* p) {
-    return base() <= p && p < top();
-  }
-};
+DumpRegion* MetaspaceShared::read_only_dump_space() {
+  return &_ro_region;
+}
 
+DumpRegion* MetaspaceShared::optional_data_dump_space() {
+  return &_od_region;
+}
 
-DumpRegion _mc_region("mc"), _ro_region("ro"), _rw_region("rw"), _md_region("md");
-size_t _total_closed_archive_region_size = 0, _total_open_archive_region_size = 0;
+void MetaspaceShared::pack_dump_space(DumpRegion* current, DumpRegion* next,
+                                      ReservedSpace* rs) {
+  current->pack(next);
+}
 
 char* MetaspaceShared::misc_code_space_alloc(size_t num_bytes) {
   return _mc_region.allocate(num_bytes);
@@ -226,20 +221,23 @@
   // If using shared space, open the file that contains the shared space
   // and map in the memory before initializing the rest of metaspace (so
   // the addresses don't conflict)
-  address cds_address = NULL;
-  FileMapInfo* mapinfo = new FileMapInfo();
+  FileMapInfo* mapinfo = new FileMapInfo(true);
 
   // Open the shared archive file, read and validate the header. If
   // initialization fails, shared spaces [UseSharedSpaces] are
   // disabled and the file is closed.
   // Map in spaces now also
-  if (mapinfo->initialize() && map_shared_spaces(mapinfo)) {
+  if (mapinfo->initialize(true) && map_shared_spaces(mapinfo)) {
     size_t cds_total = core_spaces_size();
-    cds_address = (address)mapinfo->region_addr(0);
+    address cds_address = (address)mapinfo->region_addr(0);
+    char* cds_end = (char *)align_up(cds_address + cds_total,
+                                     Metaspace::reserve_alignment());
+
+    // Mapping the dynamic archive before allocating the class space
+    cds_end = initialize_dynamic_runtime_shared_spaces((char*)cds_address, cds_end);
+
 #ifdef _LP64
     if (Metaspace::using_class_space()) {
-      char* cds_end = (char*)(cds_address + cds_total);
-      cds_end = (char *)align_up(cds_end, Metaspace::reserve_alignment());
       // If UseCompressedClassPointers is set then allocate the metaspace area
       // above the heap and above the CDS area (if it exists).
       Metaspace::allocate_metaspace_compressed_klass_ptrs(cds_end, cds_address);
@@ -255,6 +253,31 @@
   }
 }
 
+char* MetaspaceShared::initialize_dynamic_runtime_shared_spaces(
+        char* static_start, char* static_end) {
+  assert(UseSharedSpaces, "must be runtime");
+  char* cds_end = static_end;
+  if (!DynamicDumpSharedSpaces) {
+    address dynamic_top = DynamicArchive::map();
+    if (dynamic_top != NULL) {
+      assert(dynamic_top > (address)static_start, "Unexpected layout");
+      MetaspaceObj::expand_shared_metaspace_range(dynamic_top);
+      cds_end = (char *)align_up(dynamic_top, Metaspace::reserve_alignment());
+    }
+  }
+  return cds_end;
+}
+
+ReservedSpace* MetaspaceShared::reserve_shared_rs(size_t size, size_t alignment,
+                                                  bool large, char* requested_address) {
+  if (requested_address != NULL) {
+    _shared_rs = ReservedSpace(size, alignment, large, requested_address);
+  } else {
+    _shared_rs = ReservedSpace(size, alignment, large);
+  }
+  return &_shared_rs;
+}
+
 void MetaspaceShared::initialize_dumptime_shared_and_meta_spaces() {
   assert(DumpSharedSpaces, "should be called for dump time only");
   const size_t reserve_alignment = Metaspace::reserve_alignment();
@@ -280,12 +303,14 @@
 #endif
 
   // First try to reserve the space at the specified SharedBaseAddress.
-  _shared_rs = ReservedSpace(cds_total, reserve_alignment, large_pages, shared_base);
+  //_shared_rs = ReservedSpace(cds_total, reserve_alignment, large_pages, shared_base);
+  reserve_shared_rs(cds_total, reserve_alignment, large_pages, shared_base);
   if (_shared_rs.is_reserved()) {
     assert(shared_base == 0 || _shared_rs.base() == shared_base, "should match");
   } else {
     // Get a mmap region anywhere if the SharedBaseAddress fails.
-    _shared_rs = ReservedSpace(cds_total, reserve_alignment, large_pages);
+    //_shared_rs = ReservedSpace(cds_total, reserve_alignment, large_pages);
+    reserve_shared_rs(cds_total, reserve_alignment, large_pages, NULL);
   }
   if (!_shared_rs.is_reserved()) {
     vm_exit_during_initialization("Unable to reserve memory for shared space",
@@ -324,13 +349,7 @@
                 CompressedClassSpaceSize, p2i(tmp_class_space.base()));
 #endif
 
-  // Start with 0 committed bytes. The memory will be committed as needed by
-  // MetaspaceShared::commit_shared_space_to().
-  if (!_shared_vs.initialize(_shared_rs, 0)) {
-    vm_exit_during_initialization("Unable to allocate memory for shared space");
-  }
-
-  _mc_region.init(&_shared_rs);
+  init_shared_dump_space(&_mc_region);
   SharedBaseAddress = (size_t)_shared_rs.base();
   tty->print_cr("Allocated shared space: " SIZE_FORMAT " bytes at " PTR_FORMAT,
                 _shared_rs.size(), p2i(_shared_rs.base()));
@@ -342,9 +361,16 @@
     int size = FileMapInfo::get_number_of_shared_paths();
     if (size > 0) {
       SystemDictionaryShared::allocate_shared_data_arrays(size, THREAD);
-      FileMapHeader* header = FileMapInfo::current_info()->header();
-      ClassLoaderExt::init_paths_start_index(header->_app_class_paths_start_index);
-      ClassLoaderExt::init_app_module_paths_start_index(header->_app_module_paths_start_index);
+      if (!DynamicDumpSharedSpaces) {
+        FileMapHeader* header;
+        if (FileMapInfo::dynamic_info() == NULL) {
+          header = FileMapInfo::current_info()->header();
+        } else {
+          header = FileMapInfo::dynamic_info()->header();
+        }
+        ClassLoaderExt::init_paths_start_index(header->_app_class_paths_start_index);
+        ClassLoaderExt::init_app_module_paths_start_index(header->_app_module_paths_start_index);
+      }
     }
   }
 }
@@ -405,7 +431,7 @@
 }
 
 void MetaspaceShared::commit_shared_space_to(char* newtop) {
-  assert(DumpSharedSpaces, "dump-time only");
+  assert(DumpSharedSpaces || DynamicDumpSharedSpaces, "dump-time only");
   char* base = _shared_rs.base();
   size_t need_committed_size = newtop - base;
   size_t has_committed_size = _shared_vs.committed_size();
@@ -417,7 +443,8 @@
   size_t preferred_bytes = 1 * M;
   size_t uncommitted = _shared_vs.reserved_size() - has_committed_size;
 
-  size_t commit = MAX2(min_bytes, preferred_bytes);
+  size_t commit =MAX2(min_bytes, preferred_bytes);
+  commit = MIN2(commit, uncommitted);
   assert(commit <= uncommitted, "sanity");
 
   bool result = _shared_vs.expand_by(commit, false);
@@ -465,6 +492,9 @@
   InstanceMirrorKlass::serialize_offsets(soc);
   soc->do_tag(--tag);
 
+  serialize_cloned_cpp_vtptrs(soc);
+  soc->do_tag(--tag);
+
   soc->do_tag(666);
 }
 
@@ -484,6 +514,19 @@
   return _cds_i2i_entry_code_buffers;
 }
 
+uintx MetaspaceShared::object_delta_uintx(void* obj) {
+  assert(DumpSharedSpaces || DynamicDumpSharedSpaces,
+         "supported only for dumping");
+  if (DumpSharedSpaces) {
+    assert(shared_rs()->contains(obj), "must be");
+  } else {
+    assert(is_in_shared_metaspace(obj) || DynamicArchive::is_in_target_space(obj), "must be");
+  }
+  address base_address = address(SharedBaseAddress);
+  uintx deltax = address(obj) - base_address;
+  return deltax;
+}
+
 // Global object for holding classes that have been loaded.  Since this
 // is run at a safepoint just before exit, this is the entire set of classes.
 static GrowableArray<Klass*>* _global_klass_objects;
@@ -589,17 +632,21 @@
     Klass* k = _global_klass_objects->at(i);
     if (k->is_instance_klass()) {
       InstanceKlass* ik = InstanceKlass::cast(k);
-      for (int i = 0; i < ik->methods()->length(); i++) {
-        Method* m = ik->methods()->at(i);
-        rewrite_nofast_bytecode(m);
-        Fingerprinter fp(m);
-        // The side effect of this call sets method's fingerprint field.
-        fp.fingerprint();
-      }
+      MetaspaceShared::rewrite_nofast_bytecodes_and_calculate_fingerprints(ik);
     }
   }
 }
 
+void MetaspaceShared::rewrite_nofast_bytecodes_and_calculate_fingerprints(InstanceKlass* ik) {
+  for (int i = 0; i < ik->methods()->length(); i++) {
+    Method* m = ik->methods()->at(i);
+    rewrite_nofast_bytecode(m);
+    Fingerprinter fp(m);
+    // The side effect of this call sets method's fingerprint field.
+    fp.fingerprint();
+  }
+}
+
 // Objects of the Metadata types (such as Klass and ConstantPool) have C++ vtables.
 // (In GCC this is the field <Type>::_vptr, i.e., first word in the object.)
 //
@@ -686,7 +733,7 @@
   intptr_t* p = clone_vtable(name, _info);
   assert((char*)p == _md_region.top(), "must be");
 
-  return p;
+  return _info->cloned_vtable();
 }
 
 template <class T>
@@ -759,7 +806,7 @@
 }
 
 #define ALLOC_CPP_VTABLE_CLONE(c) \
-  CppVtableCloner<c>::allocate(#c);
+  _cloned_cpp_vtptrs[c##_Kind] = CppVtableCloner<c>::allocate(#c);
 
 #define CLONE_CPP_VTABLE(c) \
   p = CppVtableCloner<c>::clone_vtable(#c, (CppVtableInfo*)p);
@@ -767,6 +814,85 @@
 #define ZERO_CPP_VTABLE(c) \
  CppVtableCloner<c>::zero_vtable_clone();
 
+//------------------------------ for DynamicDumpSharedSpaces - start
+#define DECLARE_CLONED_VTABLE_KIND(c) c ## _Kind,
+
+enum {
+  CPP_VTABLE_PATCH_TYPES_DO(DECLARE_CLONED_VTABLE_KIND)
+  _num_cloned_vtable_kinds
+};
+
+static intptr_t** _cloned_cpp_vtptrs = NULL;
+
+void MetaspaceShared::serialize_cloned_cpp_vtptrs(SerializeClosure* soc) {
+  soc->do_ptr((void**)&_cloned_cpp_vtptrs);
+}
+
+intptr_t* MetaspaceShared::fix_cpp_vtable_for_dynamic_archive(MetaspaceObj::Type msotype, address obj) {
+  assert(DynamicDumpSharedSpaces, "must");
+  int kind = -1;
+  switch (msotype) {
+  case MetaspaceObj::SymbolType:
+  case MetaspaceObj::TypeArrayU1Type:
+  case MetaspaceObj::TypeArrayU2Type:
+  case MetaspaceObj::TypeArrayU4Type:
+  case MetaspaceObj::TypeArrayU8Type:
+  case MetaspaceObj::TypeArrayOtherType:
+  case MetaspaceObj::ConstMethodType:
+  case MetaspaceObj::ConstantPoolCacheType:
+  case MetaspaceObj::AnnotationsType:
+  case MetaspaceObj::MethodCountersType:
+    // These have no vtables.
+    break;
+  case MetaspaceObj::ClassType:
+    {
+      Klass* k = (Klass*)obj;
+      assert(k->is_klass(), "must be");
+      if (k->is_instance_klass()) {
+        kind = InstanceKlass_Kind;
+      } else {
+        assert(k->is_objArray_klass(),
+               "We shouldn't archive any other klasses in DynamicDumpSharedSpaces");
+        kind = ObjArrayKlass_Kind;
+      }
+    }
+    break;
+
+  case MetaspaceObj::MethodType:
+    {
+      Method* m = (Method*)obj;
+      assert(m->is_method(), "must be");
+      kind = Method_Kind;
+    }
+    break;
+
+  case MetaspaceObj::MethodDataType:
+    // We don't archive MethodData <-- should have been removed in removed_unsharable_info
+    ShouldNotReachHere();
+    break;
+
+  case MetaspaceObj::ConstantPoolType:
+    {
+      ConstantPool *cp = (ConstantPool*)obj;
+      assert(cp->is_constantPool(), "must be");
+      kind = ConstantPool_Kind;
+    }
+    break;
+
+  default:
+    ShouldNotReachHere();
+  }
+
+  if (kind >= 0) {
+    assert(kind < _num_cloned_vtable_kinds, "must be");
+    return _cloned_cpp_vtptrs[kind];
+  } else {
+    return NULL;
+  }
+}
+
+//------------------------------ for DynamicDumpSharedSpaces - end
+
 // This can be called at both dump time and run time.
 intptr_t* MetaspaceShared::clone_cpp_vtables(intptr_t* p) {
   assert(DumpSharedSpaces || UseSharedSpaces, "sanity");
@@ -830,55 +956,27 @@
   return CppVtableCloner<Method>::is_valid_shared_object(m);
 }
 
-// Closure for serializing initialization data out to a data area to be
-// written to the shared file.
+void WriteClosure::do_oop(oop* o) {
+  if (*o == NULL) {
+    _dump_region->append_intptr_t(0);
+  } else {
+    assert(HeapShared::is_heap_object_archiving_allowed(),
+           "Archiving heap object is not allowed");
+    _dump_region->append_intptr_t(
+      (intptr_t)CompressedOops::encode_not_null(*o));
+  }
+}
 
-class WriteClosure : public SerializeClosure {
-private:
-  DumpRegion* _dump_region;
-
-public:
-  WriteClosure(DumpRegion* r) {
-    _dump_region = r;
+void WriteClosure::do_region(u_char* start, size_t size) {
+  assert((intptr_t)start % sizeof(intptr_t) == 0, "bad alignment");
+  assert(size % sizeof(intptr_t) == 0, "bad size");
+  do_tag((int)size);
+  while (size > 0) {
+    _dump_region->append_intptr_t(*(intptr_t*)start);
+    start += sizeof(intptr_t);
+    size -= sizeof(intptr_t);
   }
-
-  void do_ptr(void** p) {
-    _dump_region->append_intptr_t((intptr_t)*p);
-  }
-
-  void do_u4(u4* p) {
-    void* ptr = (void*)(uintx(*p));
-    do_ptr(&ptr);
-  }
-
-  void do_tag(int tag) {
-    _dump_region->append_intptr_t((intptr_t)tag);
-  }
-
-  void do_oop(oop* o) {
-    if (*o == NULL) {
-      _dump_region->append_intptr_t(0);
-    } else {
-      assert(HeapShared::is_heap_object_archiving_allowed(),
-             "Archiving heap object is not allowed");
-      _dump_region->append_intptr_t(
-        (intptr_t)CompressedOops::encode_not_null(*o));
-    }
-  }
-
-  void do_region(u_char* start, size_t size) {
-    assert((intptr_t)start % sizeof(intptr_t) == 0, "bad alignment");
-    assert(size % sizeof(intptr_t) == 0, "bad size");
-    do_tag((int)size);
-    while (size > 0) {
-      _dump_region->append_intptr_t(*(intptr_t*)start);
-      start += sizeof(intptr_t);
-      size -= sizeof(intptr_t);
-    }
-  }
-
-  bool reading() const { return false; }
-};
+}
 
 // This is for dumping detailed statistics for the allocations
 // in the shared spaces.
@@ -1166,20 +1264,22 @@
   public:
     ShallowCopier(bool read_only) : _read_only(read_only) {}
 
-    virtual void do_unique_ref(Ref* ref, bool read_only) {
+    virtual bool do_unique_ref(Ref* ref, bool read_only) {
       if (read_only == _read_only) {
         allocate(ref, read_only);
       }
+      return true; // recurse into ref.obj()
     }
   };
 
   // Relocate embedded pointers within a MetaspaceObj's shallow copy
   class ShallowCopyEmbeddedRefRelocator: public UniqueMetaspaceClosure {
   public:
-    virtual void do_unique_ref(Ref* ref, bool read_only) {
+    virtual bool do_unique_ref(Ref* ref, bool read_only) {
       address new_loc = get_new_loc(ref);
       RefRelocator refer;
       ref->metaspace_pointers_do_at(&refer, new_loc);
+      return true; // recurse into ref.obj()
     }
   };
 
@@ -1294,6 +1394,8 @@
     Universe::metaspace_pointers_do(it);
     SymbolTable::metaspace_pointers_do(it);
     vmSymbols::metaspace_pointers_do(it);
+
+    it->finish();
   }
 
   static Klass* get_relocated_klass(Klass* orig_klass) {
@@ -1336,6 +1438,9 @@
 
   char* start = _ro_region.top();
 
+  size_t vtptrs_bytes = _num_cloned_vtable_kinds * sizeof(intptr_t*);
+  _cloned_cpp_vtptrs = (intptr_t**)_ro_region.allocate(vtptrs_bytes, sizeof(intptr_t*));
+
   // Write the other data to the output array.
   WriteClosure wc(&_ro_region);
   MetaspaceShared::serialize(&wc);
@@ -1354,6 +1459,7 @@
   //     in the VM thread.
   // (2) ArchiveCompactor needs to work with a stable set of MetaspaceObjs.
   Metaspace::freeze();
+  DEBUG_ONLY(SystemDictionaryShared::NoClassLoadingMark nclm);
 
   Thread* THREAD = VMThread::vm_thread();
 
@@ -1441,7 +1547,7 @@
 
   // Create and write the archive file that maps the shared spaces.
 
-  FileMapInfo* mapinfo = new FileMapInfo();
+  FileMapInfo* mapinfo = new FileMapInfo(true);
   mapinfo->populate_header(os::vm_allocation_granularity());
   mapinfo->set_read_only_tables_start(read_only_tables_start);
   mapinfo->set_misc_data_patching_start(vtbl_list);
@@ -1816,67 +1922,55 @@
 }
 #endif // INCLUDE_CDS_JAVA_HEAP
 
-// Closure for serializing initialization data in from a data area
-// (ptr_array) read from the shared file.
+void ReadClosure::do_ptr(void** p) {
+  assert(*p == NULL, "initializing previous initialized pointer.");
+  intptr_t obj = nextPtr();
+  assert((intptr_t)obj >= 0 || (intptr_t)obj < -100,
+         "hit tag while initializing ptrs.");
+  *p = (void*)obj;
+}
 
-class ReadClosure : public SerializeClosure {
-private:
-  intptr_t** _ptr_array;
+void ReadClosure::do_u4(u4* p) {
+  intptr_t obj = nextPtr();
+  *p = (u4)(uintx(obj));
+}
 
-  inline intptr_t nextPtr() {
-    return *(*_ptr_array)++;
+void ReadClosure::do_tag(int tag) {
+  int old_tag;
+  old_tag = (int)(intptr_t)nextPtr();
+  // do_int(&old_tag);
+  assert(tag == old_tag, "old tag doesn't match");
+  FileMapInfo::assert_mark(tag == old_tag);
+}
+
+void ReadClosure::do_oop(oop *p) {
+  narrowOop o = (narrowOop)nextPtr();
+  if (o == 0 || !HeapShared::open_archive_heap_region_mapped()) {
+    p = NULL;
+  } else {
+    assert(HeapShared::is_heap_object_archiving_allowed(),
+           "Archived heap object is not allowed");
+    assert(HeapShared::open_archive_heap_region_mapped(),
+           "Open archive heap region is not mapped");
+    *p = HeapShared::decode_from_archive(o);
   }
+}
 
-public:
-  ReadClosure(intptr_t** ptr_array) { _ptr_array = ptr_array; }
+void ReadClosure::do_region(u_char* start, size_t size) {
+  assert((intptr_t)start % sizeof(intptr_t) == 0, "bad alignment");
+  assert(size % sizeof(intptr_t) == 0, "bad size");
+  do_tag((int)size);
+  while (size > 0) {
+    *(intptr_t*)start = nextPtr();
+    start += sizeof(intptr_t);
+    size -= sizeof(intptr_t);
+  }
+}
 
-  void do_ptr(void** p) {
-    assert(*p == NULL, "initializing previous initialized pointer.");
-    intptr_t obj = nextPtr();
-    assert((intptr_t)obj >= 0 || (intptr_t)obj < -100,
-           "hit tag while initializing ptrs.");
-    *p = (void*)obj;
-  }
-
-  void do_u4(u4* p) {
-    intptr_t obj = nextPtr();
-    *p = (u4)(uintx(obj));
-  }
-
-  void do_tag(int tag) {
-    int old_tag;
-    old_tag = (int)(intptr_t)nextPtr();
-    // do_int(&old_tag);
-    assert(tag == old_tag, "old tag doesn't match");
-    FileMapInfo::assert_mark(tag == old_tag);
-  }
-
-  void do_oop(oop *p) {
-    narrowOop o = (narrowOop)nextPtr();
-    if (o == 0 || !HeapShared::open_archive_heap_region_mapped()) {
-      p = NULL;
-    } else {
-      assert(HeapShared::is_heap_object_archiving_allowed(),
-             "Archived heap object is not allowed");
-      assert(HeapShared::open_archive_heap_region_mapped(),
-             "Open archive heap region is not mapped");
-      *p = HeapShared::decode_from_archive(o);
-    }
-  }
-
-  void do_region(u_char* start, size_t size) {
-    assert((intptr_t)start % sizeof(intptr_t) == 0, "bad alignment");
-    assert(size % sizeof(intptr_t) == 0, "bad size");
-    do_tag((int)size);
-    while (size > 0) {
-      *(intptr_t*)start = nextPtr();
-      start += sizeof(intptr_t);
-      size -= sizeof(intptr_t);
-    }
-  }
-
-  bool reading() const { return true; }
-};
+void MetaspaceShared::set_shared_metaspace_range(void* base, void* top) {
+  _shared_metaspace_static_top = top;
+  MetaspaceObj::set_shared_metaspace_range(base, top);
+}
 
 // Return true if given address is in the misc data region
 bool MetaspaceShared::is_in_shared_region(const void* p, int idx) {
@@ -1890,6 +1984,15 @@
   return false;
 }
 
+bool MetaspaceShared::is_shared_dynamic(void* p) {
+  if ((p < MetaspaceObj::shared_metaspace_top()) &&
+      (p >= _shared_metaspace_static_top)) {
+    return true;
+  } else {
+    return false;
+  }
+}
+
 // Map shared spaces at requested addresses and return if succeeded.
 bool MetaspaceShared::map_shared_spaces(FileMapInfo* mapinfo) {
   size_t image_alignment = mapinfo->alignment();
@@ -1904,42 +2007,23 @@
 
   assert(!DumpSharedSpaces, "Should not be called with DumpSharedSpaces");
 
-  char* ro_base = NULL; char* ro_top;
-  char* rw_base = NULL; char* rw_top;
-  char* mc_base = NULL; char* mc_top;
-  char* md_base = NULL; char* md_top;
+  // Map each shared region
+  int regions[] = {mc, rw, ro, md};
+  size_t len = sizeof(regions)/sizeof(int);
+  char* saved_base[] = {NULL, NULL, NULL, NULL};
+  char* top = mapinfo->map_regions(regions, saved_base, len );
 
-  // Map each shared region
-  if ((mc_base = mapinfo->map_region(mc, &mc_top)) != NULL &&
-      (rw_base = mapinfo->map_region(rw, &rw_top)) != NULL &&
-      (ro_base = mapinfo->map_region(ro, &ro_top)) != NULL &&
-      (md_base = mapinfo->map_region(md, &md_top)) != NULL &&
+  if (top != NULL &&
       (image_alignment == (size_t)os::vm_allocation_granularity()) &&
       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().
-    //
-    // We require that mc->rw->ro->md to be laid out consecutively, with no
-    // gaps between them. That way, we can ensure that the OS won't be able to
-    // allocate any new memory spaces inside _shared_metaspace_{base,top}, which
-    // would mess up the simple comparision in MetaspaceShared::is_in_shared_metaspace().
-    assert(mc_base < ro_base && mc_base < rw_base && mc_base < md_base, "must be");
-    assert(md_top  > ro_top  && md_top  > rw_top  && md_top  > mc_top , "must be");
-    assert(mc_top == rw_base, "must be");
-    assert(rw_top == ro_base, "must be");
-    assert(ro_top == md_base, "must be");
-
     _core_spaces_size = mapinfo->core_spaces_size();
-    MetaspaceObj::set_shared_metaspace_range((void*)mc_base, (void*)md_top);
+    set_shared_metaspace_range((void*)saved_base[0], (void*)top);
     return true;
   } else {
-    // If there was a failure in mapping any of the spaces, unmap the ones
-    // that succeeded
-    if (ro_base != NULL) mapinfo->unmap_region(ro);
-    if (rw_base != NULL) mapinfo->unmap_region(rw);
-    if (mc_base != NULL) mapinfo->unmap_region(mc);
-    if (md_base != NULL) mapinfo->unmap_region(md);
+    mapinfo->unmap_regions(regions, saved_base, len);
 #ifndef _WINDOWS
     // Release the entire mapped region
     shared_rs.release();
@@ -1970,6 +2054,9 @@
   // The rest of the data is now stored in the RW region
   buffer = mapinfo->read_only_tables_start();
 
+  // Skip over _cloned_cpp_vtptrs;
+  buffer += _num_cloned_vtable_kinds * sizeof(intptr_t*);
+
   // Verify various attributes of the archive, plus initialize the
   // shared string/symbol tables
   intptr_t* array = (intptr_t*)buffer;
@@ -2009,6 +2096,12 @@
     if (!mapinfo->remap_shared_readonly_as_readwrite()) {
       return false;
     }
+    if (FileMapInfo::dynamic_info() != NULL) {
+      mapinfo = FileMapInfo::dynamic_info();
+      if (!mapinfo->remap_shared_readonly_as_readwrite()) {
+        return false;
+      }
+    }
     _remapped_readwrite = true;
   }
   return true;
--- a/src/hotspot/share/memory/metaspaceShared.hpp	Fri May 17 10:48:02 2019 -0400
+++ b/src/hotspot/share/memory/metaspaceShared.hpp	Fri May 17 08:29:55 2019 -0700
@@ -47,6 +47,124 @@
   CompactHashtableStats string;
 };
 
+#if INCLUDE_CDS
+class DumpRegion {
+private:
+  const char* _name;
+  char* _base;
+  char* _top;
+  char* _end;
+  bool _is_packed;
+
+public:
+  DumpRegion(const char* name) : _name(name), _base(NULL), _top(NULL), _end(NULL), _is_packed(false) {}
+
+  char* expand_top_to(char* newtop);
+  char* allocate(size_t num_bytes, size_t alignment=BytesPerWord);
+
+  void append_intptr_t(intptr_t n) {
+    assert(is_aligned(_top, sizeof(intptr_t)), "bad alignment");
+    intptr_t *p = (intptr_t*)_top;
+    char* newtop = _top + sizeof(intptr_t);
+    expand_top_to(newtop);
+    *p = n;
+  }
+
+  char* base()      const { return _base;        }
+  char* top()       const { return _top;         }
+  char* end()       const { return _end;         }
+  size_t reserved() const { return _end - _base; }
+  size_t used()     const { return _top - _base; }
+  bool is_packed()  const { return _is_packed;   }
+  bool is_allocatable() const {
+    return !is_packed() && _base != NULL;
+  }
+
+  void print(size_t total_bytes) const;
+  void print_out_of_space_msg(const char* failing_region, size_t needed_bytes);
+
+  void init(const ReservedSpace* rs, char* base) {
+    if (base == NULL) {
+      base = rs->base();
+    }
+    assert(rs->contains(base), "must be");
+    _base = _top = base;
+    _end = rs->end();
+  }
+  void init(char* b, char* t, char* e) {
+    _base = b;
+    _top = t;
+    _end = e;
+  }
+
+  void pack(DumpRegion* next = NULL);
+
+  bool contains(char* p) {
+    return base() <= p && p < top();
+  }
+};
+
+// Closure for serializing initialization data out to a data area to be
+// written to the shared file.
+
+class WriteClosure : public SerializeClosure {
+private:
+  DumpRegion* _dump_region;
+
+public:
+  WriteClosure(DumpRegion* r) {
+    _dump_region = r;
+  }
+
+  void do_ptr(void** p) {
+    _dump_region->append_intptr_t((intptr_t)*p);
+  }
+
+  void do_u4(u4* p) {
+    void* ptr = (void*)(uintx(*p));
+    do_ptr(&ptr);
+  }
+
+  void do_tag(int tag) {
+    _dump_region->append_intptr_t((intptr_t)tag);
+  }
+
+  void do_oop(oop* o);
+
+  void do_region(u_char* start, size_t size);
+
+  bool reading() const { return false; }
+};
+
+// Closure for serializing initialization data in from a data area
+// (ptr_array) read from the shared file.
+
+class ReadClosure : public SerializeClosure {
+private:
+  intptr_t** _ptr_array;
+
+  inline intptr_t nextPtr() {
+    return *(*_ptr_array)++;
+  }
+
+public:
+  ReadClosure(intptr_t** ptr_array) { _ptr_array = ptr_array; }
+
+  void do_ptr(void** p);
+
+  void do_u4(u4* p);
+
+  void do_tag(int tag);
+
+  void do_oop(oop *p);
+
+  void do_region(u_char* start, size_t size);
+
+  bool reading() const { return true; }
+};
+
+#endif
+
 // Class Data Sharing Support
 class MetaspaceShared : AllStatic {
 
@@ -61,6 +179,7 @@
   static address _cds_i2i_entry_code_buffers;
   static size_t  _cds_i2i_entry_code_buffers_size;
   static size_t  _core_spaces_size;
+  static void* _shared_metaspace_static_top;
  public:
   enum {
     // core archive spaces
@@ -102,16 +221,12 @@
   }
   static void initialize_dumptime_shared_and_meta_spaces() NOT_CDS_RETURN;
   static void initialize_runtime_shared_and_meta_spaces() NOT_CDS_RETURN;
+  static char* initialize_dynamic_runtime_shared_spaces(
+                     char* static_start, char* static_end) NOT_CDS_RETURN_(NULL);
   static void post_initialize(TRAPS) NOT_CDS_RETURN;
 
-  // Delta of this object from the bottom of the archive.
-  static uintx object_delta_uintx(void* obj) {
-    assert(DumpSharedSpaces, "supported only for dumping");
-    assert(shared_rs()->contains(obj), "must be");
-    address base_address = address(shared_rs()->base());
-    uintx deltax = address(obj) - base_address;
-    return deltax;
-  }
+  // Delta of this object from SharedBaseAddress
+  static uintx object_delta_uintx(void* obj);
 
   static u4 object_delta_u4(void* obj) {
     // offset is guaranteed to be less than MAX_SHARED_DELTA in DumpRegion::expand_top_to()
@@ -134,15 +249,25 @@
     return (p < MetaspaceObj::shared_metaspace_top() && p >= MetaspaceObj::shared_metaspace_base());
   }
 
+  static address shared_metaspace_top() {
+    return (address)MetaspaceObj::shared_metaspace_top();
+  }
+
+  static void set_shared_metaspace_range(void* base, void* top) NOT_CDS_RETURN;
+
   // Return true if given address is in the shared region corresponding to the idx
   static bool is_in_shared_region(const void* p, int idx) NOT_CDS_RETURN_(false);
 
   static bool is_in_trampoline_frame(address addr) NOT_CDS_RETURN_(false);
 
+  static bool is_shared_dynamic(void* p) NOT_CDS_RETURN_(false);
+
   static void allocate_cpp_vtable_clones();
   static intptr_t* clone_cpp_vtables(intptr_t* p);
   static void zero_cpp_vtable_clones_for_writing();
   static void patch_cpp_vtable_pointers();
+  static void serialize_cloned_cpp_vtptrs(SerializeClosure* sc);
+
   static bool is_valid_shared_method(const Method* m) NOT_CDS_RETURN_(false);
   static void serialize(SerializeClosure* sc) NOT_CDS_RETURN;
 
@@ -165,6 +290,20 @@
   static bool try_link_class(InstanceKlass* ik, TRAPS);
   static void link_and_cleanup_shared_classes(TRAPS);
 
+#if INCLUDE_CDS
+  static ReservedSpace* reserve_shared_rs(size_t size, size_t alignment,
+                                          bool large, char* requested_address);
+  static void init_shared_dump_space(DumpRegion* first_space, address first_space_bottom = NULL);
+  static DumpRegion* misc_code_dump_space();
+  static DumpRegion* read_write_dump_space();
+  static DumpRegion* read_only_dump_space();
+  static DumpRegion* optional_data_dump_space();
+  static void pack_dump_space(DumpRegion* current, DumpRegion* next,
+                              ReservedSpace* rs);
+
+  static void rewrite_nofast_bytecodes_and_calculate_fingerprints(InstanceKlass* ik);
+#endif
+
   // Allocate a block of memory from the "mc", "ro", or "rw" regions.
   static char* misc_code_space_alloc(size_t num_bytes);
   static char* read_only_space_alloc(size_t num_bytes);
@@ -181,6 +320,12 @@
 #endif
   }
 
+  template <typename T>
+  static size_t ro_array_bytesize(int length) {
+    size_t byte_size = Array<T>::byte_sizeof(length, sizeof(T));
+    return align_up(byte_size, BytesPerWord);
+  }
+
   static address cds_i2i_entry_code_buffers(size_t total_size);
 
   static address cds_i2i_entry_code_buffers() {
@@ -193,6 +338,8 @@
 
   static Klass* get_relocated_klass(Klass *k);
 
+  static intptr_t* fix_cpp_vtable_for_dynamic_archive(MetaspaceObj::Type msotype, address obj);
+
 private:
   static void read_extra_data(const char* filename, TRAPS) NOT_CDS_RETURN;
 };
--- a/src/hotspot/share/memory/universe.cpp	Fri May 17 10:48:02 2019 -0400
+++ b/src/hotspot/share/memory/universe.cpp	Fri May 17 08:29:55 2019 -0700
@@ -711,13 +711,14 @@
   {
     SymbolTable::create_table();
     StringTable::create_table();
+  }
 
 #if INCLUDE_CDS
-    if (DumpSharedSpaces) {
-      MetaspaceShared::prepare_for_dumping();
-    }
+  if (DumpSharedSpaces || DynamicDumpSharedSpaces) {
+    MetaspaceShared::prepare_for_dumping();
+  }
 #endif
-  }
+
   if (strlen(VerifySubSet) > 0) {
     Universe::initialize_verify_flags();
   }
--- a/src/hotspot/share/oops/constMethod.hpp	Fri May 17 10:48:02 2019 -0400
+++ b/src/hotspot/share/oops/constMethod.hpp	Fri May 17 08:29:55 2019 -0700
@@ -288,12 +288,16 @@
 
   // adapter
   void set_adapter_entry(AdapterHandlerEntry* adapter) {
-    assert(!is_shared(), "shared methods have fixed adapter_trampoline");
+    assert(!is_shared(),
+           "shared methods in archive have fixed adapter_trampoline");
     _adapter = adapter;
   }
   void set_adapter_trampoline(AdapterHandlerEntry** trampoline) {
-    assert(DumpSharedSpaces, "must be");
-    assert(*trampoline == NULL, "must be NULL during dump time, to be initialized at run time");
+    assert(DumpSharedSpaces || DynamicDumpSharedSpaces, "must be");
+    if (DumpSharedSpaces) {
+      assert(*trampoline == NULL,
+             "must be NULL during dump time, to be initialized at run time");
+    }
     _adapter_trampoline = trampoline;
   }
   void update_adapter_trampoline(AdapterHandlerEntry* adapter) {
--- a/src/hotspot/share/oops/constantPool.cpp	Fri May 17 10:48:02 2019 -0400
+++ b/src/hotspot/share/oops/constantPool.cpp	Fri May 17 08:29:55 2019 -0700
@@ -371,7 +371,9 @@
   // If archiving heap objects is not allowed, clear the resolved references.
   // Otherwise, it is cleared after the resolved references array is cached
   // (see archive_resolved_references()).
-  if (!HeapShared::is_heap_object_archiving_allowed()) {
+  // If DynamicDumpSharedSpaces is enabled, clear the resolved references also
+  // as java objects are not archived in the top layer.
+  if (!HeapShared::is_heap_object_archiving_allowed() || DynamicDumpSharedSpaces) {
     set_resolved_references(NULL);
   }
 
@@ -382,7 +384,16 @@
   _flags |= (_on_stack | _is_shared);
   int num_klasses = 0;
   for (int index = 1; index < length(); index++) { // Index 0 is unused
-    assert(!tag_at(index).is_unresolved_klass_in_error(), "This must not happen during dump time");
+    if (!DynamicDumpSharedSpaces) {
+      assert(!tag_at(index).is_unresolved_klass_in_error(), "This must not happen during static dump time");
+    } else {
+      if (tag_at(index).is_unresolved_klass_in_error() ||
+          tag_at(index).is_method_handle_in_error()    ||
+          tag_at(index).is_method_type_in_error()      ||
+          tag_at(index).is_dynamic_constant_in_error()) {
+        tag_at_put(index, JVM_CONSTANT_UnresolvedClass);
+      }
+    }
     if (tag_at(index).is_klass()) {
       // This class was resolved as a side effect of executing Java code
       // during dump time. We need to restore it back to an UnresolvedClass,
--- a/src/hotspot/share/oops/cpCache.cpp	Fri May 17 10:48:02 2019 -0400
+++ b/src/hotspot/share/oops/cpCache.cpp	Fri May 17 08:29:55 2019 -0700
@@ -697,7 +697,7 @@
 }
 
 void ConstantPoolCache::walk_entries_for_initialization(bool check_only) {
-  assert(DumpSharedSpaces, "sanity");
+  assert(DumpSharedSpaces || DynamicDumpSharedSpaces, "sanity");
   // When dumping the archive, we want to clean up the ConstantPoolCache
   // to remove any effect of linking due to the execution of Java code --
   // each ConstantPoolCacheEntry will have the same contents as if
--- a/src/hotspot/share/oops/instanceKlass.cpp	Fri May 17 10:48:02 2019 -0400
+++ b/src/hotspot/share/oops/instanceKlass.cpp	Fri May 17 08:29:55 2019 -0700
@@ -451,7 +451,7 @@
   assert(is_instance_klass(), "is layout incorrect?");
   assert(size_helper() == parser.layout_size(), "incorrect size_helper?");
 
-  if (DumpSharedSpaces) {
+  if (DumpSharedSpaces || DynamicDumpSharedSpaces) {
     SystemDictionaryShared::init_dumptime_info(this);
   }
 }
@@ -601,7 +601,7 @@
   }
   set_annotations(NULL);
 
-  if (DumpSharedSpaces) {
+  if (DumpSharedSpaces || DynamicDumpSharedSpaces) {
     SystemDictionaryShared::remove_dumptime_info(this);
   }
 }
@@ -2225,8 +2225,8 @@
     // (1) We are running AOT to generate a shared library.
     return true;
   }
-  if (DumpSharedSpaces) {
-    // (2) We are running -Xshare:dump to create a shared archive
+  if (DumpSharedSpaces || DynamicDumpSharedSpaces) {
+    // (2) We are running -Xshare:dump or -XX:ArchiveClassesAtExit to create a shared archive
     return true;
   }
   if (UseAOT && is_unsafe_anonymous) {
@@ -2346,15 +2346,13 @@
     array_klasses()->remove_unshareable_info();
   }
 
-  // These are not allocated from metaspace, but they should should all be empty
-  // during dump time, so we don't need to worry about them in InstanceKlass::iterate().
-  guarantee(_source_debug_extension == NULL, "must be");
-  guarantee(_dep_context == NULL, "must be");
-  guarantee(_osr_nmethods_head == NULL, "must be");
-
+  // These are not allocated from metaspace. They are safe to set to NULL.
+  _source_debug_extension = NULL;
+  _dep_context = NULL;
+  _osr_nmethods_head = NULL;
 #if INCLUDE_JVMTI
-  guarantee(_breakpoints == NULL, "must be");
-  guarantee(_previous_versions == NULL, "must be");
+  _breakpoints = NULL;
+  _previous_versions = NULL;
   _cached_class_file = NULL;
 #endif
 
@@ -2475,6 +2473,10 @@
   // notify ClassLoadingService of class unload
   ClassLoadingService::notify_class_unloaded(ik);
 
+  if (DumpSharedSpaces || DynamicDumpSharedSpaces) {
+    SystemDictionaryShared::remove_dumptime_info(ik);
+  }
+
   if (log_is_enabled(Info, class, unload)) {
     ResourceMark rm;
     log_info(class, unload)("unloading class %s " INTPTR_FORMAT, ik->external_name(), p2i(ik));
@@ -3422,7 +3424,12 @@
       info_stream.print(" source: %s", class_loader->klass()->external_name());
     }
   } else {
-    info_stream.print(" source: shared objects file");
+    assert(this->is_shared(), "must be");
+    if (MetaspaceShared::is_shared_dynamic((void*)this)) {
+      info_stream.print(" source: shared objects file (top)");
+    } else {
+      info_stream.print(" source: shared objects file");
+    }
   }
 
   msg.info("%s", info_stream.as_string());
--- a/src/hotspot/share/oops/klass.cpp	Fri May 17 10:48:02 2019 -0400
+++ b/src/hotspot/share/oops/klass.cpp	Fri May 17 08:29:55 2019 -0700
@@ -525,7 +525,8 @@
 }
 
 void Klass::remove_unshareable_info() {
-  assert (DumpSharedSpaces, "only called for DumpSharedSpaces");
+  assert (DumpSharedSpaces || DynamicDumpSharedSpaces,
+          "only called during CDS dump time");
   JFR_ONLY(REMOVE_ID(this);)
   if (log_is_enabled(Trace, cds, unshareable)) {
     ResourceMark rm;
@@ -542,7 +543,7 @@
 }
 
 void Klass::remove_java_mirror() {
-  assert (DumpSharedSpaces, "only called for DumpSharedSpaces");
+  assert(DumpSharedSpaces || DynamicDumpSharedSpaces, "only called during CDS dump time");
   if (log_is_enabled(Trace, cds, unshareable)) {
     ResourceMark rm;
     log_trace(cds, unshareable)("remove java_mirror: %s", external_name());
--- a/src/hotspot/share/oops/method.cpp	Fri May 17 10:48:02 2019 -0400
+++ b/src/hotspot/share/oops/method.cpp	Fri May 17 08:29:55 2019 -0700
@@ -958,23 +958,30 @@
 void Method::unlink_method() {
   _code = NULL;
 
-  assert(DumpSharedSpaces, "dump time only");
+  assert(DumpSharedSpaces || DynamicDumpSharedSpaces, "dump time only");
   // Set the values to what they should be at run time. Note that
   // this Method can no longer be executed during dump time.
   _i2i_entry = Interpreter::entry_for_cds_method(this);
   _from_interpreted_entry = _i2i_entry;
 
+  if (DynamicDumpSharedSpaces) {
+    assert(_from_compiled_entry != NULL, "sanity");
+  } else {
+    // TODO: Simplify the adapter trampoline allocation for static archiving.
+    //       Remove the use of CDSAdapterHandlerEntry.
+    CDSAdapterHandlerEntry* cds_adapter = (CDSAdapterHandlerEntry*)adapter();
+    constMethod()->set_adapter_trampoline(cds_adapter->get_adapter_trampoline());
+    _from_compiled_entry = cds_adapter->get_c2i_entry_trampoline();
+    assert(*((int*)_from_compiled_entry) == 0,
+           "must be NULL during dump time, to be initialized at run time");
+  }
+
   if (is_native()) {
     *native_function_addr() = NULL;
     set_signature_handler(NULL);
   }
   NOT_PRODUCT(set_compiled_invocation_count(0);)
 
-  CDSAdapterHandlerEntry* cds_adapter = (CDSAdapterHandlerEntry*)adapter();
-  constMethod()->set_adapter_trampoline(cds_adapter->get_adapter_trampoline());
-  _from_compiled_entry = cds_adapter->get_c2i_entry_trampoline();
-  assert(*((int*)_from_compiled_entry) == 0, "must be NULL during dump time, to be initialized at run time");
-
   set_method_data(NULL);
   clear_method_counters();
 }
--- a/src/hotspot/share/oops/method.hpp	Fri May 17 10:48:02 2019 -0400
+++ b/src/hotspot/share/oops/method.hpp	Fri May 17 08:29:55 2019 -0700
@@ -468,9 +468,15 @@
   void set_adapter_entry(AdapterHandlerEntry* adapter) {
     constMethod()->set_adapter_entry(adapter);
   }
+  void set_adapter_trampoline(AdapterHandlerEntry** trampoline) {
+    constMethod()->set_adapter_trampoline(trampoline);
+  }
   void update_adapter_trampoline(AdapterHandlerEntry* adapter) {
     constMethod()->update_adapter_trampoline(adapter);
   }
+  void set_from_compiled_entry(address entry) {
+    _from_compiled_entry =  entry;
+  }
 
   address get_i2c_entry();
   address get_c2i_entry();
@@ -511,7 +517,8 @@
   address interpreter_entry() const              { return _i2i_entry; }
   // Only used when first initialize so we can set _i2i_entry and _from_interpreted_entry
   void set_interpreter_entry(address entry) {
-    assert(!is_shared(), "shared method's interpreter entry should not be changed at run time");
+    assert(!is_shared(),
+           "shared method's interpreter entry should not be changed at run time");
     if (_i2i_entry != entry) {
       _i2i_entry = entry;
     }
--- a/src/hotspot/share/oops/symbol.cpp	Fri May 17 10:48:02 2019 -0400
+++ b/src/hotspot/share/oops/symbol.cpp	Fri May 17 08:29:55 2019 -0700
@@ -74,6 +74,13 @@
   FreeHeap(p);
 }
 
+void Symbol::set_permanent() {
+  // This is called at a safepoint during dumping of a dynamic CDS archive.
+  assert(SafepointSynchronize::is_at_safepoint(), "must be at a safepoint");
+  _length_and_refcount =  pack_length_and_refcount(length(), PERM_REFCOUNT);
+}
+
+
 // ------------------------------------------------------------------
 // Symbol::starts_with
 //
--- a/src/hotspot/share/oops/symbol.hpp	Fri May 17 10:48:02 2019 -0400
+++ b/src/hotspot/share/oops/symbol.hpp	Fri May 17 08:29:55 2019 -0700
@@ -169,6 +169,7 @@
   bool is_permanent() {
     return (refcount() == PERM_REFCOUNT);
   }
+  void set_permanent();
   void make_permanent();
 
   // Function char_at() returns the Symbol's selected u1 byte as a char type.
--- a/src/hotspot/share/prims/cdsoffsets.cpp	Fri May 17 10:48:02 2019 -0400
+++ b/src/hotspot/share/prims/cdsoffsets.cpp	Fri May 17 08:29:55 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2019, 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
@@ -26,6 +26,7 @@
 #include "utilities/macros.hpp"
 #if INCLUDE_CDS
 #include "runtime/os.hpp"
+#include "memory/dynamicArchive.hpp"
 #include "memory/filemap.hpp"
 #include "memory/allocation.hpp"
 #include "memory/allocation.inline.hpp"
@@ -44,6 +45,7 @@
 
 #define CREATE_OFFSET_MAPS                                                                  \
     _all = new CDSOffsets("size_t_size", sizeof(size_t), NULL);                             \
+    ADD_NEXT(_all, "int_size", sizeof(int));                                                \
     ADD_NEXT(_all, "FileMapHeader::_magic", offset_of(FileMapHeader, _magic));              \
     ADD_NEXT(_all, "FileMapHeader::_crc", offset_of(FileMapHeader, _crc));                  \
     ADD_NEXT(_all, "FileMapHeader::_version", offset_of(FileMapHeader, _version));          \
@@ -52,6 +54,7 @@
     ADD_NEXT(_all, "CDSFileMapRegion::_used", offset_of(CDSFileMapRegion, _used));          \
     ADD_NEXT(_all, "FileMapHeader::_paths_misc_info_size", offset_of(FileMapHeader, _paths_misc_info_size)); \
     ADD_NEXT(_all, "file_header_size", sizeof(FileMapHeader));                              \
+    ADD_NEXT(_all, "DynamicArchiveHeader::_base_archive_crc", offset_of(DynamicArchiveHeader, _base_archive_crc)); \
     ADD_NEXT(_all, "CDSFileMapRegion_size", sizeof(CDSFileMapRegion));
 
 int CDSOffsets::find_offset(const char* name) {
--- a/src/hotspot/share/prims/whitebox.cpp	Fri May 17 10:48:02 2019 -0400
+++ b/src/hotspot/share/prims/whitebox.cpp	Fri May 17 08:29:55 2019 -0700
@@ -38,6 +38,7 @@
 #include "gc/shared/genArguments.hpp"
 #include "gc/shared/genCollectedHeap.hpp"
 #include "jvmtifiles/jvmtiEnv.hpp"
+#include "memory/filemap.hpp"
 #include "memory/heapShared.inline.hpp"
 #include "memory/metaspaceShared.hpp"
 #include "memory/metadataFactory.hpp"
@@ -1883,6 +1884,10 @@
   return UseSharedSpaces;
 WB_END
 
+WB_ENTRY(jboolean, WB_CDSMemoryMappingFailed(JNIEnv* env, jobject wb))
+  return FileMapInfo::memory_mapping_failed();
+WB_END
+
 WB_ENTRY(jboolean, WB_IsShared(JNIEnv* env, jobject wb, jobject obj))
   oop obj_oop = JNIHandles::resolve(obj);
   return HeapShared::is_archived_object(obj_oop);
@@ -1908,6 +1913,15 @@
   }
 WB_END
 
+WB_ENTRY(void, WB_LinkClass(JNIEnv* env, jobject wb, jclass clazz))
+  Klass *k = java_lang_Class::as_Klass(JNIHandles::resolve_non_null(clazz));
+  if (!k->is_instance_klass()) {
+    return;
+  }
+  InstanceKlass *ik = InstanceKlass::cast(k);
+  ik->link_class(THREAD); // may throw verification error
+WB_END
+
 WB_ENTRY(jboolean, WB_AreOpenArchiveHeapObjectsMapped(JNIEnv* env))
   return HeapShared::open_archive_heap_region_mapped();
 WB_END
@@ -2342,10 +2356,12 @@
   {CC"isSharedClass",      CC"(Ljava/lang/Class;)Z",  (void*)&WB_IsSharedClass },
   {CC"areSharedStringsIgnored",           CC"()Z",    (void*)&WB_AreSharedStringsIgnored },
   {CC"getResolvedReferences", CC"(Ljava/lang/Class;)Ljava/lang/Object;", (void*)&WB_GetResolvedReferences},
+  {CC"linkClass",          CC"(Ljava/lang/Class;)V",  (void*)&WB_LinkClass},
   {CC"areOpenArchiveHeapObjectsMapped",   CC"()Z",    (void*)&WB_AreOpenArchiveHeapObjectsMapped},
   {CC"isCDSIncludedInVmBuild",            CC"()Z",    (void*)&WB_IsCDSIncludedInVmBuild },
   {CC"isJFRIncludedInVmBuild",            CC"()Z",    (void*)&WB_IsJFRIncludedInVmBuild },
-  {CC"isJavaHeapArchiveSupported",      CC"()Z",      (void*)&WB_IsJavaHeapArchiveSupported },
+  {CC"isJavaHeapArchiveSupported",        CC"()Z",    (void*)&WB_IsJavaHeapArchiveSupported },
+  {CC"cdsMemoryMappingFailed",            CC"()Z",    (void*)&WB_CDSMemoryMappingFailed },
 
   {CC"clearInlineCaches0",  CC"(Z)V",                 (void*)&WB_ClearInlineCaches },
   {CC"handshakeWalkStack", CC"(Ljava/lang/Thread;Z)I", (void*)&WB_HandshakeWalkStack },
--- a/src/hotspot/share/runtime/arguments.cpp	Fri May 17 10:48:02 2019 -0400
+++ b/src/hotspot/share/runtime/arguments.cpp	Fri May 17 08:29:55 2019 -0700
@@ -36,6 +36,7 @@
 #include "logging/logStream.hpp"
 #include "logging/logTag.hpp"
 #include "memory/allocation.inline.hpp"
+#include "memory/filemap.hpp"
 #include "oops/oop.inline.hpp"
 #include "prims/jvmtiExport.hpp"
 #include "runtime/arguments.hpp"
@@ -95,6 +96,7 @@
 bool   Arguments::_enable_preview               = false;
 
 char*  Arguments::SharedArchivePath             = NULL;
+char*  Arguments::SharedDynamicArchivePath      = NULL;
 
 AgentLibraryList Arguments::_libraryList;
 AgentLibraryList Arguments::_agentList;
@@ -1469,7 +1471,8 @@
                                       "--patch-module"
                                     };
 void Arguments::check_unsupported_dumping_properties() {
-  assert(DumpSharedSpaces, "this function is only used with -Xshare:dump");
+  assert(DumpSharedSpaces || DynamicDumpSharedSpaces,
+         "this function is only used with CDS dump time");
   assert(ARRAY_SIZE(unsupported_properties) == ARRAY_SIZE(unsupported_options), "must be");
   // If a vm option is found in the unsupported_options array, vm will exit with an error message.
   SystemProperty* sp = system_properties();
@@ -1492,6 +1495,13 @@
 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");
+  if (ArchiveClassesAtExit != NULL) {
+    // dynamic dumping, just return false for now.
+    // check_unsupported_dumping_properties() will be called later to check the same set of
+    // properties, and will exit the VM with the correct error message if the unsupported properties
+    // are used.
+    return false;
+  }
   for (uint i = 0; i < ARRAY_SIZE(unsupported_properties); i++) {
     if (get_property(unsupported_properties[i]) != NULL) {
       if (RequireSharedSpaces) {
@@ -2713,7 +2723,6 @@
       if (FLAG_SET_CMDLINE(bool, DumpSharedSpaces, true) != JVMFlag::SUCCESS) {
         return JNI_EINVAL;
       }
-      set_mode_flags(_int);     // Prevent compilation, which creates objects
     // -Xshare:on
     } else if (match_option(option, "-Xshare:on")) {
       if (FLAG_SET_CMDLINE(bool, UseSharedSpaces, true) != JVMFlag::SUCCESS) {
@@ -2722,7 +2731,7 @@
       if (FLAG_SET_CMDLINE(bool, RequireSharedSpaces, true) != JVMFlag::SUCCESS) {
         return JNI_EINVAL;
       }
-    // -Xshare:auto
+    // -Xshare:auto || -XX:ArchiveClassesAtExit=<archive file>
     } else if (match_option(option, "-Xshare:auto")) {
       if (FLAG_SET_CMDLINE(bool, UseSharedSpaces, true) != JVMFlag::SUCCESS) {
         return JNI_EINVAL;
@@ -3110,15 +3119,24 @@
     // the archived Klasses and Java string objects (at dump time only).
     UseBiasedLocking = false;
 
+    // Compiler threads may concurrently update the class metadata (such as method entries), so it's
+    // unsafe with DumpSharedSpaces (which modifies the class metadata in place). Let's disable
+    // compiler just to be safe.
+    //
+    // Note: this is not a concern for DynamicDumpSharedSpaces, which makes a copy of the class metadata
+    // instead of modifying them in place. The copy is inaccessible to the compiler.
+    // TODO: revisit the following for the static archive case.
+    set_mode_flags(_int);
+  }
+  if (DumpSharedSpaces || ArchiveClassesAtExit != NULL) {
     // Always verify non-system classes during CDS dump
     if (!BytecodeVerificationRemote) {
       BytecodeVerificationRemote = true;
       log_info(cds)("All non-system classes will be verified (-Xverify:remote) during CDS dump time.");
     }
-
-    // Compilation is already disabled if the user specifies -Xshare:dump.
-    // Disable compilation in case user specifies -XX:+DumpSharedSpaces instead of -Xshare:dump.
-    set_mode_flags(_int);
+  }
+  if (ArchiveClassesAtExit == NULL) {
+    FLAG_SET_DEFAULT(DynamicDumpSharedSpaces, false);
   }
   if (UseSharedSpaces && patch_mod_javabase) {
     no_shared_spaces("CDS is disabled when " JAVA_BASE_NAME " module is patched.");
@@ -3427,6 +3445,7 @@
   }
 }
 
+#if INCLUDE_CDS
 // Sharing support
 // Construct the path to the archive
 char* Arguments::get_default_shared_archive_path() {
@@ -3446,15 +3465,104 @@
   return default_archive_path;
 }
 
-static char* get_shared_archive_path() {
-  char *shared_archive_path;
+int Arguments::num_archives(const char* archive_path) {
+  if (archive_path == NULL) {
+    return 0;
+  }
+  int npaths = 1;
+  char* p = (char*)archive_path;
+  while (*p != '\0') {
+    if (*p == os::path_separator()[0]) {
+      npaths++;
+    }
+    p++;
+  }
+  return npaths;
+}
+
+void Arguments::extract_shared_archive_paths(const char* archive_path,
+                                         char** base_archive_path,
+                                         char** top_archive_path) {
+  char* begin_ptr = (char*)archive_path;
+  char* end_ptr = strchr((char*)archive_path, os::path_separator()[0]);
+  if (end_ptr == NULL || end_ptr == begin_ptr) {
+    vm_exit_during_initialization("Base archive was not specified", archive_path);
+  }
+  size_t len = end_ptr - begin_ptr;
+  char* cur_path = NEW_C_HEAP_ARRAY(char, len + 1, mtInternal);
+  strncpy(cur_path, begin_ptr, len);
+  cur_path[len] = '\0';
+  FileMapInfo::check_archive((const char*)cur_path, true /*is_static*/);
+  *base_archive_path = cur_path;
+
+  begin_ptr = ++end_ptr;
+  if (*begin_ptr == '\0') {
+    vm_exit_during_initialization("Top archive was not specified", archive_path);
+  }
+  end_ptr = strchr(begin_ptr, '\0');
+  assert(end_ptr != NULL, "sanity");
+  len = end_ptr - begin_ptr;
+  cur_path = NEW_C_HEAP_ARRAY(char, len + 1, mtInternal);
+  strncpy(cur_path, begin_ptr, len + 1);
+  //cur_path[len] = '\0';
+  FileMapInfo::check_archive((const char*)cur_path, false /*is_static*/);
+  *top_archive_path = cur_path;
+}
+
+bool Arguments::init_shared_archive_paths() {
+  if (ArchiveClassesAtExit != NULL) {
+    if (DumpSharedSpaces) {
+      vm_exit_during_initialization("-XX:ArchiveClassesAtExit cannot be used with -Xshare:dump");
+    }
+    if (FLAG_SET_CMDLINE(bool, DynamicDumpSharedSpaces, true) != JVMFlag::SUCCESS) {
+      return false;
+    }
+    check_unsupported_dumping_properties();
+    SharedDynamicArchivePath = os::strdup_check_oom(ArchiveClassesAtExit, mtArguments);
+  }
   if (SharedArchiveFile == NULL) {
-    shared_archive_path = Arguments::get_default_shared_archive_path();
+    SharedArchivePath = get_default_shared_archive_path();
   } else {
-    shared_archive_path = os::strdup_check_oom(SharedArchiveFile, mtArguments);
+    int archives = num_archives(SharedArchiveFile);
+    if (DynamicDumpSharedSpaces || DumpSharedSpaces) {
+      if (archives > 1) {
+        vm_exit_during_initialization(
+          "Cannot have more than 1 archive file specified in -XX:SharedArchiveFile during CDS dumping");
+      }
+      if (DynamicDumpSharedSpaces) {
+        if (FileMapInfo::same_files(SharedArchiveFile, ArchiveClassesAtExit)) {
+          vm_exit_during_initialization(
+            "Cannot have the same archive file specified for -XX:SharedArchiveFile and -XX:ArchiveClassesAtExit",
+            SharedArchiveFile);
+        }
+      }
+    }
+    if (!DynamicDumpSharedSpaces && !DumpSharedSpaces){
+      if (archives > 2) {
+        vm_exit_during_initialization(
+          "Cannot have more than 2 archive files specified in the -XX:SharedArchiveFile option");
+      }
+      if (archives == 1) {
+        char* temp_archive_path = os::strdup_check_oom(SharedArchiveFile, mtArguments);
+        int name_size;
+        bool success =
+          FileMapInfo::get_base_archive_name_from_header(temp_archive_path, &name_size, &SharedArchivePath);
+        if (!success) {
+          SharedArchivePath = temp_archive_path;
+        } else {
+          SharedDynamicArchivePath = temp_archive_path;
+        }
+      } else {
+        extract_shared_archive_paths((const char*)SharedArchiveFile,
+                                      &SharedArchivePath, &SharedDynamicArchivePath);
+      }
+    } else { // CDS dumping
+      SharedArchivePath = os::strdup_check_oom(SharedArchiveFile, mtArguments);
+    }
   }
-  return shared_archive_path;
+  return (SharedArchivePath != NULL);
 }
+#endif // INCLUDE_CDS
 
 #ifndef PRODUCT
 // Determine whether LogVMOutput should be implicitly turned on.
@@ -3786,11 +3894,12 @@
     return result;
   }
 
-  // Call get_shared_archive_path() here, after possible SharedArchiveFile option got parsed.
-  SharedArchivePath = get_shared_archive_path();
-  if (SharedArchivePath == NULL) {
+#if INCLUDE_CDS
+  // Initialize shared archive paths which could include both base and dynamic archive paths
+  if (!init_shared_archive_paths()) {
     return JNI_ENOMEM;
   }
+#endif
 
   // Delay warning until here so that we've had a chance to process
   // the -XX:-PrintWarnings flag
--- a/src/hotspot/share/runtime/arguments.hpp	Fri May 17 10:48:02 2019 -0400
+++ b/src/hotspot/share/runtime/arguments.hpp	Fri May 17 08:29:55 2019 -0700
@@ -484,6 +484,11 @@
   static AliasedLoggingFlag catch_logging_aliases(const char* name, bool on);
 
   static char*  SharedArchivePath;
+  static char*  SharedDynamicArchivePath;
+  static int num_archives(const char* archive_path) NOT_CDS_RETURN_(0);
+  static void extract_shared_archive_paths(const char* archive_path,
+                                         char** base_archive_path,
+                                         char** top_archive_path) NOT_CDS_RETURN;
 
  public:
   // Parses the arguments, first phase
@@ -563,6 +568,7 @@
   static vfprintf_hook_t vfprintf_hook()    { return _vfprintf_hook; }
 
   static const char* GetSharedArchivePath() { return SharedArchivePath; }
+  static const char* GetSharedDynamicArchivePath() { return SharedDynamicArchivePath; }
 
   // Java launcher properties
   static void process_sun_java_launcher_properties(JavaVMInitArgs* args);
@@ -625,7 +631,8 @@
   static char* get_appclasspath() { return _java_class_path->value(); }
   static void  fix_appclasspath();
 
-  static char* get_default_shared_archive_path();
+  static char* get_default_shared_archive_path() NOT_CDS_RETURN_(NULL);
+  static bool  init_shared_archive_paths() NOT_CDS_RETURN_(false);
 
   // Operation modi
   static Mode mode()                        { return _mode; }
--- a/src/hotspot/share/runtime/globals.hpp	Fri May 17 10:48:02 2019 -0400
+++ b/src/hotspot/share/runtime/globals.hpp	Fri May 17 08:29:55 2019 -0700
@@ -2359,6 +2359,9 @@
           "shared spaces, and dumps the shared spaces to a file to be "     \
           "used in future JVM runs")                                        \
                                                                             \
+  product(bool, DynamicDumpSharedSpaces, false,                             \
+          "Dynamic archive")                                                \
+                                                                            \
   product(bool, PrintSharedArchiveAndExit, false,                           \
           "Print shared archive file contents")                             \
                                                                             \
@@ -2476,6 +2479,9 @@
   product(ccstr, SharedArchiveFile, NULL,                                   \
           "Override the default location of the CDS archive file")          \
                                                                             \
+  product(ccstr, ArchiveClassesAtExit, NULL,                                \
+          "The path and name of the dynamic archive file")                  \
+                                                                            \
   product(ccstr, ExtraSharedClassListFile, NULL,                            \
           "Extra classlist for building the CDS archive file")              \
                                                                             \
--- a/src/hotspot/share/runtime/java.cpp	Fri May 17 10:48:02 2019 -0400
+++ b/src/hotspot/share/runtime/java.cpp	Fri May 17 08:29:55 2019 -0700
@@ -43,6 +43,7 @@
 #include "logging/logStream.hpp"
 #include "memory/oopFactory.hpp"
 #include "memory/resourceArea.hpp"
+#include "memory/dynamicArchive.hpp"
 #include "memory/universe.hpp"
 #include "oops/constantPool.hpp"
 #include "oops/generateOopMap.hpp"
@@ -498,6 +499,12 @@
   // Note: we don't wait until it actually dies.
   os::terminate_signal_thread();
 
+#if INCLUDE_CDS
+  if (DynamicDumpSharedSpaces) {
+    DynamicArchive::dump();
+  }
+#endif
+
   print_statistics();
   Universe::heap()->print_tracing_info();
 
--- a/src/hotspot/share/runtime/mutexLocker.cpp	Fri May 17 10:48:02 2019 -0400
+++ b/src/hotspot/share/runtime/mutexLocker.cpp	Fri May 17 08:29:55 2019 -0700
@@ -153,9 +153,12 @@
 #if INCLUDE_NMT
 Mutex*   NMTQuery_lock                = NULL;
 #endif
-#if INCLUDE_CDS && INCLUDE_JVMTI
+#if INCLUDE_CDS
+#if INCLUDE_JVMTI
 Mutex*   CDSClassFileStream_lock      = NULL;
 #endif
+Mutex*   DumpTimeTable_lock           = NULL;
+#endif // INCLUDE_CDS
 
 #if INCLUDE_JVMCI
 Monitor* JVMCI_lock                   = NULL;
@@ -351,7 +354,8 @@
 #if INCLUDE_NMT
   def(NMTQuery_lock                , PaddedMutex  , max_nonleaf, false, Monitor::_safepoint_check_always);
 #endif
-#if INCLUDE_CDS && INCLUDE_JVMTI
+#if INCLUDE_CDS
+#if INCLUDE_JVMTI
   def(CDSClassFileStream_lock      , PaddedMutex  , max_nonleaf, false, Monitor::_safepoint_check_always);
 #endif
 
@@ -360,6 +364,8 @@
   def(JVMCIGlobalAlloc_lock        , PaddedMutex  , nonleaf,     true,  Monitor::_safepoint_check_never);
   def(JVMCIGlobalActive_lock       , PaddedMutex  , nonleaf-1,   true,  Monitor::_safepoint_check_never);
 #endif
+  def(DumpTimeTable_lock           , PaddedMutex  , leaf,        true,  Monitor::_safepoint_check_never);
+#endif // INCLUDE_CDS
 }
 
 GCMutexLocker::GCMutexLocker(Monitor * mutex) {
--- a/src/hotspot/share/runtime/mutexLocker.hpp	Fri May 17 10:48:02 2019 -0400
+++ b/src/hotspot/share/runtime/mutexLocker.hpp	Fri May 17 08:29:55 2019 -0700
@@ -132,9 +132,12 @@
 #if INCLUDE_NMT
 extern Mutex*   NMTQuery_lock;                   // serialize NMT Dcmd queries
 #endif
-#if INCLUDE_CDS && INCLUDE_JVMTI
+#if INCLUDE_CDS
+#if INCLUDE_JVMTI
 extern Mutex*   CDSClassFileStream_lock;         // FileMapInfo::open_stream_for_jvmti
 #endif
+extern Mutex*   DumpTimeTable_lock;              // SystemDictionaryShared::find_or_allocate_info_for
+#endif // INCLUDE_CDS
 #if INCLUDE_JFR
 extern Mutex*   JfrStacktrace_lock;              // used to guard access to the JFR stacktrace table
 extern Monitor* JfrMsg_lock;                     // protects JFR messaging
--- a/src/hotspot/share/runtime/thread.cpp	Fri May 17 10:48:02 2019 -0400
+++ b/src/hotspot/share/runtime/thread.cpp	Fri May 17 08:29:55 2019 -0700
@@ -3964,10 +3964,8 @@
   SystemDictionary::compute_java_loaders(CHECK_JNI_ERR);
 
 #if INCLUDE_CDS
-  if (DumpSharedSpaces) {
-    // capture the module path info from the ModuleEntryTable
-    ClassLoader::initialize_module_path(THREAD);
-  }
+  // capture the module path info from the ModuleEntryTable
+  ClassLoader::initialize_module_path(THREAD);
 #endif
 
 #if INCLUDE_JVMCI
@@ -4169,7 +4167,7 @@
   for (agent = Arguments::agents(); agent != NULL; agent = agent->next()) {
     // CDS dumping does not support native JVMTI agent.
     // CDS dumping supports Java agent if the AllowArchivingWithJavaAgent diagnostic option is specified.
-    if (DumpSharedSpaces) {
+    if (DumpSharedSpaces || DynamicDumpSharedSpaces) {
       if(!agent->is_instrument_lib()) {
         vm_exit_during_cds_dumping("CDS dumping does not support native JVMTI agent, name", agent->name());
       } else if (!AllowArchivingWithJavaAgent) {
--- a/test/hotspot/jtreg/TEST.groups	Fri May 17 10:48:02 2019 -0400
+++ b/test/hotspot/jtreg/TEST.groups	Fri May 17 08:29:55 2019 -0700
@@ -314,6 +314,23 @@
 hotspot_appcds = \
   runtime/appcds/
 
+hotspot_appcds_dynamic = \
+  runtime/appcds/ \
+ -runtime/appcds/cacheObject \
+ -runtime/appcds/customLoader \
+ -runtime/appcds/dynamicArchive \
+ -runtime/appcds/javaldr/ArrayTest.java \
+ -runtime/appcds/javaldr/GCSharedStringsDuringDump.java \
+ -runtime/appcds/javaldr/HumongousDuringDump.java \
+ -runtime/appcds/sharedStrings \
+ -runtime/appcds/DumpClassList.java \
+ -runtime/appcds/ExtraSymbols.java \
+ -runtime/appcds/LongClassListPath.java \
+ -runtime/appcds/LotsOfClasses.java \
+ -runtime/appcds/SharedArchiveConsistency.java \
+ -runtime/appcds/UnusedCPDuringDump.java \
+ -runtime/appcds/VerifierTest_1B.java
+
 # A subset of AppCDS tests to be run in tier1
 tier1_runtime_appcds = \
   runtime/appcds/HelloTest.java \
--- a/test/hotspot/jtreg/runtime/appcds/AppendClasspath.java	Fri May 17 10:48:02 2019 -0400
+++ b/test/hotspot/jtreg/runtime/appcds/AppendClasspath.java	Fri May 17 08:29:55 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2019, 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
@@ -58,23 +58,26 @@
     // FAIL: 2) runtime with classpath different from the one used in dump time
     // (runtime has an extra jar file prepended to the class path)
     TestCommon.run(
+        "-Xlog:cds",
         "-cp", appJar2 + File.pathSeparator + appJar,
         "HelloMore")
-      .assertAbnormalExit(errorMessage1, errorMessage2);
+        .assertAbnormalExit(errorMessage1, errorMessage2);
 
     // FAIL: 3) runtime with classpath part of the one used in dump time
     TestCommon.testDump(appJar + File.pathSeparator + appJar2,
                                       TestCommon.list("Hello"));
     TestCommon.run(
+        "-Xlog:cds",
         "-cp", appJar2,
         "Hello")
-      .assertAbnormalExit(errorMessage1, errorMessage2);
+        .assertAbnormalExit(errorMessage1, errorMessage2);
 
     // FAIL: 4) runtime with same set of jar files in the classpath but
     // with different order
     TestCommon.run(
+        "-Xlog:cds",
         "-cp", appJar2 + File.pathSeparator + appJar,
         "HelloMore")
-      .assertAbnormalExit(errorMessage1, errorMessage2);
+        .assertAbnormalExit(errorMessage1, errorMessage2);
   }
 }
--- a/test/hotspot/jtreg/runtime/appcds/BootClassPathMismatch.java	Fri May 17 10:48:02 2019 -0400
+++ b/test/hotspot/jtreg/runtime/appcds/BootClassPathMismatch.java	Fri May 17 08:29:55 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2019, 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
@@ -55,7 +55,11 @@
         test.testBootClassPathMismatch();
         test.testBootClassPathMismatchWithAppClass();
         test.testBootClassPathMismatchWithBadPath();
-        test.testBootClassPathMatchWithAppend();
+        if (!TestCommon.isDynamicArchive()) {
+            // this test is not applicable to dynamic archive since
+            // there is no class to be archived in the top archive
+            test.testBootClassPathMatchWithAppend();
+        }
         test.testBootClassPathMatch();
     }
 
@@ -77,11 +81,13 @@
 
         TestCommon.dump(appJar, appClasses, "-Xbootclasspath/a:" + appJar);
         TestCommon.run(
+                "-Xlog:cds",
                 "-cp", appJar, "-Xbootclasspath/a:" + otherJar, "Hello")
             .assertAbnormalExit(mismatchMessage);
 
         TestCommon.dump(appJar, appClasses, "-Xbootclasspath/a:" + otherJar);
         TestCommon.run(
+                "-Xlog:cds",
                 "-cp", appJar, "-Xbootclasspath/a:" + appJar, "Hello")
             .assertAbnormalExit(mismatchMessage);
     }
@@ -100,6 +106,7 @@
 
         TestCommon.dump(appJar, appClasses, "-Xbootclasspath/a:" + appJar);
         TestCommon.run(
+                "-Xlog:cds",
                 "-cp", appJar, "-Xbootclasspath/a:" + otherJar, "Hello")
             .assertAbnormalExit(mismatchMessage);
     }
@@ -148,6 +155,7 @@
         String appClasses[] = {"Hello"};
         TestCommon.dump(appJar, appClasses);
         TestCommon.run(
+                "-Xlog:cds",
                 "-cp", appJar, "-Xbootclasspath/a:" + appJar, "Hello")
             .assertAbnormalExit(mismatchMessage);
     }
--- a/test/hotspot/jtreg/runtime/appcds/CDSandJFR.java	Fri May 17 10:48:02 2019 -0400
+++ b/test/hotspot/jtreg/runtime/appcds/CDSandJFR.java	Fri May 17 08:29:55 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2018, 2019, 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
@@ -30,7 +30,7 @@
  * @modules jdk.jfr
  * @build Hello GetFlightRecorder
  * @run driver ClassFileInstaller -jar CDSandJFR.jar Hello GetFlightRecorder GetFlightRecorder$TestEvent GetFlightRecorder$SimpleEvent
- * @run driver/timeout=500 CDSandJFR
+ * @run main/othervm/timeout=500 CDSandJFR
  */
 
 import jdk.test.lib.BuildHelper;
--- a/test/hotspot/jtreg/runtime/appcds/CaseSensitiveClassPath.java	Fri May 17 10:48:02 2019 -0400
+++ b/test/hotspot/jtreg/runtime/appcds/CaseSensitiveClassPath.java	Fri May 17 08:29:55 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2019, 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
@@ -78,8 +78,7 @@
         }
         boolean isSameFile = Files.isSameFile(jarPath, jarPathUpper);
 
-        TestCommon.run("-cp", appJarUpper, "Hello", "-Xlog:class+path=info",
-                       "-Xlog:cds")
+        TestCommon.run("-Xlog:class+path=info,cds", "-cp", appJarUpper, "Hello")
             .ifNoMappingFailure(output -> {
                     if (isSameFile) {
                         output.shouldContain("Hello World");
--- a/test/hotspot/jtreg/runtime/appcds/CommandLineFlagCombo.java	Fri May 17 10:48:02 2019 -0400
+++ b/test/hotspot/jtreg/runtime/appcds/CommandLineFlagCombo.java	Fri May 17 08:29:55 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2019, 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
@@ -72,10 +72,22 @@
                 continue;
 
             OutputAnalyzer dumpOutput = TestCommon.dump(appJar, classList, testEntry);
-            TestCommon.checkDump(dumpOutput, "Loading classes to share");
+            if (!TestCommon.isDynamicArchive()) {
+                TestCommon.checkDump(dumpOutput, "Loading classes to share");
+            } else {
+                if (testEntry.contains("ObjectAlignmentInBytes")) {
+                   dumpOutput.shouldHaveExitValue(1)
+                             .shouldMatch("The shared archive file's ObjectAlignmentInBytes of .* does not equal the current ObjectAlignmentInBytes of");
+                } else {
+                   TestCommon.checkDump(dumpOutput, "Loading classes to share");
+                }
+            }
 
-            OutputAnalyzer execOutput = TestCommon.exec(appJar, testEntry, "Hello");
-            TestCommon.checkExec(execOutput, "Hello World");
+            if ((TestCommon.isDynamicArchive() && !testEntry.contains("ObjectAlignmentInBytes")) ||
+                !TestCommon.isDynamicArchive()) {
+                OutputAnalyzer execOutput = TestCommon.exec(appJar, testEntry, "Hello");
+                TestCommon.checkExec(execOutput, "Hello World");
+            }
         }
 
         for (int i=0; i<2; i++) {
--- a/test/hotspot/jtreg/runtime/appcds/CommandLineFlagComboNegative.java	Fri May 17 10:48:02 2019 -0400
+++ b/test/hotspot/jtreg/runtime/appcds/CommandLineFlagComboNegative.java	Fri May 17 08:29:55 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2019, 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,8 +65,10 @@
         if (Platform.is64bit()) {
             testTable.add( new TestVector("-XX:ObjectAlignmentInBytes=8", "-XX:ObjectAlignmentInBytes=16",
                 "An error has occurred while processing the shared archive file", 1) );
-            testTable.add( new TestVector("-XX:ObjectAlignmentInBytes=64", "-XX:ObjectAlignmentInBytes=32",
-                "An error has occurred while processing the shared archive file", 1) );
+            if (!TestCommon.isDynamicArchive()) {
+                testTable.add( new TestVector("-XX:ObjectAlignmentInBytes=64", "-XX:ObjectAlignmentInBytes=32",
+                    "An error has occurred while processing the shared archive file", 1) );
+            }
             testTable.add( new TestVector("-XX:+UseCompressedOops", "-XX:-UseCompressedOops",
                 "Class data sharing is inconsistent with other specified options", 1) );
             testTable.add( new TestVector("-XX:+UseCompressedClassPointers", "-XX:-UseCompressedClassPointers",
--- a/test/hotspot/jtreg/runtime/appcds/DirClasspathTest.java	Fri May 17 10:48:02 2019 -0400
+++ b/test/hotspot/jtreg/runtime/appcds/DirClasspathTest.java	Fri May 17 08:29:55 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, 2019, 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
@@ -27,7 +27,9 @@
  * @summary Handling of directories in -cp is based on the classlist
  * @requires vm.cds
  * @library /test/lib
+ * @modules jdk.jartool/sun.tools.jar
  * @compile test-classes/Hello.java
+ * @compile test-classes/Super.java
  * @run driver DirClasspathTest
  */
 
@@ -42,11 +44,19 @@
 public class DirClasspathTest {
     private static final int MAX_PATH = 260;
 
+    // We add helloJar into the classpath to be compatible with TestCommon.DYNAMIC_DUMP
+    static OutputAnalyzer doDump(String path, String classList[],
+                                        String... suffix) throws Exception {
+        String helloJar = JarBuilder.getOrCreateHelloJar();
+        return TestCommon.dump(helloJar + File.pathSeparator + path, classList, suffix);
+    }
+
     public static void main(String[] args) throws Exception {
         File dir = new File(System.getProperty("user.dir"));
         File emptydir = new File(dir, "emptydir");
         emptydir.mkdir();
 
+
         /////////////////////////////////////////////////////////////////
         // The classlist only contains boot class in following test cases
         /////////////////////////////////////////////////////////////////
@@ -54,7 +64,7 @@
 
         // Empty dir in -cp: should be OK
         OutputAnalyzer output;
-        output = TestCommon.dump(emptydir.getPath(), bootClassList, "-Xlog:class+path=info");
+        output = doDump(emptydir.getPath(), bootClassList, "-Xlog:class+path=info");
         TestCommon.checkDump(output);
 
         // Long path to empty dir in -cp: should be OK
@@ -71,17 +81,17 @@
         longDir.mkdir();
         File subDir = new File(longDir, "subdir");
         subDir.mkdir();
-        output = TestCommon.dump(subDir.getPath(), bootClassList, "-Xlog:class+path=info");
+        output = doDump(subDir.getPath(), bootClassList, "-Xlog:class+path=info");
         TestCommon.checkDump(output);
 
         // Non-empty dir in -cp: should be OK
         // <dir> is not empty because it has at least one subdirectory, i.e., <emptydir>
-        output = TestCommon.dump(dir.getPath(), bootClassList, "-Xlog:class+path=info");
+        output = doDump(dir.getPath(), bootClassList, "-Xlog:class+path=info");
         TestCommon.checkDump(output);
 
         // Long path to non-empty dir in -cp: should be OK
         // <dir> is not empty because it has at least one subdirectory, i.e., <emptydir>
-        output = TestCommon.dump(longDir.getPath(), bootClassList, "-Xlog:class+path=info");
+        output = doDump(longDir.getPath(), bootClassList, "-Xlog:class+path=info");
         TestCommon.checkDump(output);
 
         /////////////////////////////////////////////////////////////////
@@ -90,27 +100,27 @@
         String appClassList[] = {"java/lang/Object", "com/sun/tools/javac/Main"};
 
         // Non-empty dir in -cp: should be OK (as long as no classes were loaded from there)
-        output = TestCommon.dump(dir.getPath(), appClassList, "-Xlog:class+path=info");
+        output = doDump(dir.getPath(), appClassList, "-Xlog:class+path=info");
         TestCommon.checkDump(output);
 
         // Long path to non-empty dir in -cp: should be OK (as long as no classes were loaded from there)
-        output = TestCommon.dump(longDir.getPath(), appClassList, "-Xlog:class+path=info");
+        output = doDump(longDir.getPath(), appClassList, "-Xlog:class+path=info");
         TestCommon.checkDump(output);
 
         /////////////////////////////////////////////////////////////////
         // Loading an app class from a directory
         /////////////////////////////////////////////////////////////////
-        String appClassList2[] = {"Hello", "java/lang/Object", "com/sun/tools/javac/Main"};
+        String appClassList2[] = {"Super", "java/lang/Object", "com/sun/tools/javac/Main"};
         // Non-empty dir in -cp: should report error if a class is loaded from it
-        output = TestCommon.dump(classDir.toString(), appClassList2, "-Xlog:class+path=info");
+        output = doDump(classDir.toString(), appClassList2, "-Xlog:class+path=info,class+load=trace");
         output.shouldNotHaveExitValue(0);
         output.shouldContain("Cannot have non-empty directory in paths");
 
         // Long path to non-empty dir in -cp: should report error if a class is loaded from it
-        File srcClass = new File(classDir.toFile(), "Hello.class");
-        File destClass = new File(longDir, "Hello.class");
+        File srcClass = new File(classDir.toFile(), "Super.class");
+        File destClass = new File(longDir, "Super.class");
         Files.copy(srcClass.toPath(), destClass.toPath());
-        output = TestCommon.dump(longDir.getPath(), appClassList2, "-Xlog:class+path=info");
+        output = doDump(longDir.getPath(), appClassList2, "-Xlog:class+path=info");
         output.shouldNotHaveExitValue(0);
         output.shouldContain("Cannot have non-empty directory in paths");
     }
--- a/test/hotspot/jtreg/runtime/appcds/JvmtiAddPath.java	Fri May 17 10:48:02 2019 -0400
+++ b/test/hotspot/jtreg/runtime/appcds/JvmtiAddPath.java	Fri May 17 08:29:55 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2019, 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
@@ -84,7 +84,9 @@
         run(check_appcds_enabled, appJar, "-Xlog:class+load", "JvmtiApp", "noadd"); // 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", "JvmtiApp", "bootonly", addbootJar); // appcds should be disabled
+        String[] toCheck = (TestCommon.isDynamicArchive()) ? check_appcds_enabled
+                                                           : check_appcds_disabled;
+        run(toCheck, appJar, "-Xlog:class+load", "JvmtiApp", "bootonly", addbootJar); // appcds should be disabled
 
         System.out.println("Test case 3: add to app classpath only - should find Hello.class in app loader");
         run(appJar, "JvmtiApp", "apponly", addappJar);
@@ -97,7 +99,11 @@
 
         System.out.println("Test case 6: add to app using AppCDS, but add to boot using JVMTI - should find Hello.class in boot loader");
         TestCommon.testDump(twoAppJars, TestCommon.list("JvmtiApp", "ExtraClass", "Hello"), use_whitebox_jar);
-        run(twoAppJars, "JvmtiApp", "bootonly", addappJar);
+        if (!TestCommon.isDynamicArchive()) {
+            // skip for dynamic archive, the Hello class will be loaded from
+            // the dynamic archive
+            run(twoAppJars, "JvmtiApp", "bootonly", addappJar);
+        }
 
         System.out.println("Test case 7: add to app using AppCDS, no JVMTI calls - should find Hello.class in app loader");
         run(twoAppJars, "JvmtiApp", "noadd-appcds");
--- a/test/hotspot/jtreg/runtime/appcds/LotsOfClasses.java	Fri May 17 10:48:02 2019 -0400
+++ b/test/hotspot/jtreg/runtime/appcds/LotsOfClasses.java	Fri May 17 08:29:55 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2018, 2019, 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
@@ -22,15 +22,7 @@
  *
  */
 
-import java.net.URI;
-import java.nio.file.DirectoryStream;
-import java.nio.file.Files;
-import java.nio.file.FileSystem;
-import java.nio.file.FileSystems;
-import java.nio.file.Path;
 import java.util.ArrayList;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
 
 import jdk.test.lib.cds.CDSTestUtils;
 import jdk.test.lib.cds.CDSOptions;
@@ -41,16 +33,15 @@
  * @summary Try to archive lots of classes by searching for classes from the jrt:/ file system. With JDK 12
  *          this will produce an archive with over 30,000 classes.
  * @requires vm.cds
- * @library /test/lib
+ * @library /test/lib /test/hotspot/jtreg/runtime/appcds
  * @run driver/timeout=500 LotsOfClasses
  */
 
 public class LotsOfClasses {
-    static Pattern pattern;
 
     public static void main(String[] args) throws Throwable {
         ArrayList<String> list = new ArrayList<>();
-        findAllClasses(list);
+        TestCommon.findAllClasses(list);
 
         CDSOptions opts = new CDSOptions();
         opts.setClassList(list);
@@ -64,28 +55,4 @@
         OutputAnalyzer out = CDSTestUtils.createArchive(opts);
         CDSTestUtils.checkDump(out);
     }
-
-    static void findAllClasses(ArrayList<String> list) throws Throwable {
-        // Find all the classes in the jrt file system
-        pattern = Pattern.compile("/modules/[a-z.]*[a-z]+/([^-]*)[.]class");
-        FileSystem fs = FileSystems.getFileSystem(URI.create("jrt:/"));
-        Path base = fs.getPath("/modules/");
-        find(base, list);
-    }
-
-    static void find(Path p, ArrayList<String> list) throws Throwable {
-        try (DirectoryStream<Path> stream = Files.newDirectoryStream(p)) {
-                for (Path entry: stream) {
-                    Matcher matcher = pattern.matcher(entry.toString());
-                    if (matcher.find()) {
-                        String className = matcher.group(1);
-                        list.add(className);
-                        //System.out.println(className);
-                    }
-                    try {
-                        find(entry, list);
-                    } catch (Throwable t) {}
-                }
-            }
-    }
 }
--- a/test/hotspot/jtreg/runtime/appcds/PackageSealing.java	Fri May 17 10:48:02 2019 -0400
+++ b/test/hotspot/jtreg/runtime/appcds/PackageSealing.java	Fri May 17 08:29:55 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2019, 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
@@ -27,14 +27,15 @@
  * @summary AppCDS handling of package.
  * @requires vm.cds
  * @library /test/lib
- * @modules java.base/jdk.internal.misc
- *          java.management
+ * @modules jdk.jartool/sun.tools.jar
  * @compile test-classes/C1.java
  * @compile test-classes/C2.java
  * @compile test-classes/PackageSealingTest.java
+ * @compile test-classes/Hello.java
  * @run driver PackageSealing
  */
 
+import java.io.File;
 import jdk.test.lib.process.OutputAnalyzer;
 
 public class PackageSealing {
@@ -44,16 +45,19 @@
             ClassFileInstaller.Manifest.fromSourceFile("test-classes/package_seal.mf"),
             "PackageSealingTest", "sealed/pkg/C1", "pkg/C2");
 
+        String helloJar = JarBuilder.getOrCreateHelloJar();
+        String jars = helloJar + File.pathSeparator + appJar;
+
         // test shared package from -cp path
-        TestCommon.testDump(appJar, TestCommon.list(classList));
+        TestCommon.testDump(jars, TestCommon.list(classList));
         OutputAnalyzer output;
-        output = TestCommon.exec(appJar, "PackageSealingTest");
+        output = TestCommon.exec(jars, "PackageSealingTest");
         TestCommon.checkExec(output, "OK");
 
         // test shared package from -Xbootclasspath/a
-        TestCommon.dump(appJar, TestCommon.list(classList),
+        TestCommon.dump(helloJar, TestCommon.list(classList),
                         "-Xbootclasspath/a:" + appJar);
-        output = TestCommon.exec(appJar, "-Xbootclasspath/a:" + appJar, "PackageSealingTest");
+        output = TestCommon.exec(helloJar, "-Xbootclasspath/a:" + appJar, "PackageSealingTest");
         TestCommon.checkExec(output, "OK");
     }
 }
--- a/test/hotspot/jtreg/runtime/appcds/ProhibitedPackage.java	Fri May 17 10:48:02 2019 -0400
+++ b/test/hotspot/jtreg/runtime/appcds/ProhibitedPackage.java	Fri May 17 08:29:55 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2019, 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
@@ -27,9 +27,7 @@
  * @summary AppCDS handling of prohibited package.
  * @requires vm.cds
  * @library /test/lib
- * @modules java.base/jdk.internal.misc
- *          java.management
- *          jdk.jartool/sun.tools.jar
+ * @modules jdk.jartool/sun.tools.jar
  * @compile test-classes/ProhibitedHelper.java test-classes/Prohibited.jasm
  * @run driver ProhibitedPackage
  */
@@ -46,7 +44,8 @@
         String appJar = TestCommon.getTestJar("prohibited_pkg.jar");
 
         // Test support for customer loaders
-        if (Platform.areCustomLoadersSupportedForCDS()) {
+        if (Platform.areCustomLoadersSupportedForCDS() &&
+            !TestCommon.isDynamicArchive()) {
             String classlist[] = new String[] {
                 "java/lang/Object id: 1",
                 "java/lang/Prohibited id: 2 super: 1 source: " + appJar
--- a/test/hotspot/jtreg/runtime/appcds/SharedArchiveConsistency.java	Fri May 17 10:48:02 2019 -0400
+++ b/test/hotspot/jtreg/runtime/appcds/SharedArchiveConsistency.java	Fri May 17 08:29:55 2019 -0700
@@ -71,7 +71,18 @@
 
     public static File jsa;        // will be updated during test
     public static File orgJsaFile; // kept the original file not touched.
-    public static String[] shared_region_name = {"MiscCode", "ReadWrite", "ReadOnly", "MiscData"};
+    // The following should be consistent with the enum in the C++ MetaspaceShared class
+    public static String[] shared_region_name = {
+        "mc",          // MiscCode
+        "rw",          // ReadWrite
+        "ro",          // ReadOnly
+        "md",          // MiscData
+        "first_closed_archive",
+        "last_closed_archive",
+        "first_open_archive",
+        "last_open_archive"
+    };
+
     public static int num_regions = shared_region_name.length;
     public static String[] matchMessages = {
         "Unable to use shared archive",
@@ -102,10 +113,11 @@
             return file_header_size;
         }
         // this is not real header size, it is struct size
+        int int_size = wb.getOffsetForName("int_size");
         file_header_size = wb.getOffsetForName("file_header_size");
         int offset_path_misc_info = wb.getOffsetForName("FileMapHeader::_paths_misc_info_size") -
             offset_magic;
-        int path_misc_info_size   = (int)readInt(fc, offset_path_misc_info, size_t_size);
+        int path_misc_info_size   = (int)readInt(fc, offset_path_misc_info, int_size);
         file_header_size += path_misc_info_size; //readInt(fc, offset_path_misc_info, size_t_size);
         System.out.println("offset_path_misc_info = " + offset_path_misc_info);
         System.out.println("path_misc_info_size   = " + path_misc_info_size);
@@ -157,25 +169,26 @@
 
     public static void modifyJsaContentRandomly() throws Exception {
         FileChannel fc = getFileChannel();
-        // corrupt random area in the data areas (MiscCode, ReadWrite, ReadOnly, MiscData)
+        // corrupt random area in the data areas
         long[] used    = new long[num_regions];       // record used bytes
         long start0, start, end, off;
         int used_offset, path_info_size;
 
         int bufSize;
-        System.out.printf("%-12s%-12s%-12s%-12s%-12s\n", "Space Name", "Offset", "Used bytes", "Reg Start", "Random Offset");
+        System.out.printf("%-24s%12s%12s%16s\n", "Space Name", "Used bytes", "Reg Start", "Random Offset");
         start0 = getFileHeaderSize(fc);
         for (int i = 0; i < num_regions; i++) {
-            used_offset = sp_offset + CDSFileMapRegion_size * i + sp_used_offset;
-            // read 'used'
-            used[i] = readInt(fc, used_offset, size_t_size);
+            used[i] = get_region_used_size_aligned(fc, i);
             start = start0;
             for (int j = 0; j < i; j++) {
                 start += align_up_page(used[j]);
             }
             end = start + used[i];
+            if (start == end) {
+                continue; // Ignore empty regions
+            }
             off = getRandomBetween(start, end);
-            System.out.printf("%-12s%-12d%-12d%-12d%-12d\n", shared_region_name[i], used_offset, used[i], start, off);
+            System.out.printf("%-24s%12d%12d%16d\n", shared_region_name[i], used[i], start, off);
             if (end - off < 1024) {
                 bufSize = (int)(end - off + 1);
             } else {
@@ -189,34 +202,50 @@
         }
     }
 
-    public static void modifyJsaContent() throws Exception {
+    static long get_region_used_size_aligned(FileChannel fc, int region) throws Exception {
+        long n = sp_offset + CDSFileMapRegion_size * region + sp_used_offset;
+        long alignment = WhiteBox.getWhiteBox().metaspaceReserveAlignment();
+        long used = readInt(fc, n, size_t_size);
+        used = (used + alignment - 1) & ~(alignment - 1);
+        return used;
+    }
+
+    public static boolean modifyJsaContent(int region) throws Exception {
         FileChannel fc = getFileChannel();
         byte[] buf = new byte[4096];
         ByteBuffer bbuf = ByteBuffer.wrap(buf);
 
         long total = 0L;
-        long used_offset = 0L;
         long[] used = new long[num_regions];
-        System.out.printf("%-12s%-12s\n", "Space name", "Used bytes");
+        System.out.printf("%-24s%12s\n", "Space name", "Used bytes");
         for (int i = 0; i < num_regions; i++) {
-            used_offset = sp_offset + CDSFileMapRegion_size* i + sp_used_offset;
-            // read 'used'
-            used[i] = readInt(fc, used_offset, size_t_size);
-            System.out.printf("%-12s%-12d\n", shared_region_name[i], used[i]);
+            used[i] = get_region_used_size_aligned(fc, i);
+            System.out.printf("%-24s%12d\n", shared_region_name[i], used[i]);
             total += used[i];
         }
-        System.out.printf("%-12s%-12d\n", "Total: ", total);
-        long corrupt_used_offset =  getFileHeaderSize(fc);
-        System.out.println("Corrupt RO section, offset = " + corrupt_used_offset);
-        while (used_offset < used[0]) {
-            writeData(fc, corrupt_used_offset, bbuf);
+        System.out.printf("%-24s%12d\n", "Total: ", total);
+        long header_size = getFileHeaderSize(fc);
+        long region_start_offset = header_size;
+        for (int i=0; i<region; i++) {
+            region_start_offset += used[i];
+        }
+        if (used[region] == 0) {
+            System.out.println("Region " + shared_region_name[region] + " is empty. Nothing to corrupt.");
+            return false;
+        }
+        System.out.println("Corrupt " + shared_region_name[region] + " section, start = " + region_start_offset
+                           + " (header_size + 0x" + Long.toHexString(region_start_offset-header_size) + ")");
+        long bytes_written = 0L;
+        while (bytes_written < used[region]) {
+            writeData(fc, region_start_offset + bytes_written, bbuf);
             bbuf.clear();
-            used_offset += 4096;
+            bytes_written += 4096;
         }
         fc.force(true);
         if (fc.isOpen()) {
             fc.close();
         }
+        return true;
     }
 
     public static void modifyJsaHeader() throws Exception {
@@ -299,11 +328,11 @@
     // read the jsa file
     //   1) run normal
     //   2) modify header
-    //   3) keep header correct but modify content
+    //   3) keep header correct but modify content in each region specified by shared_region_name[]
     //   4) update both header and content, test
     //   5) delete bytes in data begining
     //   6) insert bytes in data begining
-    //   7) randomly corrupt data in four areas: RO, RW. MISC DATA, MISC CODE
+    //   7) randomly corrupt data in each region specified by shared_region_name[]
     public static void main(String... args) throws Exception {
         // must call to get offset info first!!!
         getFileOffsetInfo();
@@ -352,18 +381,23 @@
         output.shouldContain("The shared archive file has the wrong version");
         output.shouldNotContain("Checksum verification failed");
 
+        File newJsaFile = null;
         // modify content
         System.out.println("\n3. Corrupt Content, should fail\n");
-
-        copyFile(orgJsaFile, jsa);
-        modifyJsaContent();
-        testAndCheck(verifyExecArgs);
+        for (int i=0; i<num_regions; i++) {
+            newJsaFile = new File(TestCommon.getNewArchiveName(shared_region_name[i]));
+            copyFile(orgJsaFile, newJsaFile);
+            if (modifyJsaContent(i)) {
+                testAndCheck(execArgs);
+            }
+        }
 
         // modify both header and content, test should fail
         System.out.println("\n4. Corrupt Header and Content, should fail\n");
-        copyFile(orgJsaFile, jsa);
+        newJsaFile = new File(TestCommon.getNewArchiveName("header-and-content"));
+        copyFile(orgJsaFile, newJsaFile);
         modifyJsaHeader();
-        modifyJsaContent();  // this will not be reached since failed on header change first
+        modifyJsaContent(0);  // this will not be reached since failed on header change first
         output = TestCommon.execCommon(execArgs);
         output.shouldContain("The shared archive file has the wrong version");
         output.shouldNotContain("Checksum verification failed");
@@ -379,7 +413,8 @@
         testAndCheck(verifyExecArgs);
 
         System.out.println("\n7. modify Content in random areas, should fail\n");
-        copyFile(orgJsaFile, jsa);
+        newJsaFile = new File(TestCommon.getNewArchiveName("random-areas"));
+        copyFile(orgJsaFile, newJsaFile);
         modifyJsaContentRandomly();
         testAndCheck(verifyExecArgs);
     }
--- a/test/hotspot/jtreg/runtime/appcds/TestCommon.java	Fri May 17 10:48:02 2019 -0400
+++ b/test/hotspot/jtreg/runtime/appcds/TestCommon.java	Fri May 17 08:29:55 2019 -0700
@@ -32,10 +32,28 @@
 import jdk.test.lib.process.ProcessTools;
 import jdk.test.lib.process.OutputAnalyzer;
 import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.InputStream;
+import java.net.URI;
+import java.nio.file.DirectoryStream;
+import java.nio.file.Files;
+import java.nio.file.FileSystem;
+import java.nio.file.FileSystems;
+import java.nio.file.Path;
 import java.text.SimpleDateFormat;
 import java.util.Arrays;
 import java.util.ArrayList;
 import java.util.Date;
+import java.util.Enumeration;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
+import java.util.zip.ZipOutputStream;
+import jtreg.SkippedException;
+import cdsutils.DynamicDumpHelper;
+
 
 /**
  * This is a test utility class for common AppCDS test functionality.
@@ -51,7 +69,7 @@
  */
 public class TestCommon extends CDSTestUtils {
     private static final String JSA_FILE_PREFIX = System.getProperty("user.dir") +
-        File.separator + "appcds-";
+        File.separator;
 
     private static final SimpleDateFormat timeStampFormat =
         new SimpleDateFormat("HH'h'mm'm'ss's'SSS");
@@ -64,8 +82,7 @@
     // Call this method to start new archive with new unique name
     public static void startNewArchiveName() {
         deletePriorArchives();
-        currentArchiveName = JSA_FILE_PREFIX +
-            timeStampFormat.format(new Date()) + ".jsa";
+        currentArchiveName = getNewArchiveName();
     }
 
     // Call this method to get current archive name
@@ -73,6 +90,18 @@
         return currentArchiveName;
     }
 
+    public static String getNewArchiveName() {
+        return getNewArchiveName(null);
+    }
+
+    public static String getNewArchiveName(String stem) {
+        if (stem == null) {
+            stem = "appcds";
+        }
+        return JSA_FILE_PREFIX + stem + "-" +
+            timeStampFormat.format(new Date()) + ".jsa";
+    }
+
     // Attempt to clean old archives to preserve space
     // Archives are large artifacts (20Mb or more), and much larger than
     // most other artifacts created in jtreg testing.
@@ -92,7 +121,6 @@
         }
     }
 
-
     // Create AppCDS archive using most common args - convenience method
     // Legacy name preserved for compatibility
     public static OutputAnalyzer dump(String appJar, String classList[],
@@ -110,10 +138,12 @@
         return createArchive(opts);
     }
 
+    // Simulate -Xshare:dump with -XX:ArchiveClassesAtExit. See comments around patchJarForDynamicDump()
+    private static final Class tmp = DynamicDumpHelper.class;
+
     // Create AppCDS archive using appcds options
     public static OutputAnalyzer createArchive(AppCDSOptions opts)
         throws Exception {
-
         ArrayList<String> cmd = new ArrayList<String>();
         startNewArchiveName();
 
@@ -122,23 +152,73 @@
         if (opts.appJar != null) {
             cmd.add("-cp");
             cmd.add(opts.appJar);
+            File jf = new File(opts.appJar);
+            if (DYNAMIC_DUMP && !jf.isDirectory()) {
+                patchJarForDynamicDump(opts.appJar);
+            }
         } else {
             cmd.add("-Djava.class.path=");
         }
 
-        cmd.add("-Xshare:dump");
-
-        if (opts.archiveName == null)
+        if (opts.archiveName == null) {
             opts.archiveName = getCurrentArchiveName();
-
-        cmd.add("-XX:SharedArchiveFile=" + opts.archiveName);
-
-        if (opts.classList != null) {
-            File classListFile = makeClassList(opts.classList);
-            cmd.add("-XX:ExtraSharedClassListFile=" + classListFile.getPath());
         }
 
-        for (String s : opts.suffix) cmd.add(s);
+        if (DYNAMIC_DUMP) {
+            cmd.add("-Xshare:on");
+            cmd.add("-XX:ArchiveClassesAtExit=" + opts.archiveName);
+
+            cmd.add("-Xlog:cds");
+            cmd.add("-Xlog:cds+dynamic");
+            boolean mainModuleSpecified = false;
+            boolean patchModuleSpecified = false;
+            for (String s : opts.suffix) {
+                if (s.length() == 0) {
+                    continue;
+                }
+                if (s.equals("-m")) {
+                    mainModuleSpecified = true;
+                }
+                if (s.startsWith("--patch-module=")) {
+                    patchModuleSpecified = true;
+                }
+                cmd.add(s);
+            }
+
+            if (opts.appJar != null) {
+                // classlist is supported only when we have a Jar file to patch (to insert
+                // cdsutils.DynamicDumpHelper)
+                if (opts.classList == null) {
+                    throw new RuntimeException("test.dynamic.dump requires classList file");
+                }
+
+                if (!mainModuleSpecified && !patchModuleSpecified) {
+                    cmd.add("cdsutils.DynamicDumpHelper");
+                    File classListFile = makeClassList(opts.classList);
+                    cmd.add(classListFile.getPath());
+                }
+            } else {
+                if (!mainModuleSpecified && !patchModuleSpecified) {
+                    // If you have an empty classpath, you cannot specify a classlist!
+                    if (opts.classList != null && opts.classList.length > 0) {
+                        throw new RuntimeException("test.dynamic.dump not supported empty classpath with non-empty classlist");
+                    }
+                    cmd.add("-version");
+                }
+            }
+        } else {
+            // static dump
+            cmd.add("-Xshare:dump");
+            cmd.add("-XX:SharedArchiveFile=" + opts.archiveName);
+
+            if (opts.classList != null) {
+                File classListFile = makeClassList(opts.classList);
+                cmd.add("-XX:ExtraSharedClassListFile=" + classListFile.getPath());
+            }
+            for (String s : opts.suffix) {
+                cmd.add(s);
+            }
+        }
 
         String[] cmdLine = cmd.toArray(new String[cmd.size()]);
         ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(true, cmdLine);
@@ -154,6 +234,93 @@
     // Some AppCDS tests are not compatible with this mode. See the group
     // hotspot_appcds_with_jfr in ../../TEST.ROOT for details.
     private static final boolean RUN_WITH_JFR = Boolean.getBoolean("test.cds.run.with.jfr");
+    // This method simulates -Xshare:dump with -XX:ArchiveClassesAtExit. This way, we
+    // can re-use many tests (outside of the ./dynamicArchive directory) for testing
+    // general features of JDK-8215311 (JEP 350: Dynamic CDS Archives).
+    //
+    // We insert the cdsutils/DynamicDumpHelper.class into the first Jar file in
+    // the classpath. We use this class to load all the classes specified in the classlist.
+    //
+    // There's no need to change the run-time command-line: in this special mode, two
+    // archives are involved. The command-line specifies only the top archive. However,
+    // the location of the base archive is recorded in the top archive, so it can be
+    // determined by the JVM at runtime start-up.
+    //
+    // To run in this special mode, specify the following in your jtreg command-line
+    //    -Dtest.dynamic.cds.archive=true
+    //
+    // Note that some tests are not compatible with this special mode, including
+    //    + Tests in ./dynamicArchive: these tests are specifically written for
+    //      dynamic archive, and do not use TestCommon.createArchive(), which works
+    //      together with patchJarForDynamicDump().
+    //    + Tests related to cached objects and shared strings: dynamic dumping
+    //      does not support these.
+    //    + Custom loader tests: DynamicDumpHelper doesn't support the required
+    //      classlist syntax. (FIXME).
+    //    + Extra symbols and extra strings.
+    // See the hotspot_appcds_dynamic in ../../TEST.ROOT for details.
+    //
+    // To run all tests that are compatible with this mode:
+    //    cd test/hotspot/jtreg
+    //    jtreg -Dtest.dynamic.cds.archive=true :hotspot_appcds_dynamic
+    //
+    private static void patchJarForDynamicDump(String cp) throws Exception {
+        System.out.println("patchJarForDynamicDump: classpath = " + cp);
+        String firstJar = cp;
+        int n = firstJar.indexOf(File.pathSeparator);
+        if (n > 0) {
+            firstJar = firstJar.substring(0, n);
+        }
+        String classDir = System.getProperty("test.classes");
+        String expected1 = classDir + File.separator;
+        String expected2 = System.getProperty("user.dir") + File.separator;
+
+        if (!firstJar.startsWith(expected1) && !firstJar.startsWith(expected2)) {
+            throw new RuntimeException("FIXME: jar file not at a supported location ('"
+                                       + expected1 + "', or '" + expected2 + "'): " + firstJar);
+        }
+
+        String replaceJar = firstJar + ".tmp";
+        String patchClass = "cdsutils/DynamicDumpHelper.class";
+        ZipFile zipFile = new ZipFile(firstJar);
+        byte[] buf = new byte[1024];
+        int len;
+        if (zipFile.getEntry(patchClass) == null) {
+            FileOutputStream fout = new FileOutputStream(replaceJar);
+            final ZipOutputStream zos = new ZipOutputStream(fout);
+
+            zos.putNextEntry(new ZipEntry(patchClass));
+            InputStream is = new FileInputStream(classDir + File.separator + patchClass);
+            while ((len = (is.read(buf))) > 0) {
+                zos.write(buf, 0, len);
+            }
+            zos.closeEntry();
+            is.close();
+
+            for (Enumeration e = zipFile.entries(); e.hasMoreElements(); ) {
+                ZipEntry entryIn = (ZipEntry) e.nextElement();
+                zos.putNextEntry(entryIn);
+                is = zipFile.getInputStream(entryIn);
+                while ((len = is.read(buf)) > 0) {
+                    zos.write(buf, 0, len);
+                }
+                zos.closeEntry();
+                is.close();
+            }
+
+            zos.close();
+            fout.close();
+            zipFile.close();
+
+            File oldFile = new File(firstJar);
+            File newFile = new File(replaceJar);
+            oldFile.delete();
+            newFile.renameTo(oldFile);
+            System.out.println("firstJar = " + firstJar + " Modified");
+        } else {
+            System.out.println("firstJar = " + firstJar);
+        }
+    }
 
     // Execute JVM using AppCDS archive with specified AppCDSOptions
     public static OutputAnalyzer runWithArchive(AppCDSOptions opts)
@@ -260,12 +427,18 @@
         return runWithArchive(opts);
     }
 
-
     // A common operation: dump, then check results
     public static OutputAnalyzer testDump(String appJar, String classList[],
                                           String... suffix) throws Exception {
         OutputAnalyzer output = dump(appJar, classList, suffix);
-        output.shouldContain("Loading classes to share");
+        if (DYNAMIC_DUMP) {
+            if (isUnableToMap(output)) {
+                throw new SkippedException(UnableToMapMsg);
+            }
+            output.shouldContain("Written dynamic archive");
+        } else {
+            output.shouldContain("Loading classes to share");
+        }
         output.shouldHaveExitValue(0);
         return output;
     }
@@ -301,7 +474,6 @@
         return output;
     }
 
-
     // Convenience concatenation utils
     public static String[] list(String ...args) {
         return args;
@@ -336,6 +508,15 @@
         return list.toArray(new String[list.size()]);
     }
 
+    public static String[] concat(String prefix, String[] extra) {
+        ArrayList<String> list = new ArrayList<String>();
+        list.add(prefix);
+        for (String s : extra) {
+            list.add(s);
+        }
+
+        return list.toArray(new String[list.size()]);
+    }
 
     // ===================== Concatenate paths
     public static String concatPaths(String... paths) {
@@ -384,4 +565,29 @@
         }
         return true;
     }
+
+    static Pattern pattern;
+
+    static void findAllClasses(ArrayList<String> list) throws Throwable {
+        // Find all the classes in the jrt file system
+        pattern = Pattern.compile("/modules/[a-z.]*[a-z]+/([^-]*)[.]class");
+        FileSystem fs = FileSystems.getFileSystem(URI.create("jrt:/"));
+        Path base = fs.getPath("/modules/");
+        findAllClassesAtPath(base, list);
+    }
+
+    private static void findAllClassesAtPath(Path p, ArrayList<String> list) throws Throwable {
+        try (DirectoryStream<Path> stream = Files.newDirectoryStream(p)) {
+            for (Path entry: stream) {
+                Matcher matcher = pattern.matcher(entry.toString());
+                if (matcher.find()) {
+                    String className = matcher.group(1);
+                    list.add(className);
+                }
+                try {
+                    findAllClassesAtPath(entry, list);
+                } catch (Throwable t) {}
+            }
+        }
+    }
 }
--- a/test/hotspot/jtreg/runtime/appcds/TraceLongClasspath.java	Fri May 17 10:48:02 2019 -0400
+++ b/test/hotspot/jtreg/runtime/appcds/TraceLongClasspath.java	Fri May 17 08:29:55 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2019, 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
@@ -31,6 +31,7 @@
  *          java.management
  *          jdk.jartool/sun.tools.jar
  * @compile test-classes/Hello.java
+ * @compile test-classes/Super.java
  * @run driver TraceLongClasspath
  */
 
@@ -43,8 +44,10 @@
 
     public static void main(String[] args) throws Exception {
         String appJar = JarBuilder.getOrCreateHelloJar();
+        String dummyJar = JarBuilder.build("dummy", "Super");
 
         String longClassPath =
+            dummyJar + ps +
             "/scratch/xxxx/yyyy/ZZZZZZ/aaaaaaaaaa/xx/abc/abc/modules/user-patch.jar" + ps +
             "/scratch/xxxx/yyyy/ZZZZZZ/aaaaaaaaaa/xx/abc/abc/modules/abc-startup.jar" + ps +
             "/scratch/xxxx/yyyy/ZZZZZZ/aaaaaaaaaa/xx/foobar_common/modules/features/com.foobar.db.jdbc7-dms.jar" + ps +
@@ -91,15 +94,15 @@
         // Then try to execute the archive with a different classpath and with -XX:+TraceClassPaths.
         // The diagnosis "expecting" app classpath trace should show the entire classpath.
         TestCommon.run(
-            "-XX:+TraceClassPaths",
+            "-XX:+TraceClassPaths", "-Xlog:cds",
             "-cp", appJar,
             "Hello")
-          .assertAbnormalExit(output -> {
-              output.shouldContain("Unable to use shared archive");
-              output.shouldContain("shared class paths mismatch");
-              // the "expecting" app classpath from -XX:+TraceClassPaths should not
-              // be truncated
-              output.shouldContain(myCP);
-            });
+            .assertAbnormalExit(output -> {
+                output.shouldContain("Unable to use shared archive");
+                output.shouldContain("shared class paths mismatch");
+                // the "expecting" app classpath from -XX:+TraceClassPaths should not
+                // be truncated
+                output.shouldContain(myCP);
+              });
     }
 }
--- a/test/hotspot/jtreg/runtime/appcds/WrongClasspath.java	Fri May 17 10:48:02 2019 -0400
+++ b/test/hotspot/jtreg/runtime/appcds/WrongClasspath.java	Fri May 17 08:29:55 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2019, 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
@@ -47,8 +47,9 @@
     // Then try to execute the archive without -classpath -- it should fail
     TestCommon.run(
         /* "-cp", appJar, */ // <- uncomment this and the execution should succeed
+        "-Xlog:cds",
         "Hello")
-      .assertAbnormalExit("Unable to use shared archive",
-                          "shared class paths mismatch");
+        .assertAbnormalExit("Unable to use shared archive",
+                            "shared class paths mismatch");
   }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/appcds/cdsutils/DynamicDumpHelper.java	Fri May 17 08:29:55 2019 -0700
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2019, 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 cdsutils;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileReader;
+
+/**
+ * This class is used to simulate -Xshare:dump with -XX:ArchiveClassesAtExit.
+ * It loads all classes specified in a classlist file. See patchJarForDynamicDump()
+ * in ../TestCommon.java for details.
+ */
+public class DynamicDumpHelper {
+    public static void main(String args[]) throws Throwable {
+        File file = new File(args[0]);
+
+        System.out.println("Loading classes to share...");
+        try (BufferedReader br = new BufferedReader(new FileReader(file))) {
+            String line;
+            while ((line = br.readLine()) != null) {
+                //System.out.println("Loading class: " + line);
+                line = line.replace('/', '.');
+                try {
+                    Class.forName(line);
+                } catch (java.lang.ClassNotFoundException ex) {
+                    try {
+                        Class.forName(line, true, null);
+                    } catch (java.lang.ClassNotFoundException cnfe) {
+                        System.out.println("Preload Warning: Cannot find " + line.replace('.', '/'));
+                    }
+                } catch (Throwable t) {
+                    System.out.println("Error: failed to load \"" + line + "\": " + t);
+                }
+            }
+        }
+        System.out.println("Loading classes to share: done.");
+    }
+}
--- a/test/hotspot/jtreg/runtime/appcds/customLoader/ClassListFormatA.java	Fri May 17 10:48:02 2019 -0400
+++ b/test/hotspot/jtreg/runtime/appcds/customLoader/ClassListFormatA.java	Fri May 17 08:29:55 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2019, 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,7 +32,7 @@
  * @modules java.base/jdk.internal.misc
  *          java.management
  *          jdk.jartool/sun.tools.jar
- * @compile test-classes/Hello.java test-classes/CustomLoadee.java test-classes/CustomLoadee2.java
+ * @compile ../test-classes/Hello.java test-classes/CustomLoadee.java test-classes/CustomLoadee2.java
  *          test-classes/CustomInterface2_ia.java test-classes/CustomInterface2_ib.java
  * @run driver ClassListFormatA
  */
@@ -133,4 +133,3 @@
             "input line too long (must be no longer than " + _max_allowed_line + " chars");
     }
 }
-
--- a/test/hotspot/jtreg/runtime/appcds/customLoader/ClassListFormatB.java	Fri May 17 10:48:02 2019 -0400
+++ b/test/hotspot/jtreg/runtime/appcds/customLoader/ClassListFormatB.java	Fri May 17 08:29:55 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2019, 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,7 +32,7 @@
  * @modules java.base/jdk.internal.misc
  *          java.management
  *          jdk.jartool/sun.tools.jar
- * @compile test-classes/Hello.java test-classes/CustomLoadee.java test-classes/CustomLoadee2.java
+ * @compile ../test-classes/Hello.java test-classes/CustomLoadee.java test-classes/CustomLoadee2.java
  *          test-classes/CustomInterface2_ia.java test-classes/CustomInterface2_ib.java
  * @run driver ClassListFormatB
  */
@@ -69,4 +69,3 @@
             "If source location is specified, id must be also specified");
     }
 }
-
--- a/test/hotspot/jtreg/runtime/appcds/customLoader/ClassListFormatBase.java	Fri May 17 10:48:02 2019 -0400
+++ b/test/hotspot/jtreg/runtime/appcds/customLoader/ClassListFormatBase.java	Fri May 17 08:29:55 2019 -0700
@@ -79,4 +79,3 @@
         return TestCommon.list(args);
     }
 }
-
--- a/test/hotspot/jtreg/runtime/appcds/customLoader/ClassListFormatC.java	Fri May 17 10:48:02 2019 -0400
+++ b/test/hotspot/jtreg/runtime/appcds/customLoader/ClassListFormatC.java	Fri May 17 08:29:55 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2019, 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,7 +32,7 @@
  * @modules java.base/jdk.internal.misc
  *          java.management
  *          jdk.jartool/sun.tools.jar
- * @compile test-classes/Hello.java test-classes/CustomLoadee.java test-classes/CustomLoadee2.java
+ * @compile ../test-classes/Hello.java test-classes/CustomLoadee.java test-classes/CustomLoadee2.java
  *          test-classes/CustomInterface2_ia.java test-classes/CustomInterface2_ib.java
  * @run driver ClassListFormatC
  */
@@ -71,4 +71,3 @@
             "If source location is not specified, interface(s) must not be specified");
     }
 }
-
--- a/test/hotspot/jtreg/runtime/appcds/customLoader/ClassListFormatD.java	Fri May 17 10:48:02 2019 -0400
+++ b/test/hotspot/jtreg/runtime/appcds/customLoader/ClassListFormatD.java	Fri May 17 08:29:55 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2019, 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,7 +32,7 @@
  * @modules java.base/jdk.internal.misc
  *          java.management
  *          jdk.jartool/sun.tools.jar
- * @compile test-classes/Hello.java test-classes/CustomLoadee.java test-classes/CustomLoadee2.java
+ * @compile ../test-classes/Hello.java test-classes/CustomLoadee.java test-classes/CustomLoadee2.java
  *          test-classes/CustomInterface2_ia.java test-classes/CustomInterface2_ib.java
  * @run driver ClassListFormatD
  */
@@ -80,4 +80,3 @@
             "Interface id 2 is not yet loaded");
     }
 }
-
--- a/test/hotspot/jtreg/runtime/appcds/customLoader/ClassListFormatE.java	Fri May 17 10:48:02 2019 -0400
+++ b/test/hotspot/jtreg/runtime/appcds/customLoader/ClassListFormatE.java	Fri May 17 08:29:55 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2019, 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,7 +32,7 @@
  * @modules java.base/jdk.internal.misc
  *          java.management
  *          jdk.jartool/sun.tools.jar
- * @compile test-classes/Hello.java test-classes/CustomLoadee.java test-classes/CustomLoadee2.java
+ * @compile ../test-classes/Hello.java test-classes/CustomLoadee.java test-classes/CustomLoadee2.java
  *          test-classes/CustomInterface2_ia.java test-classes/CustomInterface2_ib.java
  * @run driver ClassListFormatE
  */
@@ -106,4 +106,3 @@
             "The specified super class CustomLoadee (id 4) does not match actual super class java.lang.Object");
     }
 }
-
--- a/test/hotspot/jtreg/runtime/appcds/customLoader/HelloCustom.java	Fri May 17 10:48:02 2019 -0400
+++ b/test/hotspot/jtreg/runtime/appcds/customLoader/HelloCustom.java	Fri May 17 08:29:55 2019 -0700
@@ -27,10 +27,12 @@
  * @summary Hello World test for AppCDS custom loader support
  * @requires vm.cds
  * @requires vm.cds.custom.loaders
- * @library /test/lib /test/hotspot/jtreg/runtime/appcds
- * @compile test-classes/Hello.java test-classes/CustomLoadee.java
- * @build sun.hotspot.WhiteBox
- * @run driver ClassFileInstaller -jar hello.jar Hello
+ * @library /test/lib /test/hotspot/jtreg/runtime/appcds /runtime/testlibrary
+ * @modules java.base/jdk.internal.misc
+ *          java.management
+ * @compile test-classes/HelloUnload.java test-classes/CustomLoadee.java
+ * @build sun.hotspot.WhiteBox ClassUnloadCommon
+ * @run driver ClassFileInstaller -jar hello.jar HelloUnload ClassUnloadCommon ClassUnloadCommon$1 ClassUnloadCommon$TestFailure
  * @run driver ClassFileInstaller -jar hello_custom.jar CustomLoadee
  * @run driver ClassFileInstaller -jar WhiteBox.jar sun.hotspot.WhiteBox
  * @run driver HelloCustom
@@ -52,7 +54,7 @@
 
         // Dump the archive
         String classlist[] = new String[] {
-            "Hello",
+            "HelloUnload",
             "java/lang/Object id: 1",
             "CustomLoadee id: 2 super: 1 source: " + customJarPath
         };
@@ -68,8 +70,7 @@
                                      use_whitebox_jar,
                                      "-XX:+UnlockDiagnosticVMOptions",
                                      "-XX:+WhiteBoxAPI",
-                                     "Hello", customJarPath));
+                                     "HelloUnload", customJarPath, "true", "true"));
         TestCommon.checkExec(output);
     }
 }
-
--- a/test/hotspot/jtreg/runtime/appcds/customLoader/HelloCustom_JFR.java	Fri May 17 10:48:02 2019 -0400
+++ b/test/hotspot/jtreg/runtime/appcds/customLoader/HelloCustom_JFR.java	Fri May 17 08:29:55 2019 -0700
@@ -30,10 +30,10 @@
  * @requires vm.hasJFR
  * @requires vm.cds
  * @requires vm.cds.custom.loaders
- * @library /test/lib /test/hotspot/jtreg/runtime/appcds
- * @compile test-classes/Hello.java test-classes/CustomLoadee.java
- * @build sun.hotspot.WhiteBox
- * @run driver ClassFileInstaller -jar hello.jar Hello
+ * @library /test/lib /test/hotspot/jtreg/runtime/appcds /runtime/testlibrary
+ * @compile test-classes/HelloUnload.java test-classes/CustomLoadee.java
+ * @build sun.hotspot.WhiteBox ClassUnloadCommon
+ * @run driver ClassFileInstaller -jar hello.jar HelloUnload ClassUnloadCommon ClassUnloadCommon$1 ClassUnloadCommon$TestFailure
  * @run driver ClassFileInstaller -jar hello_custom.jar CustomLoadee
  * @run driver ClassFileInstaller -jar WhiteBox.jar sun.hotspot.WhiteBox
  * @run driver HelloCustom_JFR
@@ -47,4 +47,3 @@
         HelloCustom.run("-XX:StartFlightRecording=dumponexit=true", "-Xlog:cds+jvmti=debug");
     }
 }
-
--- a/test/hotspot/jtreg/runtime/appcds/customLoader/ProhibitedPackageNamesTest.java	Fri May 17 10:48:02 2019 -0400
+++ b/test/hotspot/jtreg/runtime/appcds/customLoader/ProhibitedPackageNamesTest.java	Fri May 17 08:29:55 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2019, 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
@@ -31,7 +31,7 @@
  * @modules java.base/jdk.internal.misc
  *          java.management
  *          jdk.jartool/sun.tools.jar
- * @compile ClassListFormatBase.java test-classes/Hello.java test-classes/InProhibitedPkg.java
+ * @compile ClassListFormatBase.java ../test-classes/Hello.java test-classes/InProhibitedPkg.java
  * @run driver ProhibitedPackageNamesTest
  */
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/appcds/customLoader/test-classes/HelloUnload.java	Fri May 17 08:29:55 2019 -0700
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+import java.io.File;
+import java.net.URL;
+import java.net.URLClassLoader;
+import sun.hotspot.WhiteBox;
+
+public class HelloUnload {
+    private static String className = "CustomLoadee";
+
+    public static void main(String args[]) throws Exception {
+        if (args.length != 3) {
+            throw new RuntimeException("Unexpected number of arguments: expected 3, actual " + args.length);
+        }
+
+        String path = args[0];
+        URL url = new File(path).toURI().toURL();
+        URL[] urls = new URL[] {url};
+        System.out.println(path);
+        System.out.println(url);
+
+        // unload the custom class loader
+        boolean doUnload = false;
+        if (args[1].equals("true")) {
+            doUnload = true;
+        } else if (args[1].equals("false")) {
+            doUnload = false;
+        } else {
+            throw new RuntimeException("args[1] can only be either \"true\" or \"false\", actual " + args[1]);
+        }
+
+        // should the CustomLoadee class be in the shared archive
+        boolean inArchive = false;
+        if (args[2].equals("true")) {
+            inArchive = true;
+        } else if (args[2].equals("false")) {
+            inArchive = false;
+        } else {
+            throw new RuntimeException("args[2] can only be either \"true\" or \"false\", actual " + args[1]);
+        }
+
+        URLClassLoader urlClassLoader =
+            new URLClassLoader("HelloClassLoader", urls, null);
+        Class c = Class.forName(className, true, urlClassLoader);
+        System.out.println(c);
+        System.out.println(c.getClassLoader());
+        Object o = c.newInstance();
+
+        // [1] Check that CustomLoadee is defined by the correct loader
+        if (c.getClassLoader() != urlClassLoader) {
+            throw new RuntimeException("c.getClassLoader() == " + c.getClassLoader() +
+                                       ", expected == " + urlClassLoader);
+        }
+
+        // [2] Check that CustomLoadee is loaded from shared archive.
+        WhiteBox wb = WhiteBox.getWhiteBox();
+        if(wb.isSharedClass(HelloUnload.class)) {
+            if (inArchive && !wb.isSharedClass(c)) {
+                throw new RuntimeException("wb.isSharedClass(c) should be true");
+            }
+        }
+
+        ClassUnloadCommon.failIf(!wb.isClassAlive(className), "should be live here");
+
+        if (doUnload) {
+            String loaderName = urlClassLoader.getName();
+            int loadedRefcount = wb.getSymbolRefcount(loaderName);
+            System.out.println("Refcount of symbol " + loaderName + " is " + loadedRefcount);
+
+            urlClassLoader = null; c = null; o = null;
+            ClassUnloadCommon.triggerUnloading();
+            System.out.println("Is CustomLoadee alive? " + wb.isClassAlive(className));
+            ClassUnloadCommon.failIf(wb.isClassAlive(className), "should have been unloaded");
+
+            int unloadedRefcount = wb.getSymbolRefcount(loaderName);
+            System.out.println("Refcount of symbol " + loaderName + " is " + unloadedRefcount);
+
+            // refcount of a permanent symbol will not be decremented
+            if (loadedRefcount != 65535) {
+                ClassUnloadCommon.failIf(unloadedRefcount != (loadedRefcount - 1), "Refcount must be decremented");
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/appcds/dynamicArchive/AppendClasspath.java	Fri May 17 08:29:55 2019 -0700
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2019, 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 At run time, it is OK to append new elements to the classpath that was used at dump time.
+ * @requires vm.cds
+ * @library /test/lib /test/hotspot/jtreg/runtime/appcds
+ * @modules java.base/jdk.internal.misc
+ *          java.management
+ *          jdk.jartool/sun.tools.jar
+ * @compile ../test-classes/Hello.java
+ * @compile ../test-classes/HelloMore.java
+ * @run driver AppendClasspath
+ */
+
+import java.io.File;
+
+public class AppendClasspath extends DynamicArchiveTestBase {
+
+    public static void main(String[] args) throws Exception {
+        runTest(AppendClasspath::testDefaultBase);
+    }
+
+    static void testDefaultBase() throws Exception {
+        String topArchiveName = getNewArchiveName("top");
+        doTest(topArchiveName);
+    }
+
+    private static void doTest(String topArchiveName) throws Exception {
+        String appJar = JarBuilder.getOrCreateHelloJar();
+        String appJar2 = JarBuilder.build("AppendClasspath_HelloMore", "HelloMore");
+
+        // Dump an archive with a specified JAR file in -classpath
+        dump(topArchiveName,
+             "-Xlog:cds",
+             "-Xlog:cds+dynamic=debug",
+             "-cp", appJar, "Hello")
+            .assertNormalExit(output -> {
+                    output.shouldContain("Buffer-space to target-space delta")
+                           .shouldContain("Written dynamic archive 0x");
+                });
+
+        // runtime with classpath containing the one used in dump time,
+        // i.e. the dump time classpath is a prefix of the runtime classpath.
+        run(topArchiveName,
+            "-Xlog:class+load",
+            "-Xlog:cds+dynamic=debug,cds=debug",
+            "-cp", appJar + File.pathSeparator + appJar2,
+            "HelloMore")
+            .assertNormalExit(output -> {
+                    output.shouldContain("Hello source: shared objects file")
+                          .shouldContain("Hello World ... More")
+                          .shouldHaveExitValue(0);
+                });
+
+        // reverse the order of the 2 jar files so that the dump time classpath
+        // is no longer a prefix of the runtime classpath. The Hello class
+        // should be loaded from the jar file.
+        run(topArchiveName,
+            "-Xlog:class+load",
+            "-Xlog:cds+dynamic=debug,cds=debug",
+            "-cp", appJar2 + File.pathSeparator + appJar,
+            "HelloMore")
+            .assertAbnormalExit(output -> {
+                    output.shouldContain("shared class paths mismatch")
+                          .shouldHaveExitValue(1);
+                });
+
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/appcds/dynamicArchive/ArchiveConsistency.java	Fri May 17 08:29:55 2019 -0700
@@ -0,0 +1,167 @@
+/*
+ * Copyright (c) 2019, 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 Corrupt the header CRC fields of the top archive. VM should exit with an error.
+ * @requires vm.cds
+ * @library /test/lib /test/hotspot/jtreg/runtime/appcds /test/hotspot/jtreg/runtime/appcds/test-classes
+ * @build Hello sun.hotspot.WhiteBox
+ * @run driver ClassFileInstaller -jar hello.jar Hello
+ * @run driver ClassFileInstaller sun.hotspot.WhiteBox
+ * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI ArchiveConsistency
+ */
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.channels.FileChannel;
+import java.nio.file.StandardOpenOption;
+import static java.nio.file.StandardOpenOption.READ;
+import static java.nio.file.StandardOpenOption.WRITE;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import sun.hotspot.WhiteBox;
+
+public class ArchiveConsistency extends DynamicArchiveTestBase {
+    public static WhiteBox wb;
+    public static int int_size;        // size of int
+    public static String[] shared_region_name = {"MiscCode", "ReadWrite", "ReadOnly", "MiscData"};
+    public static int num_regions = shared_region_name.length;
+
+    public static void main(String[] args) throws Exception {
+        runTest(ArchiveConsistency::testCustomBase);
+    }
+
+    // Test with custom base archive + top archive
+    static void testCustomBase() throws Exception {
+        String topArchiveName = getNewArchiveName("top2");
+        String baseArchiveName = getNewArchiveName("base");
+        dumpBaseArchive(baseArchiveName);
+        doTest(baseArchiveName, topArchiveName);
+    }
+
+    public static void setReadWritePermission(File file) throws Exception {
+        if (!file.canRead()) {
+            if (!file.setReadable(true)) {
+                throw new IOException("Cannot modify file " + file + " as readable");
+            }
+        }
+        if (!file.canWrite()) {
+            if (!file.setWritable(true)) {
+                throw new IOException("Cannot modify file " + file + " as writable");
+            }
+        }
+    }
+
+    public static long readInt(FileChannel fc, long offset, int nbytes) throws Exception {
+        ByteBuffer bb = ByteBuffer.allocate(nbytes);
+        bb.order(ByteOrder.nativeOrder());
+        fc.position(offset);
+        fc.read(bb);
+        return  (nbytes > 4 ? bb.getLong(0) : bb.getInt(0));
+    }
+
+    public static long align_up_page(long l) throws Exception {
+        // wb is obtained in getFileOffsetInfo() which is called first in main() else we should call
+        // WhiteBox.getWhiteBox() here first.
+        int pageSize = wb.getVMPageSize();
+        return (l + pageSize -1) & (~ (pageSize - 1));
+    }
+
+    public static void writeData(FileChannel fc, long offset, ByteBuffer bb) throws Exception {
+        fc.position(offset);
+        fc.write(bb);
+        fc.force(true);
+    }
+
+    public static FileChannel getFileChannel(File jsa) throws Exception {
+        List<StandardOpenOption> arry = new ArrayList<StandardOpenOption>();
+        arry.add(READ);
+        arry.add(WRITE);
+        return FileChannel.open(jsa.toPath(), new HashSet<StandardOpenOption>(arry));
+    }
+
+   public static void modifyJsaHeaderCRC(File jsa) throws Exception {
+        FileChannel fc = getFileChannel(jsa);
+        int_size = wb.getOffsetForName("int_size");
+        System.out.println("    int_size " + int_size);
+        ByteBuffer bbuf = ByteBuffer.allocateDirect(int_size);
+        for (int i = 0; i < int_size; i++) {
+            bbuf.put((byte)0);
+        }
+
+        int baseArchiveCRCOffset = wb.getOffsetForName("DynamicArchiveHeader::_base_archive_crc");
+        int crc = 0;
+        System.out.printf("%-12s%-12s\n", "Space name", "CRC");
+        for (int i = 0; i < 4; i++) {
+            baseArchiveCRCOffset += int_size * i;
+            System.out.println("    baseArchiveCRCOffset " + baseArchiveCRCOffset);
+            crc = (int)readInt(fc, baseArchiveCRCOffset, int_size );
+            System.out.printf("%-11s%-12d\n", shared_region_name[i], crc);
+            bbuf.rewind();
+            writeData(fc, baseArchiveCRCOffset, bbuf);
+        }
+        fc.force(true);
+        if (fc.isOpen()) {
+            fc.close();
+        }
+    }
+
+    private static void doTest(String baseArchiveName, String topArchiveName) throws Exception {
+        String appJar = ClassFileInstaller.getJarPath("hello.jar");
+        String mainClass = "Hello";
+        dump2(baseArchiveName, topArchiveName,
+             "-Xlog:cds",
+             "-Xlog:cds+dynamic=debug",
+             "-cp", appJar, mainClass)
+            .assertNormalExit(output -> {
+                    output.shouldContain("Buffer-space to target-space delta")
+                          .shouldContain("Written dynamic archive 0x");
+                });
+
+        File jsa = new File(topArchiveName);
+        if (!jsa.exists()) {
+            throw new IOException(jsa + " does not exist!");
+        }
+
+        // Modify the CRC values in the header of the top archive.
+        wb = WhiteBox.getWhiteBox();
+        setReadWritePermission(jsa);
+        modifyJsaHeaderCRC(jsa);
+
+        run2(baseArchiveName, topArchiveName,
+            "-Xlog:class+load",
+            "-Xlog:cds+dynamic=debug,cds=debug",
+            "-XX:+VerifySharedSpaces",
+            "-cp", appJar, mainClass)
+            .assertAbnormalExit(output -> {
+                    output.shouldContain("Header checksum verification failed")
+                          .shouldContain("Unable to use shared archive")
+                          .shouldHaveExitValue(1);
+                });
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/appcds/dynamicArchive/ArrayKlasses.java	Fri May 17 08:29:55 2019 -0700
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2019, 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 handling of the existence of InstanceKlass::array_klasses()
+ * @requires vm.cds
+ * @library /test/lib /test/hotspot/jtreg/runtime/appcds
+ *          /test/hotspot/jtreg/runtime/appcds/dynamicArchive/test-classes
+ * @build ArrayKlassesApp
+ * @run driver ClassFileInstaller -jar ArrayKlasses.jar
+ *             ArrayKlassesApp
+ * @run driver ArrayKlasses
+ */
+
+public class ArrayKlasses extends DynamicArchiveTestBase {
+    public static void main(String[] args) throws Exception {
+        runTest(ArrayKlasses::test);
+    }
+
+    static void test() throws Exception {
+        String topArchiveName = getNewArchiveName();
+        String appJar = ClassFileInstaller.getJarPath("ArrayKlasses.jar");
+        String mainClass = "ArrayKlassesApp";
+
+        dumpAndRun(topArchiveName, "-Xlog:cds+dynamic=debug", "-cp", appJar, mainClass);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/appcds/dynamicArchive/ClassResolutionFailure.java	Fri May 17 08:29:55 2019 -0700
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+/*
+ * @test
+ * @summary Test with a jar file which contains only the main class but not the dependent class.
+ *          The main class should be archived. During run time, the main class
+ *          should be loaded from the archive.
+ * @requires vm.cds
+ * @library /test/lib /test/hotspot/jtreg/runtime/appcds /test/hotspot/jtreg/runtime/appcds/dynamicArchive/test-classes
+ * @build StrConcatApp
+ * @build MissingDependent
+ * @run driver ClassFileInstaller -jar missingDependent.jar MissingDependent
+ * @run driver ClassResolutionFailure
+ */
+
+public class ClassResolutionFailure extends DynamicArchiveTestBase {
+
+    public static void main(String[] args) throws Exception {
+        runTest(ClassResolutionFailure::testDefaultBase);
+    }
+
+    // Test with default base archive + top archive
+    static void testDefaultBase() throws Exception {
+        String topArchiveName = getNewArchiveName("top");
+        doTest(topArchiveName);
+    }
+
+    private static void doTest(String topArchiveName) throws Exception {
+        String appJar = ClassFileInstaller.getJarPath("missingDependent.jar");
+        String mainClass = "MissingDependent";
+
+        dump(topArchiveName,
+             "-Xlog:cds",
+             "-Xlog:cds+dynamic=debug",
+             "-Xlog:class+load=trace",
+             "-cp", appJar, mainClass)
+            .assertNormalExit(output -> {
+                    output.shouldContain("Buffer-space to target-space delta")
+                           .shouldContain("Written dynamic archive 0x");
+                });
+
+        run(topArchiveName,
+            "-Xlog:class+load",
+            "-Xlog:cds+dynamic=debug,cds=debug",
+            "-cp", appJar, mainClass)
+            .assertNormalExit(output -> {
+                    output.shouldContain("MissingDependent source: shared objects file")
+                          .shouldHaveExitValue(0);
+                });
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/appcds/dynamicArchive/DynamicArchiveTestBase.java	Fri May 17 08:29:55 2019 -0700
@@ -0,0 +1,246 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+import java.io.File;
+import jdk.test.lib.process.OutputAnalyzer;
+import jdk.test.lib.process.ProcessTools;
+import jdk.test.lib.cds.CDSOptions;
+import jdk.test.lib.cds.CDSTestUtils;
+import jdk.test.lib.cds.CDSTestUtils.Result;
+
+/**
+ * Base class for test cases in test/hotspot/jtreg/runtime/appcds/dynamicArchive/
+ */
+class DynamicArchiveTestBase {
+    private static boolean executedIn_run = false;
+
+    public static interface DynamicArchiveTest {
+        public void run() throws Exception;
+    }
+
+    public static interface DynamicArchiveTestWithArgs {
+        public void run(String args[]) throws Exception;
+    }
+
+
+    /*
+     * Tests for dynamic archives should be written using this pattern:
+     *
+     * public class HelloDynamic extends DynamicArchiveTestBase {
+     *     public static void main(String[] args) throws Exception {
+     *        runTest(HelloDynamic::testDefaultBase); // launch one test case
+     *     }
+     *
+     *     // the body of a test case
+     *     static void testDefaultBase() throws Exception {
+     *         String topArchiveName = getNewArchiveName("top");
+     *         doTest(null, topArchiveName);
+     *     }
+     * }
+     *
+     * The reason for this is so that we can clean up the archive files
+     * created by prior test cases. Otherwise tests with lots of
+     * test cases may fill up the scratch directory.
+     */
+    public static void runTest(DynamicArchiveTest t) throws Exception {
+        executedIn_run = true;
+        try {
+            TestCommon.deletePriorArchives();
+            t.run();
+        } finally {
+            executedIn_run = false;
+        }
+    }
+
+    public static void runTest(DynamicArchiveTestWithArgs t, String... args) throws Exception {
+        executedIn_run = true;
+        try {
+            TestCommon.deletePriorArchives();
+            t.run(args);
+        } finally {
+            executedIn_run = false;
+        }
+    }
+
+    public static String getNewArchiveName() {
+        return TestCommon.getNewArchiveName();
+    }
+    public static String getNewArchiveName(String stem) {
+        return TestCommon.getNewArchiveName(stem);
+    }
+
+    /**
+     * Execute a JVM using the base archive (given by baseArchiveName) with the command line
+     * (given by cmdLineSuffix). At JVM exit, dump all eligible classes into the top archive
+     * (give by topArchiveName).
+     *
+     * If baseArchiveName is null, use the JDK's default archive as the base archive.
+     */
+    public static Result dump2(String baseArchiveName, String topArchiveName, String ... cmdLineSuffix)
+        throws Exception
+    {
+        String[] cmdLine = TestCommon.concat(
+            "-XX:ArchiveClassesAtExit=" + topArchiveName);
+        // to allow dynamic archive tests to be run in the "rt-non-cds-mode"
+        cmdLine = TestCommon.concat(cmdLine, "-Xshare:auto");
+        if (baseArchiveName != null) {
+            cmdLine = TestCommon.concat(cmdLine, "-XX:SharedArchiveFile=" + baseArchiveName);
+        }
+        cmdLine = TestCommon.concat(cmdLine, cmdLineSuffix);
+        return execProcess("dump", cmdLine);
+    }
+
+    public static Result dump2_WB(String baseArchiveName, String topArchiveName, String ... cmdLineSuffix)
+        throws Exception
+    {
+        return dump2(baseArchiveName, topArchiveName,
+                     TestCommon.concat(wbRuntimeArgs(), cmdLineSuffix));
+    }
+
+    /**
+     * A convenience method similar to dump2, but always use the JDK's default archive
+     * as the base archive.
+     *
+     * Most dynamicArchive/*.java test cases should be using this method instead of run2.
+     */
+    public static Result dump(String topArchiveName, String ... cmdLineSuffix)
+        throws Exception
+    {
+        return dump2(null, topArchiveName, cmdLineSuffix);
+    }
+
+    /**
+     * Dump the base archive. The JDK's default class list is used (unless otherwise specified
+     * in cmdLineSuffix).
+     */
+    public static void dumpBaseArchive(String baseArchiveName, String ... cmdLineSuffix)
+        throws Exception
+    {
+        CDSOptions opts = new CDSOptions();
+        opts.setArchiveName(baseArchiveName);
+        opts.addSuffix(cmdLineSuffix);
+        opts.addSuffix("-Djava.class.path=");
+        OutputAnalyzer out = CDSTestUtils.createArchive(opts);
+        CDSTestUtils.checkDump(out);
+    }
+
+    /**
+     * Same as dumpBaseArchive, but also add WhiteBox to the bootcp
+     */
+    public static void dumpBaseArchive_WB(String baseArchiveName, String ... cmdLineSuffix)
+        throws Exception
+    {
+        dumpBaseArchive(baseArchiveName,
+                        TestCommon.concat("-Xbootclasspath/a:" + getWhiteBoxJar(), cmdLineSuffix));
+    }
+
+    private static String getWhiteBoxJar() {
+        String wbJar = ClassFileInstaller.getJarPath("WhiteBox.jar");
+        if (!(new File(wbJar)).exists()) {
+            throw new RuntimeException("Test error: your test must have " +
+                                       "'@run driver ClassFileInstaller -jar WhiteBox.jar sun.hotspot.WhiteBox'");
+        }
+        return wbJar;
+    }
+
+    private static String[] wbRuntimeArgs() {
+        return TestCommon.concat("-Xbootclasspath/a:" + getWhiteBoxJar(),
+                                 "-XX:+UnlockDiagnosticVMOptions",
+                                 "-XX:+WhiteBoxAPI");
+    }
+
+    /**
+     * Execute a JVM using the base archive (given by baseArchiveName) and the top archive
+     * (give by topArchiveName), using the command line (given by cmdLineSuffix).
+     *
+     * If baseArchiveName is null, use the JDK's default archive as the base archive.
+     */
+    public static Result run2(String baseArchiveName, String topArchiveName, String ... cmdLineSuffix)
+        throws Exception {
+        if (baseArchiveName == null && topArchiveName == null) {
+            throw new RuntimeException("Both baseArchiveName and topArchiveName cannot be null at the same time.");
+        }
+        String archiveFiles = (baseArchiveName == null) ? topArchiveName :
+            (topArchiveName == null) ? baseArchiveName :
+            baseArchiveName + File.pathSeparator + topArchiveName;
+        String[] cmdLine = TestCommon.concat(
+            "-Xshare:on",
+            "-XX:SharedArchiveFile=" + archiveFiles);
+        cmdLine = TestCommon.concat(cmdLine, cmdLineSuffix);
+        return execProcess("exec", cmdLine);
+    }
+
+    public static Result run2_WB(String baseArchiveName, String topArchiveName, String ... cmdLineSuffix)
+        throws Exception
+    {
+        return run2(baseArchiveName, topArchiveName,
+                    TestCommon.concat(wbRuntimeArgs(), cmdLineSuffix));
+    }
+
+    /**
+     * A convenience method similar to run2, but always use the JDK's default archive
+     * as the base archive.
+     *
+     * Most dynamicArchive/*.java test cases should be using this method instead of run2.
+     */
+    public static Result run(String topArchiveName, String ... cmdLineSuffix)
+        throws Exception
+    {
+        return run2(null, topArchiveName, cmdLineSuffix);
+    }
+
+    private static String getXshareMode(String[] cmdLine) {
+        for (int i = 0; i <= cmdLine.length - 1; i++) {
+            int j = cmdLine[i].indexOf("-Xshare:");
+            if (j != -1) {
+                return (cmdLine[i].substring(j));
+            }
+        }
+        return null;
+   }
+
+
+    private static Result execProcess(String mode, String[] cmdLine) throws Exception {
+        if (!executedIn_run) {
+            throw new Exception("Test error: dynamic archive tests must be executed via DynamicArchiveTestBase.run()");
+        }
+        ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(true, cmdLine);
+        OutputAnalyzer output = TestCommon.executeAndLog(pb, mode);
+        CDSOptions opts = new CDSOptions();
+        String xShareMode = getXshareMode(cmdLine);
+        if (xShareMode != null) {
+            opts.setXShareMode(xShareMode);
+        }
+        return new Result(opts, output);
+    }
+
+    /**
+     * A convenience method for dumping and running, using the default CDS archive from the
+     * JDK. Both dumping and running should exit normally.
+     */
+    public static void dumpAndRun(String topArchiveName, String ... cmdLineSuffix) throws Exception {
+        dump(topArchiveName, cmdLineSuffix).assertNormalExit();
+        run(topArchiveName,  cmdLineSuffix).assertNormalExit();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/appcds/dynamicArchive/DynamicFlag.java	Fri May 17 08:29:55 2019 -0700
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2019, 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 The DynamicDumpShareSpaces flag is internal, setting it at the command line should have no effect.
+ * @requires vm.cds
+ * @library /test/lib /test/hotspot/jtreg/runtime/appcds
+ * @modules java.base/jdk.internal.misc
+ *          jdk.jartool/sun.tools.jar
+ * @compile ../test-classes/Hello.java
+ * @run driver DynamicFlag
+ */
+
+public class DynamicFlag {
+  public static void main(String[] args) throws Exception {
+      TestCommon.test(JarBuilder.getOrCreateHelloJar(),
+          TestCommon.list("Hello"), "-XX:+DynamicDumpSharedSpaces", "Hello");
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/appcds/dynamicArchive/DynamicLotsOfClasses.java	Fri May 17 08:29:55 2019 -0700
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+import java.io.File;
+import java.nio.charset.Charset;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.List;
+import java.util.ArrayList;
+
+/*
+ * @test
+ * @summary Try to archive lots of classes by searching for classes from the jrt:/ file system. With JDK 12
+ *          this will produce an archive with over 30,000 classes.
+ * @requires vm.cds
+ * @library /test/lib /test/hotspot/jtreg/runtime/appcds /test/hotspot/jtreg/runtime/appcds/dynamicArchive/test-classes
+ * @build LoadClasses
+ * @build sun.hotspot.WhiteBox
+ * @modules jdk.jartool/sun.tools.jar
+ * @run driver ClassFileInstaller -jar loadclasses.jar LoadClasses
+ * @run driver ClassFileInstaller -jar whitebox.jar sun.hotspot.WhiteBox
+ * @run driver/timeout=500 DynamicLotsOfClasses
+ */
+
+public class DynamicLotsOfClasses extends DynamicArchiveTestBase {
+
+    public static void main(String[] args) throws Throwable {
+        runTest(DynamicLotsOfClasses::testDefaultBase);
+    }
+
+    static void testDefaultBase() throws Exception {
+        String topArchiveName = getNewArchiveName("top");
+        try {
+            doTest(topArchiveName);
+         } catch (Throwable th) {
+             System.out.println(th.toString());
+             Exception ex = new Exception(th);
+             throw ex;
+         }
+    }
+
+    private static void doTest(String topArchiveName) throws Throwable {
+        ArrayList<String> list = new ArrayList<>();
+        TestCommon.findAllClasses(list);
+
+        String classList = System.getProperty("user.dir") + File.separator +
+                           "LotsOfClasses.list";
+        List<String> lines = list;
+        Path file = Paths.get(classList);
+        Files.write(file, lines, Charset.forName("UTF-8"));
+
+        String appJar = ClassFileInstaller.getJarPath("loadclasses.jar");
+        String mainClass = "LoadClasses";
+
+        String whiteBoxJar = ClassFileInstaller.getJarPath("whitebox.jar");
+        String bootClassPath = "-Xbootclasspath/a:" + whiteBoxJar;
+        dump(topArchiveName,
+             "--add-modules",
+             "ALL-SYSTEM",
+             "-Xlog:hashtables",
+             "-Xmx500m",
+             "-Xlog:cds,cds+dynamic",
+             bootClassPath,
+             "-XX:+UnlockDiagnosticVMOptions", "-XX:+WhiteBoxAPI",
+             "-cp", appJar, mainClass, classList)
+             .assertNormalExit(output -> {
+                 output.shouldContain("Buffer-space to target-space delta")
+                        .shouldContain("Written dynamic archive 0x");
+             });
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/appcds/dynamicArchive/ExcludedClasses.java	Fri May 17 08:29:55 2019 -0700
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2019, 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 Unreferenced app classes during dump time should not be included in the archive.
+ * @requires vm.cds
+ * @library /test/lib /test/hotspot/jtreg/runtime/appcds
+ *          /test/hotspot/jtreg/runtime/appcds/dynamicArchive/test-classes
+ * @build ExcludedClassesApp
+ * @run driver ClassFileInstaller -jar ExcludedClasses.jar
+ *             ExcludedClassesApp
+ *             ExcludedClassesApp$NotLinkedSuper
+ *             ExcludedClassesApp$NotLinkedChild
+ *             ExcludedClassesApp$NotLinkedInterface
+ * @run driver ExcludedClasses
+ */
+
+public class ExcludedClasses extends DynamicArchiveTestBase {
+    public static void main(String[] args) throws Exception {
+        runTest(ExcludedClasses::test);
+    }
+
+    static void test() throws Exception {
+        String topArchiveName = getNewArchiveName();
+        String appJar = ClassFileInstaller.getJarPath("ExcludedClasses.jar");
+        String mainClass = "ExcludedClassesApp";
+
+        dumpAndRun(topArchiveName, "-Xlog:cds+dynamic=debug", "-cp", appJar, mainClass);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/appcds/dynamicArchive/HelloDynamic.java	Fri May 17 08:29:55 2019 -0700
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2019, 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 Hello World test for dynamic archive
+ * @requires vm.cds
+ * @library /test/lib /test/hotspot/jtreg/runtime/appcds /test/hotspot/jtreg/runtime/appcds/test-classes
+ * @build Hello
+ * @run driver ClassFileInstaller -jar hello.jar Hello
+ * @run driver HelloDynamic
+ */
+
+public class HelloDynamic extends DynamicArchiveTestBase {
+    public static void main(String[] args) throws Exception {
+        runTest(HelloDynamic::testDefaultBase);
+        runTest(HelloDynamic::testCustomBase);
+    }
+
+    // (1) Test with default base archive + top archive
+    static void testDefaultBase() throws Exception {
+        String topArchiveName = getNewArchiveName("top");
+        doTest(null, topArchiveName);
+    }
+
+    // (2) Test with custom base archive + top archive
+    static void testCustomBase() throws Exception {
+        String topArchiveName = getNewArchiveName("top2");
+        String baseArchiveName = getNewArchiveName("base");
+        dumpBaseArchive(baseArchiveName);
+        doTest(baseArchiveName, topArchiveName);
+    }
+
+    private static void doTest(String baseArchiveName, String topArchiveName) throws Exception {
+        String appJar = ClassFileInstaller.getJarPath("hello.jar");
+        String mainClass = "Hello";
+        dump2(baseArchiveName, topArchiveName,
+             "-Xlog:cds",
+             "-Xlog:cds+dynamic=debug",
+             "-cp", appJar, mainClass)
+            .assertNormalExit(output -> {
+                    output.shouldContain("Buffer-space to target-space delta")
+                           .shouldContain("Written dynamic archive 0x");
+                });
+        run2(baseArchiveName, topArchiveName,
+            "-Xlog:class+load",
+            "-Xlog:cds+dynamic=debug,cds=debug",
+            "-cp", appJar, mainClass)
+            .assertNormalExit(output -> {
+                    output.shouldContain("Hello source: shared objects file")
+                          .shouldHaveExitValue(0);
+                });
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/appcds/dynamicArchive/HelloDynamicCustom.java	Fri May 17 08:29:55 2019 -0700
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2019, 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 Hello World test for dynamic archive with custom loader
+ * @requires vm.cds
+ * @library /test/lib /test/hotspot/jtreg/runtime/appcds /test/hotspot/jtreg/runtime/appcds/customLoader/test-classes /runtime/testlibrary
+ * @build HelloUnload CustomLoadee ClassUnloadCommon
+ * @build sun.hotspot.WhiteBox
+ * @run driver ClassFileInstaller -jar hello.jar HelloUnload ClassUnloadCommon ClassUnloadCommon$1 ClassUnloadCommon$TestFailure
+ * @run driver ClassFileInstaller -jar hello_custom.jar CustomLoadee
+ * @run driver ClassFileInstaller -jar WhiteBox.jar sun.hotspot.WhiteBox
+ * @run driver HelloDynamicCustom
+ */
+
+import java.io.File;
+import jdk.test.lib.process.OutputAnalyzer;
+import jdk.test.lib.process.ProcessTools;
+
+public class HelloDynamicCustom {
+    private static final String ARCHIVE_NAME =
+        System.getProperty("test.classes") + File.separator + "HelloDynamicCustom.jsa";
+
+    public static void main(String[] args) throws Exception {
+        String wbJar = ClassFileInstaller.getJarPath("WhiteBox.jar");
+        String use_whitebox_jar = "-Xbootclasspath/a:" + wbJar;
+        String appJar = ClassFileInstaller.getJarPath("hello.jar");
+        String customJarPath = ClassFileInstaller.getJarPath("hello_custom.jar");
+        String mainAppClass = "HelloUnload";
+
+        ProcessBuilder dumpPb = ProcessTools.createJavaProcessBuilder(true,
+            use_whitebox_jar,
+            "-XX:+UnlockDiagnosticVMOptions",
+            "-XX:+WhiteBoxAPI",
+            "-Xlog:cds",
+            "-Xlog:cds+dynamic=debug",
+            "-Xshare:auto",
+            "-XX:ArchiveClassesAtExit=" + ARCHIVE_NAME,
+            "-cp", appJar,
+            mainAppClass, customJarPath, "false", "false");
+        TestCommon.executeAndLog(dumpPb, "dump")
+            .shouldContain("Buffer-space to target-space delta")
+            .shouldContain("Written dynamic archive 0x")
+            .shouldNotContain("klasses.*=.*CustomLoadee")   // Fixme -- use a better way to decide if a class has been archived
+            .shouldHaveExitValue(0);
+
+        ProcessBuilder execPb = ProcessTools.createJavaProcessBuilder(true,
+            use_whitebox_jar,
+            "-XX:+UnlockDiagnosticVMOptions",
+            "-XX:+WhiteBoxAPI",
+            "-Xlog:class+load",
+            "-Xlog:cds=debug",
+            "-Xlog:cds+dynamic=info",
+            "-Xshare:auto",
+            "-XX:SharedArchiveFile=" + ARCHIVE_NAME,
+            "-cp", appJar,
+            mainAppClass, customJarPath, "false", "true");
+        TestCommon.executeAndLog(execPb, "exec")
+            .shouldContain("HelloUnload source: shared objects file")
+            .shouldContain("CustomLoadee source: shared objects file")
+            .shouldHaveExitValue(0);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/appcds/dynamicArchive/HelloDynamicCustomUnload.java	Fri May 17 08:29:55 2019 -0700
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2019, 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 Hello World test for dynamic archive with custom loader.
+ *          Attempt will be made to unload the custom loader during
+ *          dump time and run time. The custom loader will be unloaded
+ *          during dump time.
+ * @requires vm.cds
+ * @library /test/lib /test/hotspot/jtreg/runtime/appcds /test/hotspot/jtreg/runtime/appcds/customLoader/test-classes /runtime/testlibrary
+ * @build HelloUnload CustomLoadee ClassUnloadCommon
+ * @build sun.hotspot.WhiteBox
+ * @run driver ClassFileInstaller -jar hello.jar HelloUnload ClassUnloadCommon ClassUnloadCommon$1 ClassUnloadCommon$TestFailure
+ * @run driver ClassFileInstaller -jar hello_custom.jar CustomLoadee
+ * @run driver ClassFileInstaller -jar WhiteBox.jar sun.hotspot.WhiteBox
+ * @run driver HelloDynamicCustomUnload
+ */
+
+import java.io.File;
+
+public class HelloDynamicCustomUnload extends DynamicArchiveTestBase {
+    private static final String ARCHIVE_NAME =
+        System.getProperty("test.classes") + File.separator + "HelloDynamicCustomUnload.jsa";
+
+    public static void main(String[] args) throws Exception {
+        runTest(HelloDynamicCustomUnload::testDefaultBase);
+    }
+
+    static void testDefaultBase() throws Exception {
+        String topArchiveName = getNewArchiveName("HelloDynamicCustomUnload-top");
+        doTest(topArchiveName);
+    }
+
+    private static void doTest(String topArchiveName) throws Exception {
+        String wbJar = ClassFileInstaller.getJarPath("WhiteBox.jar");
+        String use_whitebox_jar = "-Xbootclasspath/a:" + wbJar;
+        String appJar = ClassFileInstaller.getJarPath("hello.jar");
+        String customJarPath = ClassFileInstaller.getJarPath("hello_custom.jar");
+        String mainAppClass = "HelloUnload";
+
+        dump(topArchiveName,
+            use_whitebox_jar,
+            "-XX:+UnlockDiagnosticVMOptions",
+            "-XX:+WhiteBoxAPI",
+            "-Xmn8m",
+            "-Xlog:cds,cds+dynamic=debug,class+unload=debug",
+            "-XX:ArchiveClassesAtExit=" + ARCHIVE_NAME,
+            "-cp", appJar,
+            mainAppClass, customJarPath, "true", "false")
+            .assertNormalExit(output -> {
+                output.shouldContain("Buffer-space to target-space delta")
+                      .shouldContain("Written dynamic archive 0x")
+                      .shouldNotContain("klasses.*=.*CustomLoadee")   // Fixme -- use a better way to decide if a class has been archived
+                      .shouldHaveExitValue(0);
+                });
+
+        run(topArchiveName,
+            use_whitebox_jar,
+            "-XX:+UnlockDiagnosticVMOptions",
+            "-XX:+WhiteBoxAPI",
+            "-Xlog:class+load,cds=debug,class+unload=debug",
+            "-XX:SharedArchiveFile=" + ARCHIVE_NAME,
+            "-cp", appJar,
+            mainAppClass, customJarPath, "true", "false")
+            .assertNormalExit(output -> {
+                output.shouldContain("HelloUnload source: shared objects file")
+                      .shouldMatch(".class.load. CustomLoadee source:.*hello_custom.jar")
+                      .shouldHaveExitValue(0);
+                });
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/appcds/dynamicArchive/JITInteraction.java	Fri May 17 08:29:55 2019 -0700
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+/*
+ * @test
+ * @summary Test interaction with JIT threads during vm exit.
+ * @requires vm.cds
+ * @library /test/lib /test/hotspot/jtreg/runtime/appcds /test/hotspot/jtreg/runtime/appcds/dynamicArchive/test-classes
+ * @build TestJIT
+ * @modules jdk.jartool/sun.tools.jar
+ * @build sun.hotspot.WhiteBox
+ * @run driver ClassFileInstaller -jar WhiteBox.jar sun.hotspot.WhiteBox
+ * @run driver ClassFileInstaller -jar testjit.jar TestJIT
+ * @run driver JITInteraction
+ */
+
+public class JITInteraction extends DynamicArchiveTestBase {
+
+    public static void main(String[] args) throws Exception {
+        runTest(JITInteraction::testDefaultBase);
+    }
+
+    // Test with default base archive + top archive
+    static void testDefaultBase() throws Exception {
+        String topArchiveName = getNewArchiveName("top");
+        doTest(topArchiveName);
+    }
+
+    private static void doTest(String topArchiveName) throws Exception {
+        String appJar = ClassFileInstaller.getJarPath("testjit.jar");
+        String mainClass = "TestJIT";
+
+        dump2_WB(null, topArchiveName,
+                 "-Xlog:cds",
+                 "-Xlog:cds+dynamic",
+                 "-XX:-UseOnStackReplacement",
+                 "-XX:+PrintCompilation",
+                 "-cp", appJar, mainClass)
+                .assertNormalExit(output -> {
+                    output.shouldContain("Buffer-space to target-space delta")
+                           .shouldContain("Written dynamic archive 0x");
+                });
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/appcds/dynamicArchive/MainModuleOnly.java	Fri May 17 08:29:55 2019 -0700
@@ -0,0 +1,259 @@
+/*
+ * Copyright (c) 2019, 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/lib /test/hotspot/jtreg/runtime/appcds
+ * @modules jdk.compiler
+ *          jdk.jartool/sun.tools.jar
+ *          jdk.jlink
+ * @run driver 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 java.util.Arrays;
+
+import jdk.test.lib.process.OutputAnalyzer;
+import jdk.test.lib.Platform;
+
+public class MainModuleOnly extends DynamicArchiveTestBase {
+
+    private static final Path USER_DIR = Paths.get(System.getProperty("user.dir"));
+
+    private static final String FS = File.separator;
+    private static final String TEST_SRC = System.getProperty("test.src") +
+        FS + ".." + FS + "jigsaw" + FS + "modulepath";
+
+    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);
+
+    }
+
+    static void testDefaultBase() throws Exception {
+        String topArchiveName = getNewArchiveName("top");
+        doTest(topArchiveName);
+    }
+
+    public static void main(String... args) throws Exception {
+        runTest(MainModuleOnly::testDefaultBase);
+    }
+
+    public static void doTest(String topArchiveName) throws Exception {
+        // compile the modules and create the modular jar files
+        buildTestModule();
+        // 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.
+        dump2(null, topArchiveName,
+              "-Xlog:cds+dynamic=debug,cds=debug",
+              "-cp", destJar.toString(),
+              "--module-path", moduleDir.toString(),
+              "-m", TEST_MODULE1)
+              .assertNormalExit(output -> {
+                      output.shouldContain("Buffer-space to target-space delta")
+                            .shouldContain("Written dynamic archive 0x");
+                  });
+
+        // run with the archive using the same command line as in dump time.
+        // The main class should be loaded from the archive.
+        run2(null, topArchiveName,
+             "-Xlog:cds+dynamic=debug,cds=debug,class+load=trace",
+             "-cp", destJar.toString(),
+             "--module-path", moduleDir.toString(),
+             "-m", TEST_MODULE1)
+            .assertNormalExit(output -> {
+                    output.shouldContain("[class,load] com.simple.Main source: shared objects file")
+                          .shouldHaveExitValue(0);
+                });
+
+        // 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.
+        run2(null, topArchiveName,
+             "-Xlog:cds+dynamic=debug,cds=debug,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.
+        run2(null, topArchiveName,
+             "-Xlog:cds+dynamic=debug,cds=debug,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.
+        run2(null, topArchiveName,
+             "-Xlog:cds+dynamic=debug,cds=debug,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.
+        run2(null, topArchiveName,
+             "-Xlog:cds+dynamic=debug,cds=debug,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.
+        run2(null, topArchiveName,
+             "-Xlog:cds+dynamic=debug,cds=debug,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.
+        run2(null, topArchiveName,
+             "-Xlog:cds+dynamic=debug,cds=debug,class+load=trace",
+             "-cp", destJar.toString(),
+             "--module-path", moduleDir.toString(),
+             "-m", TEST_MODULE1)
+            .assertAbnormalExit(
+                "A jar file is not the one used while building the shared archive file:");
+        // create an archive with a non-empty directory in the --module-path.
+        // The dumping process will exit with an error due to non-empty directory
+        // in the --module-path.
+        dump2(null, topArchiveName,
+              "-Xlog:cds+dynamic=debug,cds=debug",
+              "-cp", destJar.toString(),
+              "--module-path", MODS_DIR.toString(),
+              "-m", TEST_MODULE1 + "/" + MAIN_CLASS)
+            .assertAbnormalExit(output -> {
+                output.shouldMatch("Error: non-empty directory.*com.simple");
+                });
+
+        // test module path with very long length
+        //
+        // This test can't be run on the windows platform due to an existing
+        // issue in ClassLoader::get_canonical_path() (JDK-8190737).
+        if (Platform.isWindows()) {
+            System.out.println("Long module path test cannot be tested on the Windows platform.");
+            return;
+        }
+        Path longDir = USER_DIR;
+        int pathLen = longDir.toString().length();
+        int PATH_LEN = 2034;
+        int MAX_DIR_LEN = 250;
+        while (pathLen < PATH_LEN) {
+            int remaining = PATH_LEN - pathLen;
+            int subPathLen = remaining > MAX_DIR_LEN ? MAX_DIR_LEN : remaining;
+            char[] chars = new char[subPathLen];
+            Arrays.fill(chars, 'x');
+            String subPath = new String(chars);
+            longDir = Paths.get(longDir.toString(), subPath);
+            pathLen = longDir.toString().length();
+        }
+        File longDirFile = new File(longDir.toString());
+        try {
+            longDirFile.mkdirs();
+        } catch (Exception e) {
+            throw e;
+        }
+        Path longDirJar = longDir.resolve(TEST_MODULE1 + ".jar");
+        // IOException results from the Files.copy() call on platform
+        // such as MacOS X. Test can't be proceeded further with the
+        // exception.
+        try {
+            Files.copy(destJar, longDirJar);
+        } catch (java.io.IOException ioe) {
+            System.out.println("Caught IOException from Files.copy(). Cannot continue.");
+            return;
+        }
+        dump2(null, topArchiveName,
+              "-Xlog:cds+dynamic=debug,cds=debug",
+              "-cp", destJar.toString(),
+              "-Xlog:exceptions=trace",
+              "--module-path", longDirJar.toString(),
+              "-m", TEST_MODULE1)
+            .ifAbnormalExit(output -> {
+                output.shouldMatch("os::stat error.*CDS dump aborted");
+                });
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/appcds/dynamicArchive/MethodSorting.java	Fri May 17 08:29:55 2019 -0700
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2019, 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 When HelloA and HelloB are copied into the dynamic archive, the Symbols
+ *          for their method's names will have a different sorting order. This requires
+ *          that the dumped InstanceKlass to re-sort their "methods" array and re-layout the vtables/itables.
+ *          A regression test for an earlier bug in DynamicArchiveBuilder::relocate_buffer_to_target().
+ * @requires vm.cds
+ * @library /test/lib /test/hotspot/jtreg/runtime/appcds /test/hotspot/jtreg/runtime/appcds/test-classes
+ *          /test/hotspot/jtreg/runtime/appcds/dynamicArchive/test-classes
+ * @build MethodSortingApp
+ * @run driver ClassFileInstaller -jar method_sorting.jar
+ *             MethodSortingApp
+ *             MethodSortingApp$HelloA
+ *             MethodSortingApp$HelloA1
+ *             MethodSortingApp$HelloB
+ *             MethodSortingApp$HelloB1
+ *             MethodSortingApp$InterfaceA
+ *             MethodSortingApp$InterfaceB
+ *             MethodSortingApp$ImplementorA
+ *             MethodSortingApp$ImplementorA1
+ *             MethodSortingApp$ImplementorB
+ *             MethodSortingApp$ImplementorB1
+ * @run driver MethodSorting
+ */
+
+public class MethodSorting extends DynamicArchiveTestBase {
+    public static void main(String[] args) throws Exception {
+        runTest(MethodSorting::test);
+    }
+
+    static void test() throws Exception {
+        String topArchiveName = getNewArchiveName();
+        String appJar = ClassFileInstaller.getJarPath("method_sorting.jar");
+        String mainClass = "MethodSortingApp";
+
+        dumpAndRun(topArchiveName, "-Xlog:cds+dynamic=debug", "-cp", appJar, mainClass);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/appcds/dynamicArchive/MissingArchive.java	Fri May 17 08:29:55 2019 -0700
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+import java.io.File;
+
+/*
+ * @test
+ * @summary error handling when either (or both) of the base/top archives are missing.
+ * @requires vm.cds
+ * @library /test/lib /test/hotspot/jtreg/runtime/appcds /test/hotspot/jtreg/runtime/appcds/test-classes
+ * @build GenericTestApp sun.hotspot.WhiteBox
+ * @run driver ClassFileInstaller -jar WhiteBox.jar sun.hotspot.WhiteBox
+ * @run driver ClassFileInstaller -jar GenericTestApp.jar GenericTestApp
+ * @run driver MissingArchive
+ */
+
+public class MissingArchive extends DynamicArchiveTestBase {
+    private static final String TOP  = "top";
+    private static final String BASE = "base";
+    private static final String BOTH = "base/top";
+    private static final String NONE = "none";
+
+    public static void main(String[] args) throws Exception {
+        runTest(MissingArchive::test, TOP);
+        runTest(MissingArchive::test, BASE);
+        runTest(MissingArchive::test, BOTH);
+        runTest(MissingArchive::test, NONE);
+    }
+
+    static void delete(String fileName) {
+        File f = new File(fileName);
+        f.delete();
+    }
+
+    static void test(String args[]) throws Exception {
+        String topArchiveName = getNewArchiveName("top");
+        String baseArchiveName = getNewArchiveName("base");
+        dumpBaseArchive(baseArchiveName);
+
+        String appJar = ClassFileInstaller.getJarPath("GenericTestApp.jar");
+        String mainClass = "GenericTestApp";
+        dump2_WB(baseArchiveName, topArchiveName,
+                 "-Xlog:cds",
+                 "-Xlog:cds+dynamic=debug",
+                 "-cp", appJar, mainClass)
+            .assertNormalExit(output -> {
+                    output.shouldContain("Buffer-space to target-space delta")
+                           .shouldContain("Written dynamic archive 0x");
+                });
+
+        // Use -Xshare:auto so top archive can fail after base archive has succeeded,
+        // but the app will continue to run.
+        String[] cmdline = TestCommon.concat(
+            "-Xlog:cds*",
+            "-Xshare:auto",
+            "-cp", appJar, mainClass);
+
+
+        String mode = args[0];
+
+        if (mode.contains(BASE)) {
+            delete(baseArchiveName);
+            cmdline = TestCommon.concat(cmdline, "assertNotShared:java.lang.Object");
+        } else {
+            cmdline = TestCommon.concat(cmdline, "assertShared:java.lang.Object");
+        }
+
+        if (mode.contains(TOP)) {
+            delete(topArchiveName);
+        }
+
+        if (mode.equals(NONE)) {
+            cmdline = TestCommon.concat(cmdline, "assertShared:GenericTestApp");
+        } else {
+            cmdline = TestCommon.concat(cmdline, "assertNotShared:GenericTestApp");
+        }
+
+        run2_WB(baseArchiveName, topArchiveName, cmdline).assertNormalExit();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/appcds/dynamicArchive/NoClassToArchive.java	Fri May 17 08:29:55 2019 -0700
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 2019, 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 A few edge cases where there's no class to be included in the dynamic archive.
+ * @requires vm.cds
+ * @library /test/lib /test/hotspot/jtreg/runtime/appcds /test/hotspot/jtreg/runtime/appcds/dynamicArchive/test-classes
+ * @build StrConcatApp
+ * @run driver ClassFileInstaller -jar strConcatApp.jar StrConcatApp
+ * @run driver NoClassToArchive
+ */
+
+import java.io.File;
+import jdk.test.lib.process.OutputAnalyzer;
+import jdk.test.lib.process.ProcessTools;
+
+public class NoClassToArchive extends DynamicArchiveTestBase {
+    static final String warningMessage =
+        "There is no class to be included in the dynamic archive";
+    static final String classList = System.getProperty("test.classes") +
+        File.separator + "NoClassToArchive.list";
+    static final String appClass = "StrConcatApp";
+
+    public static void main(String[] args) throws Exception {
+        runTest(NoClassToArchive::testDefaultBase);
+        runTest(NoClassToArchive::testCustomBase);
+    }
+
+    // (1) Test with default base archive + top archive
+    static void testDefaultBase() throws Exception {
+        String topArchiveName = getNewArchiveName("top");
+        doTest(null, topArchiveName);
+    }
+
+    // (2) Test with custom base archive + top archive
+    static void testCustomBase() throws Exception {
+        String topArchiveName = getNewArchiveName("top2");
+        String baseArchiveName = getNewArchiveName("base");
+        doTestCustomBase(baseArchiveName, topArchiveName);
+    }
+
+    private static void doTest(String baseArchiveName, String topArchiveName) throws Exception {
+        dump2(baseArchiveName, topArchiveName,
+             "-Xlog:cds",
+             "-Xlog:cds+dynamic=debug",
+             "-Xlog:class+load=trace",
+             "-version")
+            .assertNormalExit(output -> {
+                    if (output.getStdout().contains("jrt:/")) {
+                        System.out.println("test skipped: this platform uses non-archived classes when running -version");
+                    } else {
+                        output.shouldContain(warningMessage);
+                    }
+                });
+
+        dump2(baseArchiveName, topArchiveName,
+             "-Xlog:cds",
+             "-Xlog:cds+dynamic=debug",
+             "-Xlog:class+load=trace",
+             "-help")
+            .assertNormalExit(output -> {
+                    // some classes will be loaded from the java.base module
+                    output.shouldContain("java.text.MessageFormat source: jrt:/java.base");
+                });
+    }
+
+    private static void doTestCustomBase(String baseArchiveName, String topArchiveName) throws Exception {
+        String appJar = ClassFileInstaller.getJarPath("strConcatApp.jar");
+        // dump class list by running the StrConcatApp
+        ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(
+            true,
+            "-XX:DumpLoadedClassList=" + classList,
+            "-cp",
+            appJar,
+            appClass);
+        OutputAnalyzer output = TestCommon.executeAndLog(pb, "dumpClassList");
+        TestCommon.checkExecReturn(output, 0, true, "length = 0");
+
+        // create a custom base archive based on the class list
+        dumpBaseArchive(baseArchiveName, "-XX:SharedClassListFile=" + classList);
+
+        // create a dynamic archive with the custom base archive
+        // no class should be included in the dynamic archive
+        dump2(baseArchiveName, topArchiveName, "-version")
+            .assertNormalExit(out -> {
+                    out.shouldMatch(warningMessage);
+                });
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/appcds/dynamicArchive/SharedArchiveFileOption.java	Fri May 17 08:29:55 2019 -0700
@@ -0,0 +1,150 @@
+/*
+ * Copyright (c) 2019, 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 Some negative tests for the SharedArchiveFile option
+ * @requires vm.cds
+ * @library /test/lib /test/hotspot/jtreg/runtime/appcds /test/hotspot/jtreg/runtime/appcds/test-classes
+ * @build Hello
+ * @run driver ClassFileInstaller -jar hello.jar Hello
+ * @run driver SharedArchiveFileOption
+ */
+
+import java.io.File;
+
+public class SharedArchiveFileOption extends DynamicArchiveTestBase {
+    public static void main(String[] args) throws Exception {
+        runTest(SharedArchiveFileOption::testCustomBase);
+    }
+
+    static String baseArchiveName2;
+    static void testCustomBase() throws Exception {
+        String topArchiveName = getNewArchiveName("top");
+        String baseArchiveName = getNewArchiveName("base");
+        baseArchiveName2 = getNewArchiveName("base2");
+        dumpBaseArchive(baseArchiveName);
+        dumpBaseArchive(baseArchiveName2);
+        doTest(baseArchiveName, topArchiveName);
+    }
+
+    private static void doTest(String baseArchiveName, String topArchiveName) throws Exception {
+        String appJar = ClassFileInstaller.getJarPath("hello.jar");
+        String mainClass = "Hello";
+        String dummyArchiveName = getNewArchiveName("dummy");
+
+        // -Xshare:dump specified with -XX:ArchiveClassesAtExit
+        dump2(dummyArchiveName, dummyArchiveName,
+            "-Xlog:cds",
+            "-Xlog:cds+dynamic=debug",
+            "-Xshare:dump",
+            "-cp", appJar, mainClass)
+            .assertAbnormalExit(output -> {
+                    output.shouldContain("-XX:ArchiveClassesAtExit cannot be used with -Xshare:dump");
+                });
+
+        // more than 1 archive file specified in -XX:SharedArchiveFile during
+        // dynamic dumpgin
+        String dummyArchives = dummyArchiveName + File.pathSeparator + dummyArchiveName;
+        dump2(dummyArchives, dummyArchiveName,
+            "-Xlog:cds",
+            "-Xlog:cds+dynamic=debug",
+            "-cp", appJar, mainClass)
+            .assertAbnormalExit(output -> {
+                    output.shouldContain("Cannot have more than 1 archive file specified in -XX:SharedArchiveFile during CDS dumping");
+                });
+
+        // normal dynamic archive dumping
+        dump2(baseArchiveName, topArchiveName,
+            "-Xlog:cds",
+            "-Xlog:cds+dynamic=debug",
+            "-cp", appJar, mainClass)
+            .assertNormalExit(output -> {
+                    output.shouldContain("Buffer-space to target-space delta")
+                           .shouldContain("Written dynamic archive 0x");
+                });
+
+        // same archive file specified for -XX:SharedArchiveFile and -XX:ArchiveClassesAtExit
+        dump2(baseArchiveName, baseArchiveName,
+            "-Xlog:cds",
+            "-Xlog:cds+dynamic=debug",
+            "-cp", appJar, mainClass)
+            .assertAbnormalExit(output -> {
+                    output.shouldContain("Cannot have the same archive file specified for -XX:SharedArchiveFile and -XX:ArchiveClassesAtExit: "
+                        + baseArchiveName);
+                });
+
+
+        // a top archive specified in the base archive position
+        run2(topArchiveName, baseArchiveName,
+            "-Xlog:class+load",
+            "-Xlog:cds+dynamic=debug,cds=debug",
+            "-cp", appJar, mainClass)
+            .assertAbnormalExit(output -> {
+                    output.shouldMatch("Not a base shared archive:.*top.*.jsa");
+                });
+
+        // a base archive specified in the top archive position
+        run2(baseArchiveName, baseArchiveName2,
+            "-Xlog:class+load",
+            "-Xlog:cds+dynamic=debug,cds=debug",
+            "-cp", appJar, mainClass)
+            .assertAbnormalExit(output -> {
+                    output.shouldMatch("Not a top shared archive:.*base.*.jsa");
+                });
+
+        // more than 2 archives specified in the -XX:ShareArchiveFile option
+        String baseArchives = baseArchiveName + File.pathSeparator + baseArchiveName2;
+        run2(baseArchives, topArchiveName,
+            "-Xlog:class+load",
+            "-Xlog:cds+dynamic=debug,cds=debug",
+            "-cp", appJar, mainClass)
+            .assertAbnormalExit(output -> {
+                    output.shouldContain(
+                        "Cannot have more than 2 archive files specified in the -XX:SharedArchiveFile option");
+                });
+
+        // base archive not specified
+        final String topArchive = File.pathSeparator + topArchiveName;
+        run2(topArchive, null,
+            "-Xlog:class+load",
+            "-Xlog:cds+dynamic=debug,cds=debug",
+            "-cp", appJar, mainClass)
+            .assertAbnormalExit(output -> {
+                    output.shouldContain(
+                        "Base archive was not specified: " + topArchive);
+                });
+
+        // top archive not specified
+        final String baseArchive = baseArchiveName + File.pathSeparator;
+        run2(baseArchive, null,
+            "-Xlog:class+load",
+            "-Xlog:cds+dynamic=debug,cds=debug",
+            "-cp", appJar, mainClass)
+            .assertAbnormalExit(output -> {
+                    output.shouldContain(
+                        "Top archive was not specified: " + baseArchive);
+                });
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/appcds/dynamicArchive/UnsupportedBaseArchive.java	Fri May 17 08:29:55 2019 -0700
@@ -0,0 +1,125 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+import java.io.File;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+
+/*
+ * @test
+ * @summary unsupported base archive tests
+ * @requires vm.cds
+ * @library /test/lib /test/hotspot/jtreg/runtime/appcds /test/hotspot/jtreg/runtime/appcds/test-classes
+ * @modules jdk.jartool/sun.tools.jar
+ * @compile ../test-classes/Hello.java
+ * @build sun.hotspot.WhiteBox
+ * @run driver ClassFileInstaller -jar WhiteBox.jar sun.hotspot.WhiteBox
+ * @run driver UnsupportedBaseArchive
+ */
+
+public class UnsupportedBaseArchive extends DynamicArchiveTestBase {
+    private static final Path USER_DIR = Paths.get(System.getProperty("user.dir"));
+
+    private static final String FS = File.separator;
+    private static final String TEST_SRC = System.getProperty("test.src") +
+        FS + ".." + FS + "jigsaw" + FS + "modulepath";
+
+    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_MODULE = "com.simple";
+
+    // the module main class
+    private static final String MAIN_CLASS = "com.simple.Main";
+
+    private static Path moduleDir = null;
+    private static Path srcJar = null;
+
+    private static final String warningBCP =
+        "Dynamic archiving is disabled because base layer archive has appended boot classpath";
+
+    private static final String warningModulePath =
+        "Dynamic archiving is disabled because base layer archive has module path";
+
+    public static void buildTestModule() throws Exception {
+
+        // javac -d mods/$TESTMODULE --module-path MOD_DIR src/$TESTMODULE/**
+        JarBuilder.compileModule(SRC_DIR.resolve(TEST_MODULE),
+                                 MODS_DIR.resolve(TEST_MODULE),
+                                 MODS_DIR.toString());
+
+
+        moduleDir = Files.createTempDirectory(USER_DIR, "mlib");
+        srcJar = moduleDir.resolve(TEST_MODULE + ".jar");
+        String classes = MODS_DIR.resolve(TEST_MODULE).toString();
+        JarBuilder.createModularJar(srcJar.toString(), classes, MAIN_CLASS);
+    }
+
+    public static void main(String[] args) throws Exception {
+        runTest(UnsupportedBaseArchive::test);
+    }
+
+    static void test(String args[]) throws Exception {
+        String topArchiveName = getNewArchiveName("top");
+        String baseArchiveName = getNewArchiveName("base");
+
+        // create a base archive with -Xbootclasspath/a:whitebox.jar
+        dumpBaseArchive_WB(baseArchiveName);
+
+        String appJar    = JarBuilder.getOrCreateHelloJar();
+        String mainClass = "Hello";
+
+        // dumping of dynamic archive should be disabled with a warning message
+        // if the base archive contains -Xbootclasspath/a entries.
+        dump2_WB(baseArchiveName, topArchiveName,
+             "-Xlog:cds*",
+             "-Xlog:cds+dynamic=debug",
+             "-Xlog:class+path=info",
+             "-cp", appJar, mainClass)
+            .assertNormalExit(warningBCP);
+
+        // create a base archive with the --module-path option
+        buildTestModule();
+        baseArchiveName = getNewArchiveName("base-with-module");
+        dumpBaseArchive(baseArchiveName,
+                        "-cp", srcJar.toString(),
+                        "--module-path", moduleDir.toString(),
+                        "-m", TEST_MODULE);
+
+        // dumping of dynamic archive should be disabled with a warning message
+        // if the base archive contains --module-path entries.
+        topArchiveName = getNewArchiveName("top-with-module");
+        dump2(baseArchiveName, topArchiveName,
+              "-Xlog:cds*",
+              "-Xlog:cds+dynamic=debug",
+              "-Xlog:class+path=info",
+              "-cp", srcJar.toString(),
+              "--module-path", moduleDir.toString(),
+              "-m", TEST_MODULE)
+            .assertNormalExit(warningModulePath);
+
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/appcds/dynamicArchive/UnusedCPDuringDump.java	Fri May 17 08:29:55 2019 -0700
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2019, 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 non-empty dir in -cp should be fine during dump time if only classes
+ *          from the system modules are being loaded even though some are
+ *          defined to the PlatformClassLoader and AppClassLoader.
+ * @requires vm.cds
+ * @library /test/lib /test/hotspot/jtreg/runtime/appcds
+ * @modules jdk.jartool/sun.tools.jar
+ * @compile ../test-classes/Hello.java
+ * @run main/othervm -Dtest.cds.copy.child.stdout=false UnusedCPDuringDump
+ */
+
+import java.io.File;
+
+public class UnusedCPDuringDump extends DynamicArchiveTestBase {
+
+    public static void main(String[] args) throws Exception {
+        runTest(UnusedCPDuringDump::testDefaultBase);
+    }
+
+    static void testDefaultBase() throws Exception {
+        String topArchiveName = getNewArchiveName("top");
+        doTest(topArchiveName);
+    }
+
+    private static void doTest(String topArchiveName) throws Exception {
+        File dir = new File(System.getProperty("user.dir"));
+        File emptydir = new File(dir, "emptydir");
+        emptydir.mkdir();
+        String appJar = JarBuilder.getOrCreateHelloJar();
+        String bootClassPath = "-Xbootclasspath/a:" + appJar;
+
+        // Dumping with a non-empty directory in the -cp.
+        // It should be fine because the app class won't be loaded from the
+        // -cp, it is being loaded from the bootclasspath.
+        dump(topArchiveName,
+             "-Xlog:cds",
+             "-Xlog:cds+dynamic=debug",
+             bootClassPath,
+             "-cp", dir.getPath(),
+             "Hello")
+            .assertNormalExit(output -> {
+                 output.shouldContain("Buffer-space to target-space delta")
+                        .shouldContain("Written dynamic archive 0x");
+                });
+
+        // Running with -cp different from dumping. It should be fine because
+        // the runtime classpath won't be checked against unused classpath
+        // during dump time.
+        run(topArchiveName,
+            "-Xlog:class+load",
+            "-Xlog:cds+dynamic=debug,cds=debug",
+             bootClassPath,
+            "-cp", appJar, "Hello")
+            .assertNormalExit(output -> {
+                    output.shouldContain("Hello World")
+                          .shouldHaveExitValue(0);
+                });
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/appcds/dynamicArchive/WrongTopClasspath.java	Fri May 17 08:29:55 2019 -0700
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+import java.io.File;
+
+/*
+ * @test
+ * @summary correct classpath for bottom archive, but bad classpath for top archive
+ * @requires vm.cds
+ * @library /test/lib /test/hotspot/jtreg/runtime/appcds /test/hotspot/jtreg/runtime/appcds/test-classes
+ * @build GenericTestApp sun.hotspot.WhiteBox
+ * @run driver ClassFileInstaller -jar WhiteBox.jar sun.hotspot.WhiteBox
+ * @run driver ClassFileInstaller -jar GenericTestApp.jar GenericTestApp
+ * @run driver ClassFileInstaller -jar WrongJar.jar GenericTestApp
+ * @run driver WrongTopClasspath
+ */
+
+public class WrongTopClasspath extends DynamicArchiveTestBase {
+
+    public static void main(String[] args) throws Exception {
+        runTest(WrongTopClasspath::test);
+    }
+
+    static void test(String args[]) throws Exception {
+        String topArchiveName = getNewArchiveName("top");
+        String baseArchiveName = getNewArchiveName("base");
+        dumpBaseArchive(baseArchiveName);
+
+        String appJar    = ClassFileInstaller.getJarPath("GenericTestApp.jar");
+        String wrongJar  = ClassFileInstaller.getJarPath("WrongJar.jar");
+        String mainClass = "GenericTestApp";
+
+        // Dump the top archive using "-cp GenericTestApp.jar" ...
+        dump2_WB(baseArchiveName, topArchiveName,
+                 "-Xlog:cds*",
+                 "-Xlog:cds+dynamic=debug",
+                 "-cp", appJar, mainClass)
+            .assertNormalExit();
+
+        // ... but try to load the top archive using "-cp WrongJar.jar".
+        // Use -Xshare:auto so top archive can fail after base archive has succeeded,
+        // but the app will continue to run.
+        run2_WB(baseArchiveName, topArchiveName,
+                "-Xlog:cds*",
+                "-Xlog:cds+dynamic=debug",
+                "-Xlog:class+path=info",
+                "-Xs