--- old/src/share/vm/classfile/classLoader.cpp 2016-12-08 19:05:12.122067455 -0500 +++ new/src/share/vm/classfile/classLoader.cpp 2016-12-08 19:05:10.557978088 -0500 @@ -84,7 +84,6 @@ typedef jzentry* (JNICALL *GetNextEntry_t)(jzfile *zip, jint n); typedef jboolean (JNICALL *ZipInflateFully_t)(void *inBuf, jlong inLen, void *outBuf, jlong outLen, char **pmsg); typedef jint (JNICALL *Crc32_t)(jint crc, const jbyte *buf, jint len); -typedef void (JNICALL *FreeEntry_t)(jzfile *zip, jzentry *entry); static ZipOpen_t ZipOpen = NULL; static ZipClose_t ZipClose = NULL; @@ -94,7 +93,6 @@ static canonicalize_fn_t CanonicalizeEntry = NULL; static ZipInflateFully_t ZipInflateFully = NULL; static Crc32_t Crc32 = NULL; -static FreeEntry_t FreeEntry = NULL; // Entry points for jimage.dll for loading jimage file entries @@ -150,7 +148,6 @@ GrowableArray* ClassLoader::_boot_modules_array = NULL; GrowableArray* ClassLoader::_platform_modules_array = NULL; SharedPathsMiscInfo* ClassLoader::_shared_paths_misc_info = NULL; -int ClassLoader::_num_patch_mod_prefixes = 0; #endif // helper routines @@ -320,20 +317,6 @@ FREE_C_HEAP_ARRAY(char, _zip_name); } -bool ClassPathZipEntry::stream_exists(const char* name) { - // enable call to C land - JavaThread* thread = JavaThread::current(); - ThreadToNativeFromVM ttn(thread); - // check whether zip archive contains name - jint name_len, filesize; - jzentry* entry = (*FindEntry)(_zip, name, &filesize, &name_len); - if (entry != NULL) { - (*FreeEntry)(_zip, entry); - return true; - } - return false; -} - u1* ClassPathZipEntry::open_entry(const char* name, jint* filesize, bool nul_terminate, TRAPS) { // enable call to C land JavaThread* thread = JavaThread::current(); @@ -1090,7 +1073,6 @@ GetNextEntry = CAST_TO_FN_PTR(GetNextEntry_t, os::dll_lookup(handle, "ZIP_GetNextEntry")); ZipInflateFully = CAST_TO_FN_PTR(ZipInflateFully_t, os::dll_lookup(handle, "ZIP_InflateFully")); Crc32 = CAST_TO_FN_PTR(Crc32_t, os::dll_lookup(handle, "ZIP_CRC32")); - FreeEntry = CAST_TO_FN_PTR(FreeEntry_t, os::dll_lookup(handle, "ZIP_FreeEntry")); // ZIP_Close is not exported on Windows in JDK5.0 so don't abort if ZIP_Close is NULL if (ZipOpen == NULL || FindEntry == NULL || ReadEntry == NULL || @@ -1418,57 +1400,6 @@ return NULL; } -#if INCLUDE_CDS -// The following function is only used during CDS dump time. -// It checks if a class can be found in the jar entries of the _patch_mod_entries. -// It does not support non-jar entries. -bool ClassLoader::is_in_patch_module(const char* const file_name) { - assert(DumpSharedSpaces, "dump time only"); - if (_patch_mod_entries == NULL) { - return false; - } - - int num_of_entries = _patch_mod_entries->length(); - char* class_module_name = NULL; - ResourceMark rm; - const char *pkg_name = package_from_name(file_name); - // Using the jimage to obtain the class' module name. - // The ModuleEntryTable cannot be used at this point during dump time - // because the module system hasn't been initialized yet. - if (pkg_name != NULL) { - JImageFile *jimage = _jrt_entry->jimage(); - class_module_name = (char*)(*JImagePackageToModule)(jimage, pkg_name); - } - - if (class_module_name == NULL) { - return false; - } - - // Loop through all the patch module entries looking for module - for (int i = 0; i < num_of_entries; i++) { - ModuleClassPathList* module_cpl = _patch_mod_entries->at(i); - Symbol* module_cpl_name = module_cpl->module_name(); - - if (strcmp(module_cpl_name->as_C_string(), class_module_name) == 0) { - // Class' module has been located, attempt to locate - // the class from the module's ClassPathEntry list. - ClassPathEntry* e = module_cpl->module_first_entry(); - while (e != NULL) { - if (e->is_jar_file()) { - if (e->stream_exists(file_name)) { - return true; - } else { - e = e->next(); - } - } - } - } - } - - return false; -} -#endif // INCLUDE_CDS - instanceKlassHandle ClassLoader::load_class(Symbol* name, bool search_append_only, TRAPS) { assert(name != NULL, "invariant"); assert(THREAD->is_Java_thread(), "must be a JavaThread"); @@ -1494,8 +1425,6 @@ // If DumpSharedSpaces is true boot loader visibility boundaries are set to: // - [jimage] + [_first_append_entry to _last_append_entry] (all path entries). - // If a class is found in the --patch-module entries, the class will not be included in the - // CDS archive. Also, CDS is not supported if exploded module builds are used. // // If search_append_only is true, boot loader visibility boundaries are // set to be _first_append_entry to the end. This includes: @@ -1519,15 +1448,13 @@ // Note: The --patch-module entries are never searched if the boot loader's // visibility boundary is limited to only searching the append entries. if (_patch_mod_entries != NULL && !search_append_only) { + // At CDS dump time, the --patch-module entries are ignored. That means a + // class is still loaded from the [jimage|exploded build] even if it might + // 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. if (!DumpSharedSpaces) { stream = search_module_entries(_patch_mod_entries, class_name, file_name, CHECK_NULL); - } else { -#if INCLUDE_CDS - if (is_in_patch_module(file_name)) { - tty->print_cr("Preload Warning: Skip archiving class %s found in --patch-module entry", class_name); - return NULL; - } -#endif } } @@ -1679,57 +1606,8 @@ } #if INCLUDE_CDS -// Capture all the --patch-module entries specified during CDS dump time. -// It also captures the non-existing path(s) and the required file(s) during inspecting -// the entries. -void ClassLoader::setup_patch_mod_path() { - assert(DumpSharedSpaces, "only used with -Xshare:dump"); - ResourceMark rm; - GrowableArray* patch_mod_args = Arguments::get_patch_mod_prefix(); - if (patch_mod_args != NULL) { - int num_of_entries = patch_mod_args->length(); - for (int i = 0; i < num_of_entries; i++) { - const char* module_name = (patch_mod_args->at(i))->module_name(); - const char* module_path = (patch_mod_args->at(i))->path_string(); - int path_len = (int)strlen(module_path); - int name_len = (int)strlen(module_name); - int buf_len = name_len + path_len + 2; // add 2 for the '=' and NULL terminator - int end = 0; - char* buf = NEW_C_HEAP_ARRAY(char, buf_len, mtInternal); - // Iterate over the module's class path entries - for (int start = 0; start < path_len; start = end) { - while (module_path[end] && module_path[end] != os::path_separator()[0]) { - end++; - } - strncpy(buf, &module_path[start], end - start); - buf[end - start] = '\0'; - struct stat st; - if (os::stat(buf, &st) != 0) { - // File not found - _shared_paths_misc_info->add_nonexist_path(buf); - } else { - if ((st.st_mode & S_IFMT) != S_IFREG) { // is not a regular file - vm_exit_during_initialization( - "--patch-module requires a regular file during dumping", buf); - } else { - _shared_paths_misc_info->add_required_file(buf); - } - } - while (module_path[end] == os::path_separator()[0]) { - end++; - } - }; - jio_snprintf(buf, buf_len, "%s=%s", module_name, module_path); - _shared_paths_misc_info->add_patch_mod_classpath((const char*)buf); - _num_patch_mod_prefixes++; - FREE_C_HEAP_ARRAY(char, buf); - } - } -} - void ClassLoader::initialize_shared_path() { if (DumpSharedSpaces) { - setup_patch_mod_path(); ClassLoaderExt::setup_search_paths(); _shared_paths_misc_info->write_jint(0); // see comments in SharedPathsMiscInfo::check() } --- old/src/share/vm/classfile/classLoader.hpp 2016-12-08 19:05:16.486316815 -0500 +++ new/src/share/vm/classfile/classLoader.hpp 2016-12-08 19:05:15.078236362 -0500 @@ -69,7 +69,6 @@ // Attempt to locate file_name through this class path entry. // Returns a class file parsing stream if successfull. virtual ClassFileStream* open_stream(const char* name, TRAPS) = 0; - virtual bool stream_exists(const char* name) = 0; // Debugging NOT_PRODUCT(virtual void compile_the_world(Handle loader, TRAPS) = 0;) }; @@ -84,7 +83,6 @@ JImageFile* jimage() const { return NULL; } ClassPathDirEntry(const char* dir); ClassFileStream* open_stream(const char* name, TRAPS); - bool stream_exists(const char* name) { return false; } // Debugging NOT_PRODUCT(void compile_the_world(Handle loader, TRAPS);) }; @@ -128,7 +126,6 @@ ClassFileStream* open_stream(const char* name, TRAPS); void contents_do(void f(const char* name, void* context), void* context); bool is_multiple_versioned(TRAPS) NOT_CDS_RETURN_(false); - bool stream_exists(const char* name); // Debugging NOT_PRODUCT(void compile_the_world(Handle loader, TRAPS);) }; @@ -148,7 +145,6 @@ ClassPathImageEntry(JImageFile* jimage, const char* name); ~ClassPathImageEntry(); ClassFileStream* open_stream(const char* name, TRAPS); - bool stream_exists(const char* name) { return false; } // Debugging NOT_PRODUCT(void compile_the_world(Handle loader, TRAPS);) @@ -259,7 +255,6 @@ // Info used by CDS CDS_ONLY(static SharedPathsMiscInfo * _shared_paths_misc_info;) - CDS_ONLY(static int _num_patch_mod_prefixes;) // Initialization: // - setup the boot loader's system class path @@ -434,9 +429,6 @@ static void initialize_module_loader_map(JImageFile* jimage); static s2 classloader_type(Symbol* class_name, ClassPathEntry* e, int classpath_index, TRAPS); - static bool is_in_patch_module(const char* const file_name); - static void setup_patch_mod_path(); // Only when -Xshare:dump - static int num_patch_mod_prefixes() { return _num_patch_mod_prefixes; } #endif static void trace_class_path(const char* msg, const char* name = NULL); --- old/src/share/vm/classfile/sharedPathsMiscInfo.cpp 2016-12-08 19:05:20.782562287 -0500 +++ new/src/share/vm/classfile/sharedPathsMiscInfo.cpp 2016-12-08 19:05:19.354480692 -0500 @@ -86,9 +86,6 @@ case REQUIRED: out->print("Expecting that file %s must exist and is not altered", path); break; - case PATCH_MOD: - out->print("Expecting --patch-module=%s", path); - break; default: ShouldNotReachHere(); } @@ -166,26 +163,6 @@ } } } - break; - case PATCH_MOD: - { - GrowableArray* patch_mod_args = Arguments::get_patch_mod_prefix(); - if (patch_mod_args != NULL) { - int num_of_entries = patch_mod_args->length(); - for (int i = 0; i < num_of_entries; i++) { - const char* module_name = (patch_mod_args->at(i))->module_name(); - const char* path_string = (patch_mod_args->at(i))->path_string(); - size_t n = strlen(module_name); - // path contains the module name, followed by '=', and one or more entries. - // E.g.: "java.base=foo" or "java.naming=dir1:dir2:dir3" - if ((strncmp(module_name, path, n) != 0) || - (path[n] != '=') || - (strcmp(path + n + 1, path_string) != 0)) { - return fail("--patch-module mismatch, path not found in run time: ", path); - } - } - } - } break; default: return fail("Corrupted archive file header"); --- old/src/share/vm/classfile/sharedPathsMiscInfo.hpp 2016-12-08 19:05:25.274818959 -0500 +++ new/src/share/vm/classfile/sharedPathsMiscInfo.hpp 2016-12-08 19:05:23.862738279 -0500 @@ -104,28 +104,10 @@ add_path(path, NON_EXIST); } - // The path must exist and have required size and modification time - void add_required_file(const char* path) { - add_path(path, REQUIRED); - - struct stat st; - if (os::stat(path, &st) != 0) { - assert(0, "sanity"); -#if INCLUDE_CDS - ClassLoader::exit_with_path_failure("failed to os::stat(%s)", path); // should not happen -#endif - } - write_time(st.st_mtime); - write_long(st.st_size); - } - // The path must exist, and must contain exactly files/dirs void add_boot_classpath(const char* path) { add_path(path, BOOT); } - void add_patch_mod_classpath(const char* path) { - add_path(path, PATCH_MOD); - } int write_jint(jint num) { write(&num, sizeof(num)); return 0; @@ -147,8 +129,7 @@ enum { BOOT = 1, NON_EXIST = 2, - REQUIRED = 3, - PATCH_MOD = 4 + REQUIRED = 3 }; virtual const char* type_name(int type) { @@ -156,7 +137,6 @@ case BOOT: return "BOOT"; case NON_EXIST: return "NON_EXIST"; case REQUIRED: return "REQUIRED"; - case PATCH_MOD: return "PATCH_MOD"; default: ShouldNotReachHere(); return "?"; } } --- old/src/share/vm/classfile/systemDictionary.cpp 2016-12-08 19:05:29.571064422 -0500 +++ new/src/share/vm/classfile/systemDictionary.cpp 2016-12-08 19:05:28.150983285 -0500 @@ -1222,6 +1222,8 @@ bool SystemDictionary::is_shared_class_visible(Symbol* class_name, instanceKlassHandle ik, Handle class_loader, TRAPS) { + assert(!ModuleEntryTable::javabase_moduleEntry()->is_patched(), + "Cannot use sharing if java.base is patched"); ResourceMark rm; int path_index = ik->shared_classpath_index(); SharedClassPathEntry* ent = @@ -1249,6 +1251,12 @@ } } + // If the archived class is from a module that has been patched at runtime, + // the class cannot be loaded from the archive. + if (mod_entry != NULL && mod_entry->is_patched()) { + return false; + } + if (class_loader.is_null()) { assert(ent != NULL, "Shared class for NULL classloader must have valid SharedClassPathEntry"); // The NULL classloader can load archived class originated from the --- old/src/share/vm/memory/filemap.cpp 2016-12-08 19:05:34.215329774 -0500 +++ new/src/share/vm/memory/filemap.cpp 2016-12-08 19:05:32.815249780 -0500 @@ -179,7 +179,6 @@ _classpath_entry_table_size = mapinfo->_classpath_entry_table_size; _classpath_entry_table = mapinfo->_classpath_entry_table; _classpath_entry_size = mapinfo->_classpath_entry_size; - _num_patch_mod_prefixes = ClassLoader::num_patch_mod_prefixes(); // The following fields are for sanity checks for whether this archive // will function correctly with this JVM and the bootclasspath it's @@ -948,23 +947,6 @@ return false; } - // Check if there is a mismatch in --patch-module entry counts between dump time and run time. - // More checks will be performed on individual --patch-module entry in the - // SharedPathsMiscInfo::check() function. - GrowableArray* patch_mod_args = Arguments::get_patch_mod_prefix(); - if (patch_mod_args != NULL) { - if (_num_patch_mod_prefixes == 0) { - FileMapInfo::fail_stop("--patch-module found in run time but none was specified in dump time"); - } - if (patch_mod_args->length() != _num_patch_mod_prefixes) { - FileMapInfo::fail_stop("mismatched --patch-module entry counts between dump time and run time"); - } - } else { - if (_num_patch_mod_prefixes > 0) { - FileMapInfo::fail_stop("--patch-module specified in dump time but none was specified in run time"); - } - } - return true; } --- old/src/share/vm/memory/filemap.hpp 2016-12-08 19:05:38.699585983 -0500 +++ new/src/share/vm/memory/filemap.hpp 2016-12-08 19:05:37.279504849 -0500 @@ -155,7 +155,6 @@ // loading failures during runtime. int _classpath_entry_table_size; size_t _classpath_entry_size; - int _num_patch_mod_prefixes; // number of --patch-module entries SharedClassPathEntry* _classpath_entry_table; char* region_addr(int idx); --- old/src/share/vm/runtime/arguments.cpp 2016-12-08 19:05:42.975830304 -0500 +++ new/src/share/vm/runtime/arguments.cpp 2016-12-08 19:05:41.563749623 -0500 @@ -1321,12 +1321,15 @@ "jdk.module.limitmods", "jdk.module.path", "jdk.module.upgrade.path", - "jdk.module.addmods.0" }; - const char* unsupported_options[] = { "-m", - "--limit-modules", - "--module-path", - "--upgrade-module-path", - "--add-modules" }; + "jdk.module.addmods.0", + "jdk.module.patch.0" }; + const char* unsupported_options[] = { "-m", // cannot use at dump time + "--limit-modules", // cannot use at dump time + "--module-path", // ignored at dump time + "--upgrade-module-path", // ignored at dump time + "--add-modules", // ignored at dump time + "--patch-module" // ignored at dump time + }; assert(ARRAY_SIZE(unsupported_properties) == ARRAY_SIZE(unsupported_options), "must be"); // If a vm option is found in the unsupported_options array with index less than the warning_idx, // vm will exit with an error message. Otherwise, it will result in a warning message. @@ -1417,10 +1420,8 @@ } } -#if defined(COMPILER2) || INCLUDE_JVMCI || defined(_LP64) || !INCLUDE_CDS // Conflict: required to use shared spaces (-Xshare:on), but // incompatible command line options were chosen. - static void no_shared_spaces(const char* message) { if (RequireSharedSpaces) { jio_fprintf(defaultStream::error_stream(), @@ -1430,7 +1431,6 @@ FLAG_SET_DEFAULT(UseSharedSpaces, false); } } -#endif // Returns threshold scaled with the value of scale. // If scale < 0.0, threshold is returned without scaling. @@ -2652,6 +2652,12 @@ return result; } +#if INCLUDE_CDS + if (UseSharedSpaces && patch_mod_javabase) { + no_shared_spaces("CDS is disabled when " JAVA_BASE_NAME " module is patched."); + } +#endif + return JNI_OK; } @@ -4376,7 +4382,6 @@ } jint Arguments::apply_ergo() { - // Set flags based on ergonomics. set_ergonomics_flags(); --- old/test/runtime/modules/PatchModule/PatchModuleCDS.java 2016-12-08 19:05:47.348080107 -0500 +++ new/test/runtime/modules/PatchModule/PatchModuleCDS.java 2016-12-08 19:05:45.939999659 -0500 @@ -52,7 +52,7 @@ new OutputAnalyzer(pb.start()) .shouldContain("ro space:"); // Make sure archive got created. - // Case 2: Test that only jar file in --patch-module is supported for CDS dumping + // Case 2: Test that directory in --patch-module is supported for CDS dumping // Create a class file in the module java.base. String source = "package javax.naming.spi; " + "public class NamingManager { " + @@ -73,7 +73,7 @@ "-Xlog:class+path=info", "-version"); new OutputAnalyzer(pb.start()) - .shouldContain("--patch-module requires a regular file during dumping"); + .shouldContain("ro space:"); // Make sure archive got created. // Case 3a: Test CDS dumping with jar file in --patch-module BasicJarBuilder.build("javanaming", "javax/naming/spi/NamingManager");