8227370: Remove SharedPathsMiscInfo
authoriklam
Tue, 27 Aug 2019 22:14:52 -0700
changeset 57898 5ddb746d45e0
parent 57897 e2e315f1aa63
child 57899 54845835747f
8227370: Remove SharedPathsMiscInfo Reviewed-by: ccheung, jiangli
src/hotspot/share/classfile/classLoader.cpp
src/hotspot/share/classfile/classLoader.hpp
src/hotspot/share/classfile/classLoaderExt.cpp
src/hotspot/share/classfile/classLoaderExt.hpp
src/hotspot/share/classfile/sharedPathsMiscInfo.cpp
src/hotspot/share/classfile/sharedPathsMiscInfo.hpp
src/hotspot/share/include/cds.h
src/hotspot/share/memory/filemap.cpp
src/hotspot/share/memory/filemap.hpp
src/hotspot/share/prims/cdsoffsets.cpp
test/hotspot/jtreg/runtime/cds/appcds/AppendClasspath.java
test/hotspot/jtreg/runtime/cds/appcds/ClassPathAttr.java
test/hotspot/jtreg/runtime/cds/appcds/NonExistClasspath.java
test/hotspot/jtreg/runtime/cds/appcds/SharedArchiveConsistency.java
test/hotspot/jtreg/runtime/cds/appcds/TraceLongClasspath.java
test/hotspot/jtreg/runtime/cds/appcds/test-classes/CpAttr6.java
--- a/src/hotspot/share/classfile/classLoader.cpp	Tue Aug 27 22:14:15 2019 -0700
+++ b/src/hotspot/share/classfile/classLoader.cpp	Tue Aug 27 22:14:52 2019 -0700
@@ -73,9 +73,6 @@
 #include "utilities/events.hpp"
 #include "utilities/hashtable.inline.hpp"
 #include "utilities/macros.hpp"
-#if INCLUDE_CDS
-#include "classfile/sharedPathsMiscInfo.hpp"
-#endif
 
 // Entry points in zip.dll for loading zip/jar file entries
 
@@ -147,7 +144,6 @@
 ClassPathEntry* ClassLoader::_last_app_classpath_entry = NULL;
 ClassPathEntry* ClassLoader::_module_path_entries = NULL;
 ClassPathEntry* ClassLoader::_last_module_path_entry = NULL;
-SharedPathsMiscInfo* ClassLoader::_shared_paths_misc_info = NULL;
 #endif
 
 // helper routines
@@ -250,13 +246,12 @@
   return pkgEntryTable->lookup_only(pkg_symbol);
 }
 
-ClassPathDirEntry::ClassPathDirEntry(const char* dir) : ClassPathEntry() {
-  char* copy = NEW_C_HEAP_ARRAY(char, strlen(dir)+1, mtClass);
-  strcpy(copy, dir);
-  _dir = copy;
+const char* ClassPathEntry::copy_path(const char* path) {
+  char* copy = NEW_C_HEAP_ARRAY(char, strlen(path)+1, mtClass);
+  strcpy(copy, path);
+  return copy;
 }
 
-
 ClassFileStream* ClassPathDirEntry::open_stream(const char* name, TRAPS) {
   // construct full path name
   assert((_dir != NULL) && (name != NULL), "sanity");
@@ -296,9 +291,7 @@
 ClassPathZipEntry::ClassPathZipEntry(jzfile* zip, const char* zip_name,
                                      bool is_boot_append, bool from_class_path_attr) : ClassPathEntry() {
   _zip = zip;
-  char *copy = NEW_C_HEAP_ARRAY(char, strlen(zip_name)+1, mtClass);
-  strcpy(copy, zip_name);
-  _zip_name = copy;
+  _zip_name = copy_path(zip_name);
   _from_class_path_attr = from_class_path_attr;
 }
 
@@ -383,8 +376,7 @@
   assert(_singleton == NULL, "VM supports only one jimage");
   DEBUG_ONLY(_singleton = this);
   size_t len = strlen(name) + 1;
-  _name = NEW_C_HEAP_ARRAY(const char, len, mtClass);
-  strncpy((char *)_name, name, len);
+  _name = copy_path(name);
 }
 
 ClassPathImageEntry::~ClassPathImageEntry() {
@@ -537,30 +529,10 @@
   } else {
     trace_class_path("bootstrap loader class path=", sys_class_path);
   }
-#if INCLUDE_CDS
-  if (DumpSharedSpaces || DynamicDumpSharedSpaces) {
-    _shared_paths_misc_info->add_boot_classpath(sys_class_path);
-  }
-#endif
   setup_boot_search_path(sys_class_path);
 }
 
 #if INCLUDE_CDS
-int ClassLoader::get_shared_paths_misc_info_size() {
-  return _shared_paths_misc_info->get_used_bytes();
-}
-
-void* ClassLoader::get_shared_paths_misc_info() {
-  return _shared_paths_misc_info->buffer();
-}
-
-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(is_static);
-  delete checker;
-  return result;
-}
-
 void ClassLoader::setup_app_search_path(const char *class_path) {
   assert(DumpSharedSpaces || DynamicDumpSharedSpaces, "Sanity");
 
@@ -943,11 +915,6 @@
     }
     return true;
   } else {
-#if INCLUDE_CDS
-    if (DumpSharedSpaces || DynamicDumpSharedSpaces) {
-      _shared_paths_misc_info->add_nonexist_path(path);
-    }
-#endif
     return false;
   }
 }
@@ -1567,12 +1534,6 @@
   load_zip_library();
   // lookup jimage library entry points
   load_jimage_library();
-#if INCLUDE_CDS
-  // initialize search path
-  if (DumpSharedSpaces || DynamicDumpSharedSpaces) {
-    _shared_paths_misc_info = new SharedPathsMiscInfo();
-  }
-#endif
   setup_bootstrap_search_path();
 }
 
@@ -1580,7 +1541,6 @@
 void ClassLoader::initialize_shared_path() {
   if (DumpSharedSpaces || DynamicDumpSharedSpaces) {
     ClassLoaderExt::setup_search_paths();
-    _shared_paths_misc_info->write_jint(0); // see comments in SharedPathsMiscInfo::check()
   }
 }
 
--- a/src/hotspot/share/classfile/classLoader.hpp	Tue Aug 27 22:14:15 2019 -0700
+++ b/src/hotspot/share/classfile/classLoader.hpp	Tue Aug 27 22:14:52 2019 -0700
@@ -47,17 +47,19 @@
 class ClassPathEntry : public CHeapObj<mtClass> {
 private:
   ClassPathEntry* volatile _next;
+protected:
+  const char* copy_path(const char*path);
 public:
   ClassPathEntry* next() const;
   virtual ~ClassPathEntry() {}
   void set_next(ClassPathEntry* next);
-  virtual bool is_modules_image() const = 0;
-  virtual bool is_jar_file() const = 0;
+  virtual bool is_modules_image() const { return false; }
+  virtual bool is_jar_file() const { return false; }
   // Is this entry created from the "Class-path" attribute from a JAR Manifest?
-  virtual bool from_class_path_attr() const = 0;
+  virtual bool from_class_path_attr() const { return false; }
   virtual const char* name() const = 0;
-  virtual JImageFile* jimage() const = 0;
-  virtual void close_jimage() = 0;
+  virtual JImageFile* jimage() const { return NULL; }
+  virtual void close_jimage() {}
   // Constructor
   ClassPathEntry() : _next(NULL) {}
   // Attempt to locate file_name through this class path entry.
@@ -73,18 +75,14 @@
  private:
   const char* _dir;           // Name of directory
  public:
-  bool is_modules_image() const { return false; }
-  bool is_jar_file() const { return false;  }
-  bool from_class_path_attr() const { return false; }
   const char* name() const { return _dir; }
-  JImageFile* jimage() const { return NULL; }
-  void close_jimage() {}
-  ClassPathDirEntry(const char* dir);
+  ClassPathDirEntry(const char* dir) {
+    _dir = copy_path(dir);
+  }
   virtual ~ClassPathDirEntry() {}
   ClassFileStream* open_stream(const char* name, TRAPS);
 };
 
-
 // Type definitions for zip file and zip file entry
 typedef void* jzfile;
 typedef struct {
@@ -104,12 +102,9 @@
   const char*   _zip_name;   // Name of zip archive
   bool _from_class_path_attr; // From the "Class-path" attribute of a jar file
  public:
-  bool is_modules_image() const { return false; }
   bool is_jar_file() const { return true;  }
   bool from_class_path_attr() const { return _from_class_path_attr; }
   const char* name() const { return _zip_name; }
-  JImageFile* jimage() const { return NULL; }
-  void close_jimage() {}
   ClassPathZipEntry(jzfile* zip, const char* zip_name, bool is_boot_append, bool from_class_path_attr);
   virtual ~ClassPathZipEntry();
   u1* open_entry(const char* name, jint* filesize, bool nul_terminate, TRAPS);
@@ -126,8 +121,6 @@
   DEBUG_ONLY(static ClassPathImageEntry* _singleton;)
 public:
   bool is_modules_image() const;
-  bool is_jar_file() const { return false; }
-  bool from_class_path_attr() const { return false; }
   bool is_open() const { return _jimage != NULL; }
   const char* name() const { return _name == NULL ? "" : _name; }
   JImageFile* jimage() const { return _jimage; }
@@ -156,8 +149,6 @@
   void add_to_list(ClassPathEntry* new_entry);
 };
 
-class SharedPathsMiscInfo;
-
 class ClassLoader: AllStatic {
  public:
   enum ClassLoaderType {
@@ -230,8 +221,6 @@
   static ClassPathEntry* _last_append_entry;
 
   // Info used by CDS
-  CDS_ONLY(static SharedPathsMiscInfo * _shared_paths_misc_info;)
-
   CDS_ONLY(static ClassPathEntry* _app_classpath_entries;)
   CDS_ONLY(static ClassPathEntry* _last_app_classpath_entry;)
   CDS_ONLY(static ClassPathEntry* _module_path_entries;)
@@ -416,10 +405,6 @@
     }
     return num_entries;
   }
-  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, 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/classLoaderExt.cpp	Tue Aug 27 22:14:15 2019 -0700
+++ b/src/hotspot/share/classfile/classLoaderExt.cpp	Tue Aug 27 22:14:52 2019 -0700
@@ -30,7 +30,6 @@
 #include "classfile/classLoaderData.inline.hpp"
 #include "classfile/klassFactory.hpp"
 #include "classfile/modules.hpp"
-#include "classfile/sharedPathsMiscInfo.hpp"
 #include "classfile/systemDictionaryShared.hpp"
 #include "classfile/vmSymbols.hpp"
 #include "memory/allocation.inline.hpp"
@@ -74,7 +73,6 @@
     trace_class_path("app loader class path (skipped)=", app_class_path);
   } else {
     trace_class_path("app loader class path=", app_class_path);
-    shared_paths_misc_info()->add_app_classpath(app_class_path);
     ClassLoader::setup_app_search_path(app_class_path);
   }
 }
@@ -212,8 +210,12 @@
         char* libname = NEW_RESOURCE_ARRAY(char, libname_len + 1);
         int n = os::snprintf(libname, libname_len + 1, "%.*s%s", dir_len, dir_name, file_start);
         assert((size_t)n == libname_len, "Unexpected number of characters in string");
-        trace_class_path("library = ", libname);
-        ClassLoader::update_class_path_entry_list(libname, true, false, true /* from_class_path_attr */);
+        if (ClassLoader::update_class_path_entry_list(libname, true, false, true /* from_class_path_attr */)) {
+          trace_class_path("library = ", libname);
+        } else {
+          trace_class_path("library (non-existent) = ", libname);
+          FileMapInfo::record_non_existent_class_path_entry(libname);
+        }
       }
 
       file_start = file_end;
@@ -222,7 +224,6 @@
 }
 
 void ClassLoaderExt::setup_search_paths() {
-  shared_paths_misc_info()->record_app_offset();
   ClassLoaderExt::setup_app_search_path();
 }
 
@@ -248,12 +249,6 @@
   result->set_class_loader_type(classloader_type);
 }
 
-void ClassLoaderExt::finalize_shared_paths_misc_info() {
-  if (!_has_app_classes) {
-    shared_paths_misc_info()->pop_app();
-  }
-}
-
 // Load the class of the given name from the location given by path. The path is specified by
 // the "source:" in the class list file (see classListParser.cpp), and can be a directory or
 // a JAR file.
--- a/src/hotspot/share/classfile/classLoaderExt.hpp	Tue Aug 27 22:14:15 2019 -0700
+++ b/src/hotspot/share/classfile/classLoaderExt.hpp	Tue Aug 27 22:14:52 2019 -0700
@@ -47,9 +47,6 @@
   static char* get_class_path_attr(const char* jar_path, char* manifest, jint manifest_size);
   static void setup_app_search_path(); // Only when -Xshare:dump
   static void process_module_table(ModuleEntryTable* met, TRAPS);
-  static SharedPathsMiscInfo* shared_paths_misc_info() {
-    return (SharedPathsMiscInfo*)_shared_paths_misc_info;
-  }
   // index of first app JAR in shared classpath entry table
   static jshort _app_class_paths_start_index;
   // index of first modular JAR in shared modulepath entry table
@@ -84,8 +81,6 @@
     return read_manifest(entry, manifest_size, false, THREAD);
   }
 
-  static void finalize_shared_paths_misc_info();
-
   static jshort app_class_paths_start_index() { return _app_class_paths_start_index; }
 
   static jshort app_module_paths_start_index() { return _app_module_paths_start_index; }
--- a/src/hotspot/share/classfile/sharedPathsMiscInfo.cpp	Tue Aug 27 22:14:15 2019 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,178 +0,0 @@
-/*
- * 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
- * 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 "classfile/classLoader.hpp"
-#include "classfile/sharedPathsMiscInfo.hpp"
-#include "logging/log.hpp"
-#include "logging/logStream.hpp"
-#include "memory/allocation.inline.hpp"
-#include "memory/filemap.hpp"
-#include "memory/metaspaceShared.hpp"
-#include "memory/resourceArea.hpp"
-#include "runtime/arguments.hpp"
-#include "runtime/os.inline.hpp"
-#include "utilities/ostream.hpp"
-
-SharedPathsMiscInfo::SharedPathsMiscInfo() {
-  _app_offset = 0;
-  _buf_size = INITIAL_BUF_SIZE;
-  _cur_ptr = _buf_start = NEW_C_HEAP_ARRAY(char, _buf_size, mtClass);
-  _allocated = true;
-}
-
-SharedPathsMiscInfo::~SharedPathsMiscInfo() {
-  if (_allocated) {
-    FREE_C_HEAP_ARRAY(char, _buf_start);
-  }
-}
-
-void SharedPathsMiscInfo::add_path(const char* path, int type) {
-  log_info(class, path)("type=%s ", type_name(type));
-  ClassLoader::trace_class_path("add misc shared path ", path);
-  write(path, strlen(path) + 1);
-  write_jint(jint(type));
-}
-
-void SharedPathsMiscInfo::ensure_size(size_t needed_bytes) {
-  assert(_allocated, "cannot modify buffer during validation.");
-  int used = get_used_bytes();
-  int target = used + int(needed_bytes);
-  if (target > _buf_size) {
-    _buf_size = _buf_size * 2 + (int)needed_bytes;
-    _buf_start = REALLOC_C_HEAP_ARRAY(char, _buf_start, _buf_size, mtClass);
-    _cur_ptr = _buf_start + used;
-    _end_ptr = _buf_start + _buf_size;
-  }
-}
-
-void SharedPathsMiscInfo::write(const void* ptr, size_t size) {
-  ensure_size(size);
-  memcpy(_cur_ptr, ptr, size);
-  _cur_ptr += size;
-}
-
-bool SharedPathsMiscInfo::read(void* ptr, size_t size) {
-  if (_cur_ptr + size <= _end_ptr) {
-    memcpy(ptr, _cur_ptr, size);
-    _cur_ptr += size;
-    return true;
-  }
-  return false;
-}
-
-bool SharedPathsMiscInfo::fail(const char* msg, const char* name) {
-  ClassLoader::trace_class_path(msg, name);
-  MetaspaceShared::set_archive_loading_failed();
-  return false;
-}
-
-void SharedPathsMiscInfo::print_path(outputStream* out, int type, const char* path) {
-  switch (type) {
-  case BOOT_PATH:
-    out->print("Expecting BOOT path=%s", path);
-    break;
-  case NON_EXIST:
-    out->print("Expecting that %s does not exist", path);
-    break;
-  case APP_PATH:
-    ClassLoader::trace_class_path("Expecting -Djava.class.path=", path);
-    break;
-  default:
-    ShouldNotReachHere();
-  }
-}
-
-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);
-  if (_cur_ptr >= _end_ptr) {
-    return fail("Truncated archive file header");
-  }
-  if (*_end_ptr != 0) {
-    return fail("Corrupted archive file header");
-  }
-
-  jshort cur_index = 0;
-  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;
-    _cur_ptr += strlen(path) + 1;
-
-    if (!read_jint(&type)) {
-      return fail("Corrupted archive file header");
-    }
-    LogTarget(Info, class, path) lt;
-    if (lt.is_enabled()) {
-      lt.print("type=%s ", type_name(type));
-      LogStream ls(lt);
-      print_path(&ls, type, path);
-      ls.cr();
-    }
-    // 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, is_static)) {
-        if (!PrintSharedArchiveAndExit) {
-          return false;
-        }
-      } else {
-        ClassLoader::trace_class_path("ok");
-      }
-    } else {
-      ClassLoader::trace_class_path("skipped check");
-    }
-    cur_index++;
-  }
-
-  return true;
-}
-
-bool SharedPathsMiscInfo::check(jint type, const char* path, bool is_static) {
-  assert(UseSharedSpaces, "runtime only");
-  switch (type) {
-  case BOOT_PATH:
-    break;
-  case NON_EXIST:
-    {
-      struct stat st;
-      if (os::stat(path, &st) == 0) {
-        // The file actually exists
-        // But we want it to not exist -> fail
-        return fail("File must not exist");
-      }
-    }
-    break;
-  case APP_PATH:
-    break;
-  default:
-    return fail("Corrupted archive file header");
-  }
-
-  return true;
-}
--- a/src/hotspot/share/classfile/sharedPathsMiscInfo.hpp	Tue Aug 27 22:14:15 2019 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,168 +0,0 @@
-/*
- * 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
- * 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_CLASSFILE_SHAREDPATHSMISCINFO_HPP
-#define SHARE_CLASSFILE_SHAREDPATHSMISCINFO_HPP
-
-#include "classfile/classLoader.hpp"
-#include "runtime/os.hpp"
-
-class outputStream;
-// During dumping time, when processing class paths, we build up the dump-time
-// classpath. The JAR files that exist are stored in the list ClassLoader::_first_append_entry.
-// However, we need to store other "misc" information for run-time checking, such as
-//
-// + The values of Arguments::get_sysclasspath() used during dumping.
-//
-// + The class path elements specified during dumping but did not exist --
-//   these elements must also be specified at run time, and they also must not
-//   exist at run time.
-//
-// These misc items are stored in a linear buffer in SharedPathsMiscInfo.
-// The storage format is stream oriented to minimize its size.
-//
-// When writing the information to the archive file, SharedPathsMiscInfo is stored in
-// the archive file header. At run-time, this information is used only during initialization
-// (accessed using read() instead of mmap()), and is deallocated afterwards to save space.
-//
-// The SharedPathsMiscInfo class is used for both creating the the information (during
-// dumping time) and validation (at run time). Different constructors are used in the
-// two situations. See below.
-
-class SharedPathsMiscInfo : public CHeapObj<mtClass> {
-private:
-  int   _app_offset;
-protected:
-  char* _buf_start;
-  char* _cur_ptr;
-  char* _end_ptr;
-  int   _buf_size;
-  bool  _allocated;   // was _buf_start allocated by me?
-  void ensure_size(size_t needed_bytes);
-  void add_path(const char* path, int type);
-
-  void write(const void* ptr, size_t size);
-  bool read(void* ptr, size_t size);
-
-protected:
-  static bool fail(const char* msg, const char* name = NULL);
-  bool check(jint type, const char* path, bool is_static);
-
-public:
-  enum {
-    INITIAL_BUF_SIZE = 128
-  };
-  // This constructor is used when creating the misc information (during dump)
-  SharedPathsMiscInfo();
-  // This constructor is used when validating the misc info (during run time)
-  SharedPathsMiscInfo(char *buff, int size) {
-    _app_offset = 0;
-    _cur_ptr = _buf_start = buff;
-    _end_ptr = _buf_start + size;
-    _buf_size = size;
-    _allocated = false;
-  }
-  ~SharedPathsMiscInfo();
-
-  int get_used_bytes() {
-    return _cur_ptr - _buf_start;
-  }
-  void* buffer() {
-    return _buf_start;
-  }
-
-  // writing --
-
-  // The path must not exist at run-time
-  void add_nonexist_path(const char* path) {
-    add_path(path, NON_EXIST);
-  }
-
-  // The path must exist, and must contain exactly <num_entries> files/dirs
-  void add_boot_classpath(const char* path) {
-    add_path(path, BOOT_PATH);
-  }
-
-  void add_app_classpath(const char* path) {
-    add_path(path, APP_PATH);
-  }
-  void record_app_offset() {
-    _app_offset = get_used_bytes();
-  }
-  void pop_app() {
-    _cur_ptr = _buf_start + _app_offset;
-    write_jint(0);
-  }
-
-  int write_jint(jint num) {
-    write(&num, sizeof(num));
-    return 0;
-  }
-  void write_time(time_t t) {
-    write(&t, sizeof(t));
-  }
-  void write_long(long l) {
-    write(&l, sizeof(l));
-  }
-
-  bool dump_to_file(int fd) {
-    int n = get_used_bytes();
-    return (os::write(fd, _buf_start, n) == (size_t)n);
-  }
-
-  // reading --
-
-private:
-  enum {
-    BOOT_PATH      = 1,
-    APP_PATH       = 2,
-    NON_EXIST      = 3
-  };
-
-  const char* type_name(int type) {
-    switch (type) {
-    case BOOT_PATH:   return "BOOT";
-    case APP_PATH:    return "APP";
-    case NON_EXIST:   return "NON_EXIST";
-    default:          ShouldNotReachHere(); return "?";
-    }
-  }
-
-  void print_path(outputStream* os, int type, const char* path);
-
-  bool read_jint(jint *ptr) {
-    return read(ptr, sizeof(jint));
-  }
-  bool read_long(long *ptr) {
-    return read(ptr, sizeof(long));
-  }
-  bool read_time(time_t *ptr) {
-    return read(ptr, sizeof(time_t));
-  }
-
-public:
-  bool check(bool is_static);
-};
-
-#endif // SHARE_CLASSFILE_SHAREDPATHSMISCINFO_HPP
--- a/src/hotspot/share/include/cds.h	Tue Aug 27 22:14:15 2019 -0700
+++ b/src/hotspot/share/include/cds.h	Tue Aug 27 22:14:52 2019 -0700
@@ -36,7 +36,7 @@
 #define NUM_CDS_REGIONS 8 // this must be the same as MetaspaceShared::n_regions
 #define CDS_ARCHIVE_MAGIC 0xf00baba2
 #define CDS_DYNAMIC_ARCHIVE_MAGIC 0xf00baba8
-#define CURRENT_CDS_ARCHIVE_VERSION 6
+#define CURRENT_CDS_ARCHIVE_VERSION 7
 #define INVALID_CDS_ARCHIVE_VERSION -1
 
 struct CDSFileMapRegion {
--- a/src/hotspot/share/memory/filemap.cpp	Tue Aug 27 22:14:15 2019 -0700
+++ b/src/hotspot/share/memory/filemap.cpp	Tue Aug 27 22:14:52 2019 -0700
@@ -241,7 +241,6 @@
   // JVM version string ... changes on each build.
   get_header_version(_jvm_ident);
 
-  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();
@@ -257,6 +256,11 @@
   _base_archive_is_default = false;
 }
 
+void SharedClassPathEntry::init_as_non_existent(const char* path, TRAPS) {
+  _type = non_existent_entry;
+  set_name(path, THREAD);
+}
+
 void SharedClassPathEntry::init(bool is_modules_image,
                                 ClassPathEntry* cpe, TRAPS) {
   assert(DumpSharedSpaces || DynamicDumpSharedSpaces, "dump time only");
@@ -288,26 +292,35 @@
     FileMapInfo::fail_stop("Unable to open file %s.", cpe->name());
   }
 
-  size_t len = strlen(cpe->name()) + 1;
+  // No need to save the name of the module file, as it will be computed at run time
+  // to allow relocation of the JDK directory.
+  const char* name = is_modules_image  ? "" : cpe->name();
+  set_name(name, THREAD);
+}
+
+void SharedClassPathEntry::set_name(const char* name, TRAPS) {
+  size_t len = strlen(name) + 1;
   _name = MetadataFactory::new_array<char>(ClassLoaderData::the_null_class_loader_data(), (int)len, THREAD);
-  strcpy(_name->data(), cpe->name());
+  strcpy(_name->data(), name);
 }
 
-bool SharedClassPathEntry::validate(bool is_class_path) {
+const char* SharedClassPathEntry::name() const {
+  if (UseSharedSpaces && is_modules_image()) {
+    // In order to validate the runtime modules image file size against the archived
+    // size information, we need to obtain the runtime modules image path. The recorded
+    // dump time modules image path in the archive may be different from the runtime path
+    // if the JDK image has beed moved after generating the archive.
+    return ClassLoader::get_jrt_entry()->name();
+  } else {
+    return _name->data();
+  }
+}
+
+bool SharedClassPathEntry::validate(bool is_class_path) const {
   assert(UseSharedSpaces, "runtime only");
 
   struct stat st;
-  const char* name;
-
-  // In order to validate the runtime modules image file size against the archived
-  // size information, we need to obtain the runtime modules image path. The recorded
-  // dump time modules image path in the archive may be different from the runtime path
-  // if the JDK image has beed moved after generating the archive.
-  if (is_modules_image()) {
-    name = ClassLoader::get_jrt_entry()->name();
-  } else {
-    name = this->name();
-  }
+  const char* name = this->name();
 
   bool ok = true;
   log_info(class, path)("checking shared classpath entry: %s", name);
@@ -345,6 +358,19 @@
   return ok;
 }
 
+bool SharedClassPathEntry::check_non_existent() const {
+  assert(_type == non_existent_entry, "must be");
+  log_info(class, path)("should be non-existent: %s", name());
+  struct stat st;
+  if (os::stat(name(), &st) != 0) {
+    log_info(class, path)("ok");
+    return true; // file doesn't exist
+  } else {
+    return false;
+  }
+}
+
+
 void SharedClassPathEntry::metaspace_pointers_do(MetaspaceClosure* it) {
   it->push(&_name);
   it->push(&_manifest);
@@ -359,10 +385,11 @@
 
 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;
+  int num_entries = 0;
+  num_entries += ClassLoader::num_boot_classpath_entries();
+  num_entries += ClassLoader::num_app_classpath_entries();
+  num_entries += ClassLoader::num_module_path_entries();
+  num_entries += FileMapInfo::num_non_existent_class_paths();
   size_t bytes = entry_size * num_entries;
 
   _table = MetadataFactory::new_array<u8>(loader_data, (int)(bytes + 7 / 8), THREAD);
@@ -372,7 +399,7 @@
 void FileMapInfo::allocate_shared_path_table() {
   assert(DumpSharedSpaces || DynamicDumpSharedSpaces, "Sanity");
 
-  Thread* THREAD = Thread::current();
+  EXCEPTION_MARK; // The following calls should never throw, but would exit VM on error.
   ClassLoaderData* loader_data = ClassLoaderData::the_null_class_loader_data();
   ClassPathEntry* jrt = ClassLoader::get_jrt_entry();
 
@@ -383,47 +410,37 @@
 
   // 1. boot class path
   int i = 0;
-  ClassPathEntry* cpe = jrt;
+  i = add_shared_classpaths(i, "boot",   jrt, THREAD);
+  i = add_shared_classpaths(i, "app",    ClassLoader::app_classpath_entries(), THREAD);
+  i = add_shared_classpaths(i, "module", ClassLoader::module_path_entries(), THREAD);
+
+  for (int x = 0; x < num_non_existent_class_paths(); x++, i++) {
+    const char* path = _non_existent_class_paths->at(x);
+    shared_path(i)->init_as_non_existent(path, THREAD);
+  }
+
+  assert(i == _shared_path_table.size(), "number of shared path entry mismatch");
+}
+
+int FileMapInfo::add_shared_classpaths(int i, const char* which, ClassPathEntry *cpe, TRAPS) {
   while (cpe != NULL) {
-    bool is_jrt = (cpe == jrt);
+    bool is_jrt = (cpe == ClassLoader::get_jrt_entry());
     const char* type = (is_jrt ? "jrt" : (cpe->is_jar_file() ? "jar" : "dir"));
-    log_info(class, path)("add main shared path (%s) %s", type, cpe->name());
+    log_info(class, path)("add %s shared path (%s) %s", which, type, cpe->name());
     SharedClassPathEntry* ent = shared_path(i);
     ent->init(is_jrt, cpe, THREAD);
-    if (!is_jrt) {    // No need to do the modules image.
-      EXCEPTION_MARK; // The following call should never throw, but would exit VM on error.
-      update_shared_classpath(cpe, ent, THREAD);
+    if (cpe->is_jar_file()) {
+      update_jar_manifest(cpe, ent, THREAD);
     }
-    cpe = ClassLoader::get_next_boot_classpath_entry(cpe);
-    i++;
-  }
-  assert(i == ClassLoader::num_boot_classpath_entries(),
-         "number of boot class path entry mismatch");
-
-  // 2. app class path
-  ClassPathEntry *acpe = ClassLoader::app_classpath_entries();
-  while (acpe != NULL) {
-    log_info(class, path)("add app shared path %s", acpe->name());
-    SharedClassPathEntry* ent = shared_path(i);
-    ent->init(false, acpe, THREAD);
-    EXCEPTION_MARK;
-    update_shared_classpath(acpe, ent, THREAD);
-    acpe = acpe->next();
+    if (is_jrt) {
+      cpe = ClassLoader::get_next_boot_classpath_entry(cpe);
+    } else {
+      cpe = cpe->next();
+    }
     i++;
   }
 
-  // 3. module path
-  ClassPathEntry *mpe = ClassLoader::module_path_entries();
-  while (mpe != NULL) {
-    log_info(class, path)("add module path %s",mpe->name());
-    SharedClassPathEntry* ent = shared_path(i);
-    ent->init(false, mpe, THREAD);
-    EXCEPTION_MARK;
-    update_shared_classpath(mpe, ent, THREAD);
-    mpe = mpe->next();
-    i++;
-  }
-  assert(i == _shared_path_table.size(), "number of shared path entry mismatch");
+  return i;
 }
 
 void FileMapInfo::check_nonempty_dir_in_shared_path_table() {
@@ -453,6 +470,24 @@
   }
 }
 
+void FileMapInfo::record_non_existent_class_path_entry(const char* path) {
+  assert(DumpSharedSpaces || DynamicDumpSharedSpaces, "dump time only");
+  log_info(class, path)("non-existent Class-Path entry %s", path);
+  if (_non_existent_class_paths == NULL) {
+    _non_existent_class_paths = new (ResourceObj::C_HEAP, mtInternal)GrowableArray<const char*>(10, true);
+  }
+  _non_existent_class_paths->append(os::strdup(path));
+}
+
+int FileMapInfo::num_non_existent_class_paths() {
+  assert(DumpSharedSpaces || DynamicDumpSharedSpaces, "dump time only");
+  if (_non_existent_class_paths != NULL) {
+    return _non_existent_class_paths->length();
+  } else {
+    return 0;
+  }
+}
+
 class ManifestStream: public ResourceObj {
   private:
   u1*   _buffer_start; // Buffer bottom
@@ -501,29 +536,27 @@
   }
 };
 
-void FileMapInfo::update_shared_classpath(ClassPathEntry *cpe, SharedClassPathEntry* ent, TRAPS) {
+void FileMapInfo::update_jar_manifest(ClassPathEntry *cpe, SharedClassPathEntry* ent, TRAPS) {
   ClassLoaderData* loader_data = ClassLoaderData::the_null_class_loader_data();
   ResourceMark rm(THREAD);
   jint manifest_size;
 
-  if (cpe->is_jar_file()) {
-    assert(ent->is_jar(), "the shared class path entry is not a JAR file");
-    char* manifest = ClassLoaderExt::read_manifest(cpe, &manifest_size, CHECK);
-    if (manifest != NULL) {
-      ManifestStream* stream = new ManifestStream((u1*)manifest,
-                                                  manifest_size);
-      if (stream->check_is_signed()) {
-        ent->set_is_signed();
-      } else {
-        // Copy the manifest into the shared archive
-        manifest = ClassLoaderExt::read_raw_manifest(cpe, &manifest_size, CHECK);
-        Array<u1>* buf = MetadataFactory::new_array<u1>(loader_data,
-                                                        manifest_size,
-                                                        THREAD);
-        char* p = (char*)(buf->data());
-        memcpy(p, manifest, manifest_size);
-        ent->set_manifest(buf);
-      }
+  assert(cpe->is_jar_file() && ent->is_jar(), "the shared class path entry is not a JAR file");
+  char* manifest = ClassLoaderExt::read_manifest(cpe, &manifest_size, CHECK);
+  if (manifest != NULL) {
+    ManifestStream* stream = new ManifestStream((u1*)manifest,
+                                                manifest_size);
+    if (stream->check_is_signed()) {
+      ent->set_is_signed();
+    } else {
+      // Copy the manifest into the shared archive
+      manifest = ClassLoaderExt::read_raw_manifest(cpe, &manifest_size, CHECK);
+      Array<u1>* buf = MetadataFactory::new_array<u1>(loader_data,
+                                                      manifest_size,
+                                                      THREAD);
+      char* p = (char*)(buf->data());
+      memcpy(p, manifest, manifest_size);
+      ent->set_manifest(buf);
     }
   }
 }
@@ -680,6 +713,16 @@
       // None of the jar file specified in the runtime -cp exists.
       return fail("None of the jar file specified in the runtime -cp exists: -Djava.class.path=", appcp);
     }
+
+    // Handling of non-existent entries in the classpath: we eliminate all the non-existent
+    // entries from both the dump time classpath (ClassLoader::update_class_path_entry_list)
+    // and the runtime classpath (FileMapInfo::create_path_array), and check the remaining
+    // entries. E.g.:
+    //
+    // dump : -cp a.jar:NE1:NE2:b.jar  -> a.jar:b.jar -> recorded in archive.
+    // run 1: -cp NE3:a.jar:NE4:b.jar  -> a.jar:b.jar -> matched
+    // run 2: -cp x.jar:NE4:b.jar      -> x.jar:b.jar -> mismatched
+
     int j = _header->_app_class_paths_start_index;
     mismatch = check_paths(j, shared_app_paths_len, rp_array);
     if (mismatch) {
@@ -689,6 +732,20 @@
   return true;
 }
 
+void FileMapInfo::log_paths(const char* msg, int start_idx, int end_idx) {
+  LogTarget(Info, class, path) lt;
+  if (lt.is_enabled()) {
+    LogStream ls(lt);
+    ls.print("%s", msg);
+    const char* prefix = "";
+    for (int i = start_idx; i < end_idx; i++) {
+      ls.print("%s%s", prefix, shared_path(i)->name());
+      prefix = os::path_separator();
+    }
+    ls.cr();
+  }
+}
+
 bool FileMapInfo::validate_shared_path_table() {
   assert(UseSharedSpaces, "runtime only");
 
@@ -717,6 +774,9 @@
     }
   }
 
+  log_paths("Expecting BOOT path=", 0, _header->_app_class_paths_start_index);
+  log_paths("Expecting -Djava.class.path=", _header->_app_class_paths_start_index, _header->_app_module_paths_start_index);
+
   int module_paths_start_index = _header->_app_module_paths_start_index;
   int shared_app_paths_len = 0;
 
@@ -757,6 +817,8 @@
     }
   }
 
+  validate_non_existent_class_paths();
+
   _validating_shared_path_table = false;
 
 #if INCLUDE_JVMTI
@@ -771,6 +833,26 @@
   return true;
 }
 
+void FileMapInfo::validate_non_existent_class_paths() {
+  // All of the recorded non-existent paths came from the Class-Path: attribute from the JAR
+  // files on the app classpath. If any of these are found to exist during runtime,
+  // it will change how classes are loading for the app loader. For safety, disable
+  // loading of archived platform/app classes (currently there's no way to disable just the
+  // app classes).
+
+  assert(UseSharedSpaces, "runtime only");
+  for (int i = _header->_app_module_paths_start_index + _header->_num_module_paths;
+       i < get_number_of_shared_paths();
+       i++) {
+    SharedClassPathEntry* ent = shared_path(i);
+    if (!ent->check_non_existent()) {
+      warning("Archived non-system classes are disabled because the "
+              "file %s exists", ent->name());
+      _header->_has_platform_or_app_classes = false;
+    }
+  }
+}
+
 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) {
@@ -840,9 +922,6 @@
   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) {
@@ -933,18 +1012,7 @@
     }
   }
 
-  _file_offset = n;
-
-  size_t info_size = _header->_paths_misc_info_size;
-  _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.");
-    FREE_C_HEAP_ARRAY(char, _paths_misc_info);
-    _paths_misc_info = NULL;
-    return false;
-  }
-  _file_offset += n + _header->_base_archive_name_size; // accounts for the size of _base_archive_name
+  _file_offset = n + _header->_base_archive_name_size; // accounts for the size of _base_archive_name
 
   if (is_static) {
     // just checking the last region is sufficient since the archive is written
@@ -1026,10 +1094,6 @@
 // Write the header to the file, seek to the next allocation boundary.
 
 void FileMapInfo::write_header() {
-  int info_size = ClassLoader::get_shared_paths_misc_info_size();
-
-  _header->_paths_misc_info_size = info_size;
-
   char* base_archive_name = NULL;
   if (_header->_magic == CDS_DYNAMIC_ARCHIVE_MAGIC) {
     base_archive_name = (char*)Arguments::GetSharedArchivePath();
@@ -1039,7 +1103,6 @@
 
   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);
   }
@@ -1728,6 +1791,7 @@
 SharedPathTable FileMapInfo::_shared_path_table;
 bool FileMapInfo::_validating_shared_path_table = false;
 bool FileMapInfo::_memory_mapping_failed = false;
+GrowableArray<const char*>* FileMapInfo::_non_existent_class_paths = NULL;
 
 // Open the shared archive file, read and validate the header
 // information (version, boot classpath, etc.).  If initialization
@@ -1736,7 +1800,7 @@
 //
 // Validation of the archive is done in two steps:
 //
-// [1] validate_header() - done here. This checks the header, including _paths_misc_info.
+// [1] validate_header() - done here.
 // [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 is_static) {
@@ -1840,22 +1904,7 @@
 }
 
 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, is_static)) {
-      if (!PrintSharedArchiveAndExit) {
-        fail_continue("shared class paths mismatch (hint: enable -Xlog:class+path=info to diagnose the failure)");
-        status = false;
-      }
-    }
-  }
-
-  if (_paths_misc_info != NULL) {
-    FREE_C_HEAP_ARRAY(char, _paths_misc_info);
-    _paths_misc_info = NULL;
-  }
-  return status;
+  return _header->validate();
 }
 
 // Check if a given address is within one of the shared regions
@@ -1907,7 +1956,7 @@
   ClassPathEntry* ent = _classpath_entries_for_jvmti[i];
   if (ent == NULL) {
     if (i == 0) {
-      ent = ClassLoader:: get_jrt_entry();
+      ent = ClassLoader::get_jrt_entry();
       assert(ent != NULL, "must be");
     } else {
       SharedClassPathEntry* scpe = shared_path(i);
--- a/src/hotspot/share/memory/filemap.hpp	Tue Aug 27 22:14:15 2019 -0700
+++ b/src/hotspot/share/memory/filemap.hpp	Tue Aug 27 22:14:52 2019 -0700
@@ -49,8 +49,12 @@
     jar_entry,
     signed_jar_entry,
     dir_entry,
+    non_existent_entry,
     unknown_entry
   };
+
+  void set_name(const char* name, TRAPS);
+
 protected:
   u1     _type;
   bool   _from_class_path_attr;
@@ -61,24 +65,25 @@
 
 public:
   void init(bool is_modules_image, ClassPathEntry* cpe, TRAPS);
+  void init_as_non_existent(const char* path, TRAPS);
   void metaspace_pointers_do(MetaspaceClosure* it);
-  bool validate(bool is_class_path = true);
+  bool validate(bool is_class_path = true) const;
 
   // The _timestamp only gets set for jar files.
-  bool has_timestamp() {
+  bool has_timestamp() const {
     return _timestamp != 0;
   }
-  bool is_dir()            { return _type == dir_entry; }
-  bool is_modules_image()  { return _type == modules_image_entry; }
-  bool is_jar()            { return _type == jar_entry; }
-  bool is_signed()         { return _type == signed_jar_entry; }
-  void set_is_signed()     {
+  bool is_dir()           const { return _type == dir_entry; }
+  bool is_modules_image() const { return _type == modules_image_entry; }
+  bool is_jar()           const { return _type == jar_entry; }
+  bool is_signed()        const { return _type == signed_jar_entry; }
+  void set_is_signed() {
     _type = signed_jar_entry;
   }
   bool from_class_path_attr() { return _from_class_path_attr; }
   time_t timestamp() const { return _timestamp; }
   long   filesize()  const { return _filesize; }
-  const char* name() const { return _name->data(); }
+  const char* name() const;
   const char* manifest() const {
     return (_manifest == NULL) ? NULL : (const char*)_manifest->data();
   }
@@ -88,6 +93,7 @@
   void set_manifest(Array<u1>* manifest) {
     _manifest = manifest;
   }
+  bool check_non_existent() const;
 };
 
 struct ArchiveHeapOopmapInfo {
@@ -147,30 +153,12 @@
   // 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
-  // detailed description.
-  //
-  // The _paths_misc_info data is stored as a byte array in the archive file header,
-  // immediately after the _header field. This information is used only when
-  // checking the validity of the archive and is deallocated after the archive is loaded.
-  //
-  // Note that the _paths_misc_info does NOT include information for JAR files
-  // that existed during dump time. Their information is stored in _shared_path_table.
-  int _paths_misc_info_size;
-
-  // The following is a table of all the class path entries that were used
-  // during dumping. At run time, we require these files to exist and have the same
-  // size/modification time, or else the archive will refuse to load.
-  //
-  // All of these entries must be JAR files. The dumping process would fail if a non-empty
-  // directory was specified in the classpaths. If an empty directory was specified
-  // it is checked by the _paths_misc_info as described above.
-  //
-  // 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.
+  // The following is a table of all the boot/app/module path entries that were used
+  // during dumping. At run time, we validate these entries according to their
+  // SharedClassPathEntry::_type. See:
+  //      check_nonempty_dir_in_shared_path_table()
+  //      validate_shared_path_table()
+  //      validate_non_existent_class_paths()
   SharedPathTable _shared_path_table;
 
   jshort _app_class_paths_start_index;  // Index of first app classpath entry
@@ -232,13 +220,14 @@
   FileMapHeader * _header;
 
   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;
   static bool _memory_mapping_failed;
+  static GrowableArray<const char*>* _non_existent_class_paths;
+
   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);
@@ -246,6 +235,8 @@
   bool  init_from_file(int fd, bool is_static);
   static void metaspace_pointers_do(MetaspaceClosure* it);
 
+  void log_paths(const char* msg, int start_idx, int end_idx);
+
 public:
   FileMapInfo(bool is_static);
   ~FileMapInfo();
@@ -353,9 +344,13 @@
   static void stop_sharing_and_unmap(const char* msg);
 
   static void allocate_shared_path_table();
+  static int add_shared_classpaths(int i, const char* which, ClassPathEntry *cpe, TRAPS);
   static void check_nonempty_dir_in_shared_path_table();
   bool validate_shared_path_table();
-  static void update_shared_classpath(ClassPathEntry *cpe, SharedClassPathEntry* ent, TRAPS);
+  void validate_non_existent_class_paths();
+  static void update_jar_manifest(ClassPathEntry *cpe, SharedClassPathEntry* ent, TRAPS);
+  static int num_non_existent_class_paths();
+  static void record_non_existent_class_path_entry(const char* path);
 
 #if INCLUDE_JVMTI
   static ClassFileStream* open_stream_for_jvmti(InstanceKlass* ik, Handle class_loader, TRAPS);
--- a/src/hotspot/share/prims/cdsoffsets.cpp	Tue Aug 27 22:14:15 2019 -0700
+++ b/src/hotspot/share/prims/cdsoffsets.cpp	Tue Aug 27 22:14:52 2019 -0700
@@ -53,7 +53,6 @@
     ADD_NEXT(_all, "FileMapHeader::_space[0]", offset_of(FileMapHeader, _space));           \
     ADD_NEXT(_all, "CDSFileMapRegion::_crc", offset_of(CDSFileMapRegion, _crc));            \
     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));
--- a/test/hotspot/jtreg/runtime/cds/appcds/AppendClasspath.java	Tue Aug 27 22:14:15 2019 -0700
+++ b/test/hotspot/jtreg/runtime/cds/appcds/AppendClasspath.java	Tue Aug 27 22:14:52 2019 -0700
@@ -95,19 +95,5 @@
         "-cp", appJar2 + File.pathSeparator + appJar,
         "HelloMore")
         .assertAbnormalExit(errorMessage1, errorMessage2);
-
-    // FAIL: 4) non-existing jar during dump time but jar exists during runtime
-    TestCommon.testDump(classPath, TestCommon.list("Hello"));
-
-    Files.copy(Paths.get(classDir, "hello.jar"),
-        Paths.get(classDir, newFile),
-        StandardCopyOption.REPLACE_EXISTING);
-
-    TestCommon.run(
-        "-cp", classPath,
-        "-Xlog:class+path=trace",
-        "Hello")
-        .assertAbnormalExit(errorMessage1, errorMessage2);
-
     }
 }
--- a/test/hotspot/jtreg/runtime/cds/appcds/ClassPathAttr.java	Tue Aug 27 22:14:15 2019 -0700
+++ b/test/hotspot/jtreg/runtime/cds/appcds/ClassPathAttr.java	Tue Aug 27 22:14:52 2019 -0700
@@ -42,6 +42,11 @@
 public class ClassPathAttr {
 
   public static void main(String[] args) throws Exception {
+    testNormalOps();
+    testNonExistentJars();
+  }
+
+  static void testNormalOps() throws Exception {
     buildCpAttr("cpattr1", "cpattr1.mf", "CpAttr1", "CpAttr1");
     buildCpAttr("cpattr1_long", "cpattr1_long.mf", "CpAttr1", "CpAttr1");
     buildCpAttr("cpattr2", "cpattr2.mf", "CpAttr2", "CpAttr2");
@@ -93,6 +98,37 @@
     }
   }
 
+  static void testNonExistentJars() throws Exception {
+    buildCpAttr("cpattr6", "cpattr6.mf", "CpAttr6", "CpAttr6");
+
+    String cp = TestCommon.getTestJar("cpattr6.jar");
+    String nonExistPath = System.getProperty("test.classes") + File.separator + "cpattrX.jar";
+    (new File(nonExistPath)).delete();
+
+    TestCommon.testDump(cp, TestCommon.list("CpAttr6"),
+        "-Xlog:class+path");
+
+    TestCommon.run(
+        "-Xlog:class+path",
+        "-cp", cp,
+        "CpAttr6")
+      .assertNormalExit(output -> {
+          output.shouldMatch("should be non-existent: .*cpattrX.jar");
+        });
+
+    // Now make nonExistPath exist. CDS still loads, but archived non-system classes will not be used.
+    Files.copy(Paths.get(cp), Paths.get(nonExistPath),
+               StandardCopyOption.REPLACE_EXISTING);
+
+    TestCommon.run(
+        "-Xlog:class+path",
+        "-cp", cp,
+        "CpAttr6")
+      .assertNormalExit(output -> {
+          output.shouldMatch("Archived non-system classes are disabled because the file .*cpattrX.jar exists");
+        });
+  }
+
   private static void buildCpAttr(String jarName, String manifest, String enclosingClassName, String ...testClassNames) throws Exception {
     String jarClassesDir = System.getProperty("test.classes") + File.separator + jarName + "_classes";
     try { Files.createDirectory(Paths.get(jarClassesDir)); } catch (FileAlreadyExistsException e) { }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/cds/appcds/NonExistClasspath.java	Tue Aug 27 22:14:52 2019 -0700
@@ -0,0 +1,115 @@
+/*
+ * 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 non-existent classpath elements during dump time and run time
+ * @requires vm.cds
+ * @library /test/lib
+ * @modules jdk.jartool/sun.tools.jar
+ * @compile test-classes/Hello.java
+ * @compile test-classes/HelloMore.java
+ * @run driver NonExistClasspath
+ */
+
+import java.io.File;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.nio.file.StandardCopyOption;
+import jdk.test.lib.process.OutputAnalyzer;
+
+public class NonExistClasspath {
+    public static void main(String[] args) throws Exception {
+        String appJar = JarBuilder.getOrCreateHelloJar();
+        doTest(appJar, false);
+        doTest(appJar, true);
+    }
+
+    static void doTest(String appJar, boolean bootcp) throws Exception {
+        String classDir = System.getProperty("test.classes");
+        String newFile = "non-exist.jar";
+        String nonExistPath = classDir + File.separator + newFile;
+        final String errorMessage1 = "Unable to use shared archive";
+        final String errorMessage2 = "shared class paths mismatch";
+        final String errorMessage3 = (bootcp ? "BOOT" : "APP") + " classpath mismatch";
+
+        (new File(nonExistPath)).delete();
+
+        String classPath = nonExistPath + File.pathSeparator + appJar;
+        TestCommon.testDump("foobar", TestCommon.list("Hello"), make_args(bootcp, classPath));
+
+        // The nonExistPath doesn't exist yet, so we should be able to run without problem
+        TestCommon.run(make_args(bootcp,
+                                 classPath,
+                                 "-Xlog:class+path=trace",
+                                 "Hello"))
+            .assertNormalExit();
+
+        // Replace nonExistPath with another non-existent file in the CP, it should still work
+        TestCommon.run(make_args(bootcp,
+                                 nonExistPath + ".duh"  + File.pathSeparator + appJar,
+                                 "-Xlog:class+path=trace",
+                                 "Hello"))
+            .assertNormalExit();
+
+        // Add a few more non-existent files in the CP, it should still work
+        TestCommon.run(make_args(bootcp,
+                                 nonExistPath + ".duh"  + File.pathSeparator +
+                                 nonExistPath + ".daa"  + File.pathSeparator +
+                                 nonExistPath + ".boo"  + File.pathSeparator +
+                                 appJar,
+                                 "-Xlog:class+path=trace",
+                                 "Hello"))
+            .assertNormalExit();
+
+        // Or, remove all non-existent paths from the CP, it should still work
+        TestCommon.run(make_args(bootcp,
+                                 appJar,
+                                 "-Xlog:class+path=trace",
+                                 "Hello"))
+            .assertNormalExit();
+
+        // Now make nonExistPath exist. CDS will fail to load.
+        Files.copy(Paths.get(classDir, "hello.jar"),
+                   Paths.get(classDir, newFile),
+                   StandardCopyOption.REPLACE_EXISTING);
+
+        TestCommon.run(make_args(bootcp,
+                                 classPath,
+                                 "-Xlog:class+path=trace",
+                                 "Hello"))
+            .assertAbnormalExit(errorMessage1, errorMessage2, errorMessage3);
+    }
+
+    static String[] make_args(boolean bootcp, String cp, String... suffix) {
+        String args[];
+        if (bootcp) {
+            args = TestCommon.concat("-Xbootclasspath/a:" + cp);
+        } else {
+            args = TestCommon.concat("-cp", cp);
+        }
+
+        return TestCommon.concat(args, suffix);
+    }
+}
--- a/test/hotspot/jtreg/runtime/cds/appcds/SharedArchiveConsistency.java	Tue Aug 27 22:14:15 2019 -0700
+++ b/test/hotspot/jtreg/runtime/cds/appcds/SharedArchiveConsistency.java	Tue Aug 27 22:14:52 2019 -0700
@@ -61,7 +61,6 @@
     public static int offset_version;   // CDSFileMapHeaderBase::_version
     public static int offset_jvm_ident; // FileMapHeader::_jvm_ident
     public static int sp_offset_crc;    // CDSFileMapRegion::_crc
-    public static int offset_paths_misc_info_size;
     public static int file_header_size = -1;// total size of header, variant, need calculation
     public static int CDSFileMapRegion_size; // size of CDSFileMapRegion
     public static int sp_offset;       // offset of CDSFileMapRegion
@@ -117,12 +116,6 @@
         // this is not real header size, it is struct size
         int_size = wb.getOffsetForName("int_size");
         file_header_size = wb.getOffsetForName("file_header_size");
-        offset_paths_misc_info_size = wb.getOffsetForName("FileMapHeader::_paths_misc_info_size") -
-            offset_magic;
-        int path_misc_info_size   = (int)readInt(fc, offset_paths_misc_info_size, int_size);
-        file_header_size += path_misc_info_size;
-        System.out.println("offset_paths_misc_info_size = " + offset_paths_misc_info_size);
-        System.out.println("path_misc_info_size   = " + path_misc_info_size);
         System.out.println("file_header_size      = " + file_header_size);
         file_header_size = (int)align_up_page(file_header_size);
         System.out.println("file_header_size (aligned to page) = " + file_header_size);
@@ -405,10 +398,9 @@
         output.shouldNotContain("Checksum verification failed");
 
         copyFile(orgJsaFile, jsa);
-        // modify _jvm_ident and _paths_misc_info_size, test should fail
-        System.out.println("\n2a. Corrupt _jvm_ident and _paths_misc_info_size, should fail\n");
+        // modify _jvm_ident, test should fail
+        System.out.println("\n2a. Corrupt _jvm_ident, should fail\n");
         modifyJvmIdent();
-        modifyHeaderIntField(offset_paths_misc_info_size, Integer.MAX_VALUE);
         output = TestCommon.execCommon(execArgs);
         output.shouldContain("The shared archive file was created by a different version or build of HotSpot");
         output.shouldNotContain("Checksum verification failed");
@@ -422,19 +414,17 @@
         output.shouldContain("Hello World");
 
         copyFile(orgJsaFile, jsa);
-        // modify _magic and _paths_misc_info_size, test should fail
-        System.out.println("\n2c. Corrupt _magic and _paths_misc_info_size, should fail\n");
+        // modify _magic, test should fail
+        System.out.println("\n2c. Corrupt _magic, should fail\n");
         modifyHeaderIntField(offset_magic, 0x00000000);
-        modifyHeaderIntField(offset_paths_misc_info_size, Integer.MAX_VALUE);
         output = TestCommon.execCommon(execArgs);
         output.shouldContain("The shared archive file has a bad magic number");
         output.shouldNotContain("Checksum verification failed");
 
         copyFile(orgJsaFile, jsa);
-        // modify _version and _paths_misc_info_size, test should fail
-        System.out.println("\n2d. Corrupt _version and _paths_misc_info_size, should fail\n");
+        // modify _version, test should fail
+        System.out.println("\n2d. Corrupt _version, should fail\n");
         modifyHeaderIntField(offset_version, 0x00000000);
-        modifyHeaderIntField(offset_paths_misc_info_size, Integer.MAX_VALUE);
         output = TestCommon.execCommon(execArgs);
         output.shouldContain("The shared archive file has the wrong version");
         output.shouldNotContain("Checksum verification failed");
--- a/test/hotspot/jtreg/runtime/cds/appcds/TraceLongClasspath.java	Tue Aug 27 22:14:15 2019 -0700
+++ b/test/hotspot/jtreg/runtime/cds/appcds/TraceLongClasspath.java	Tue Aug 27 22:14:52 2019 -0700
@@ -24,7 +24,7 @@
 
 /*
  * @test
- * @summary ensure -XX:+TraceClassPaths showing entire expecting app classpath
+ * @summary ensure -Xlog:class+path showing entire expecting app classpath
  * @requires vm.cds
  * @library /test/lib
  * @modules jdk.jartool/sun.tools.jar
@@ -85,22 +85,23 @@
             "/scratch/xxxx/yyyy/ZZZZZZ/aaaaaaaaaa/jdk/lib/tools.jar" + ps +
             "/scratch/xxxx/yyyy/ZZZZZZ/aaaaaaaaaa/xx/foobar_common/modules/foobar.ooo_12.1.3/ooo-manifest.jar";
 
-        String myCP = longClassPath + ps + appJar;
+        String dumpCP = longClassPath + ps + appJar;
         // Dump an archive with a specified JAR file in -classpath
-        TestCommon.testDump(myCP, TestCommon.list("Hello"));
+        TestCommon.testDump(dumpCP, TestCommon.list("Hello"));
 
-        // 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.
+        // Then try to execute the archive with a different classpath and with -Xlog:class+path.
+        // The diagnostic "expecting" app classpath trace should show the entire classpath (excluding any non-existent dump-time paths).
+        String recordedCP = dummyJar + ps + appJar;
         TestCommon.run(
-            "-XX:+TraceClassPaths", "-Xlog:cds",
+            "-Xlog:class+path", "-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
+                // the "expecting" app classpath from -Xlog:class+path should not
                 // be truncated
-                output.shouldContain(myCP);
+                output.shouldContain(recordedCP);
               });
     }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/cds/appcds/test-classes/CpAttr6.java	Tue Aug 27 22:14:52 2019 -0700
@@ -0,0 +1,29 @@
+/*
+ * 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.
+ *
+ */
+
+public class CpAttr6 {
+    public static void main(String args[]) {
+        System.out.println("Test passed");
+    }
+}