--- old/src/share/vm/runtime/arguments.cpp 2016-07-15 07:00:13.882973891 +0100 +++ new/src/share/vm/runtime/arguments.cpp 2016-07-15 07:00:13.776966648 +0100 @@ -111,7 +111,7 @@ SystemProperty *Arguments::_java_class_path = NULL; SystemProperty *Arguments::_jdk_boot_class_path_append = NULL; -GrowableArray *Arguments::_xpatchprefix = NULL; +GrowableArray *Arguments::_patch_mod_prefix = NULL; PathString *Arguments::_system_boot_class_path = NULL; char* Arguments::_ext_dirs = NULL; @@ -140,6 +140,83 @@ } } +#define MODULE_PROPERTY_PREFIX "jdk.module" +#define MODULE_PROPERTY_PREFIX_LEN 10 +#define ADDEXPORTS "addexports" +#define ADDEXPORTS_LEN 10 +#define ADDREADS "addreads" +#define ADDREADS_LEN 8 +#define PATCH "patch" +#define PATCH_LEN 5 +#define ADDMODS "addmods" +#define ADDMODS_LEN 7 +#define LIMITMODS "limitmods" +#define LIMITMODS_LEN 9 +#define PATH "path" +#define PATH_LEN 4 +#define UPGRADE_PATH "upgrade.path" +#define UPGRADE_PATH_LEN 12 + +// Return TRUE if option matches property. or matches property.=. +static bool is_matching_numbered_property(const char* option, const char* property, size_t len) { + if (strncmp(option, property, len) == 0) { + // Check for digits. + const char* sptr = option + len; + if (isdigit(*sptr)) { // Make sure next char is a digit. + while (isdigit(*sptr)) { + sptr++; + if (*sptr == '=' || *sptr == '\0') { + return true; + } + } + } + } + return false; +} + +// Return TRUE if option matches property or matches property=. +static bool is_matching_property(const char* option, const char* property, size_t len) { + return (strncmp(option, property, len) == 0) && (option[len] == '=' || option[len] == '\0'); +} + +// Return true if option_end is the name of a module-related java property +// with "-Djdk.module." removed. +static bool is_internal_module_property_end(const char* option_end) { + // For the repeating properties such as (-Djdk.module.patch.0 + // -Djdk.module.patch.1, etc) return true for ".[=]". + if (is_matching_numbered_property(option_end, ADDEXPORTS ".", ADDEXPORTS_LEN + 1) || + is_matching_numbered_property(option_end, ADDREADS ".", ADDREADS_LEN + 1) || + is_matching_numbered_property(option_end, PATCH ".", PATCH_LEN + 1)) { + return true; + } + return (is_matching_property(option_end, ADDMODS, ADDMODS_LEN) || + is_matching_property(option_end, LIMITMODS, LIMITMODS_LEN)); +} + +// Return true if the option is one of the module-related java properties +// that can only be set using the proper module-related option. +static bool is_module_property(const JavaVMOption *option) { + if (strncmp(option->optionString, "-D" MODULE_PROPERTY_PREFIX ".", MODULE_PROPERTY_PREFIX_LEN + 3) == 0) { + const char* option_end = option->optionString + MODULE_PROPERTY_PREFIX_LEN + 3; + return (is_internal_module_property_end(option_end) || + is_matching_property(option_end, PATH, PATH_LEN) || + is_matching_property(option_end, UPGRADE_PATH, UPGRADE_PATH_LEN)); + } + return false; +} + +// Return true if the option is one of the module-related java properties +// that can only be set using the proper module-related option and cannot +// be read by jvmti. +// It's expected that the caller removed the leading "-D" from 'option'. +bool Arguments::is_internal_module_property(const char* option) { + assert((strncmp(option, "-D", 2) != 0), "Unexpected leading -D"); + if (strncmp(option, MODULE_PROPERTY_PREFIX ".", MODULE_PROPERTY_PREFIX_LEN + 1) == 0) { + return is_internal_module_property_end(option + MODULE_PROPERTY_PREFIX_LEN + 1); + } + return false; +} + // Return true if any of the strings in null-terminated array 'names' matches. // If tail_allowed is true, then the tail must begin with a colon; otherwise, // the option must match exactly. @@ -197,7 +274,7 @@ _system_boot_class_path = new PathString(NULL); PropertyList_add(&_system_properties, new SystemProperty("java.vm.specification.name", - "Java Virtual Machine Specification", false)); + "Java Virtual Machine Specification", false)); PropertyList_add(&_system_properties, new SystemProperty("java.vm.version", VM_Version::vm_release(), false)); PropertyList_add(&_system_properties, new SystemProperty("java.vm.name", VM_Version::vm_name(), false)); PropertyList_add(&_system_properties, new SystemProperty("java.vm.info", VM_Version::vm_info_string(), true)); @@ -1199,7 +1276,7 @@ return PropertyList_get_value(system_properties(), key); } -bool Arguments::add_property(const char* prop) { +bool Arguments::add_property(const char* prop, PropertyWriteable writeable, PropertyInternal internal) { const char* eq = strchr(prop, '='); const char* key; const char* value = ""; @@ -1229,7 +1306,9 @@ // private and are processed in process_sun_java_launcher_properties(); // the sun.java.launcher property is passed on to the java application } else if (strcmp(key, "sun.boot.library.path") == 0) { - PropertyList_unique_add(&_system_properties, key, value, true); + // append is true, writable is true, internal is false + PropertyList_unique_add(&_system_properties, key, value, AppendProperty, + WriteableProperty, ExternalProperty); } else { if (strcmp(key, "sun.java.command") == 0) { char *old_java_command = _java_command; @@ -1249,7 +1328,7 @@ } // Create new property and add at the end of the list - PropertyList_unique_add(&_system_properties, key, value); + PropertyList_unique_add(&_system_properties, key, value, AddProperty, writeable, internal); } if (key != prop) { @@ -1261,9 +1340,9 @@ return true; } -// sets or adds a module name to the jdk.launcher.addmods property +// sets or adds a module name to the jdk.module.addmods property bool Arguments::append_to_addmods_property(const char* module_name) { - const char* key = "jdk.launcher.addmods"; + const char* key = "jdk.module.addmods"; const char* old_value = Arguments::get_property(key); size_t buf_len = strlen(key) + strlen(module_name) + 2; if (old_value != NULL) { @@ -1278,7 +1357,7 @@ } else { jio_snprintf(new_value, buf_len, "%s=%s,%s", key, old_value, module_name); } - bool added = add_property(new_value); + bool added = add_property(new_value, UnwriteableProperty, InternalProperty); FreeHeap(new_value); return added; } @@ -1288,14 +1367,14 @@ assert(DumpSharedSpaces, "this function is only used with -Xshare:dump"); const char* unsupported_properties[5] = { "jdk.module.main", "jdk.module.path", - "jdk.upgrade.module.path", - "jdk.launcher.addmods", - "jdk.launcher.limitmods" }; + "jdk.module.upgrade.path", + "jdk.module.addmods", + "jdk.module.limitmods" }; const char* unsupported_options[5] = { "-m", - "-modulepath", - "-upgrademodulepath", - "-addmods", - "-limitmods" }; + "--module-path", + "--upgrade-module-path", + "--add-modules", + "--limit-modules" }; SystemProperty* sp = system_properties(); while (sp != NULL) { for (int i = 0; i < 5; i++) { @@ -1322,7 +1401,7 @@ // Ensure Agent_OnLoad has the correct initial values. // This may not be the final mode; mode may change later in onload phase. PropertyList_unique_add(&_system_properties, "java.vm.info", - VM_Version::vm_info_string(), false); + VM_Version::vm_info_string(), AddProperty, UnwriteableProperty, ExternalProperty); UseInterpreter = true; UseCompiler = true; @@ -2520,6 +2599,41 @@ return false; } +unsigned int addreads_count = 0; +unsigned int addexports_count = 0; +unsigned int patch_mod_count = 0; +const char* add_modules_value = NULL; + +bool Arguments::create_property(const char* prop_name, const char* prop_value, PropertyInternal internal) { + size_t prop_len = strlen(prop_name) + strlen(prop_value) + 2; + char* property = AllocateHeap(prop_len, mtArguments); + int ret = jio_snprintf(property, prop_len, "%s=%s", prop_name, prop_value); + if (ret < 0 || ret >= (int)prop_len) { + FreeHeap(property); + return false; + } + bool added = add_property(property, UnwriteableProperty, internal); + FreeHeap(property); + return added; +} + +bool Arguments::create_numbered_property(const char* prop_base_name, const char* prop_value, unsigned int count) { + // Make sure count is < 1,000. Otherwise, memory allocation will be too small. + if (count < 1000) { + size_t prop_len = strlen(prop_base_name) + strlen(prop_value) + 5; + char* property = AllocateHeap(prop_len, mtArguments); + int ret = jio_snprintf(property, prop_len, "%s.%d=%s", prop_base_name, count, prop_value); + if (ret < 0 || ret >= (int)prop_len) { + FreeHeap(property); + return false; + } + bool added = add_property(property, UnwriteableProperty, InternalProperty); + FreeHeap(property); + return added; + } + return false; +} + Arguments::ArgsRange Arguments::parse_memory_size(const char* s, julong* long_arg, julong min_size) { @@ -2532,7 +2646,7 @@ jint Arguments::parse_vm_init_args(const JavaVMInitArgs *java_tool_options_args, const JavaVMInitArgs *java_options_args, const JavaVMInitArgs *cmd_line_args) { - bool xpatch_javabase = false; + bool patch_mod_javabase = false; // Save default settings for some mode flags Arguments::_AlwaysCompileLoopMethods = AlwaysCompileLoopMethods; @@ -2549,20 +2663,20 @@ // Parse args structure generated from JAVA_TOOL_OPTIONS environment // variable (if present). - jint result = parse_each_vm_init_arg(java_tool_options_args, &xpatch_javabase, Flag::ENVIRON_VAR); + jint result = parse_each_vm_init_arg(java_tool_options_args, &patch_mod_javabase, Flag::ENVIRON_VAR); if (result != JNI_OK) { return result; } // Parse args structure generated from the command line flags. - result = parse_each_vm_init_arg(cmd_line_args, &xpatch_javabase, Flag::COMMAND_LINE); + result = parse_each_vm_init_arg(cmd_line_args, &patch_mod_javabase, Flag::COMMAND_LINE); if (result != JNI_OK) { return result; } // Parse args structure generated from the _JAVA_OPTIONS environment // variable (if present) (mimics classic VM) - result = parse_each_vm_init_arg(java_options_args, &xpatch_javabase, Flag::ENVIRON_VAR); + result = parse_each_vm_init_arg(java_options_args, &patch_mod_javabase, Flag::ENVIRON_VAR); if (result != JNI_OK) { return result; } @@ -2621,7 +2735,35 @@ return false; } -jint Arguments::parse_each_vm_init_arg(const JavaVMInitArgs* args, bool* xpatch_javabase, Flag::Flags origin) { +int Arguments::process_patch_mod_option(const char* patch_mod_tail, bool* patch_mod_javabase) { + // --patch-module==()* + assert(patch_mod_tail != NULL, "Unexpected NULL patch-module value"); + // Find the equal sign between the module name and the path specification + const char* module_equal = strchr(patch_mod_tail, '='); + if (module_equal == NULL) { + jio_fprintf(defaultStream::output_stream(), "Missing '=' in --patch-module specification\n"); + return JNI_ERR; + } else { + // Pick out the module name + size_t module_len = module_equal - patch_mod_tail; + char* module_name = NEW_C_HEAP_ARRAY_RETURN_NULL(char, module_len+1, mtArguments); + if (module_name != NULL) { + memcpy(module_name, patch_mod_tail, module_len); + *(module_name + module_len) = '\0'; + // The path piece begins one past the module_equal sign + add_patch_mod_prefix(module_name, module_equal + 1, patch_mod_javabase); + FREE_C_HEAP_ARRAY(char, module_name); + if (!create_numbered_property("jdk.module.patch", patch_mod_tail, patch_mod_count++)) { + return JNI_ENOMEM; + } + } else { + return JNI_ENOMEM; + } + } + return JNI_OK; +} + +jint Arguments::parse_each_vm_init_arg(const JavaVMInitArgs* args, bool* patch_mod_javabase, Flag::Flags origin) { // For match_option to return remaining or value part of option string const char* tail; @@ -2706,6 +2848,34 @@ #endif // !INCLUDE_JVMTI add_init_library(name, options); } + } else if (match_option(option, "--add-reads=", &tail)) { + if (!create_numbered_property("jdk.module.addreads", tail, addreads_count++)) { + return JNI_ENOMEM; + } + } else if (match_option(option, "--add-exports=", &tail)) { + if (!create_numbered_property("jdk.module.addexports", tail, addexports_count++)) { + return JNI_ENOMEM; + } + } else if (match_option(option, "--add-modules=", &tail)) { + add_modules_value = tail; + } else if (match_option(option, "--limit-modules=", &tail)) { + if (!create_property("jdk.module.limitmods", tail, InternalProperty)) { + return JNI_ENOMEM; + } + } else if (match_option(option, "--module-path=", &tail)) { + if (!create_property("jdk.module.path", tail, ExternalProperty)) { + return JNI_ENOMEM; + } + } else if (match_option(option, "--upgrade-module-path=", &tail)) { + if (!create_property("jdk.module.upgrade.path", tail, ExternalProperty)) { + return JNI_ENOMEM; + } + } else if (match_option(option, "--patch-module=", &tail)) { + // --patch-module==()* + int res = process_patch_mod_option(tail, patch_mod_javabase); + if (res != JNI_OK) { + return res; + } // -agentlib and -agentpath } else if (match_option(option, "-agentlib:", &tail) || (is_absolute_path = match_option(option, "-agentpath:", &tail))) { @@ -2997,6 +3167,11 @@ "-Djava.ext.dirs=%s is not supported. Use -classpath instead.\n", value); return JNI_EINVAL; } + // Silently ignore module related properties. They must be set using the modules + // options. For example: use "--add-modules java.sql", not "-Djdk.module.addmods=java.sql" + if (is_module_property(option)) { + continue; + } if (!add_property(tail)) { return JNI_ENOMEM; @@ -3017,33 +3192,6 @@ return JNI_ERR; #endif } - if (match_option(option, "-Djdk.launcher.patch.", &tail)) { - // -Djdk.launcher.patch.#==()* - // The number, #, specified will be increasing with each -Xpatch - // specified on the command line. - // Pick up module name, following the -D property's equal sign. - const char* property_equal = strchr(tail, '='); - if (property_equal == NULL) { - jio_fprintf(defaultStream::output_stream(), "Missing '=' in -Xpatch specification\n"); - return JNI_ERR; - } else { - // Find the equal sign between the module name and the path specification - const char* module_equal = strchr(property_equal + 1, '='); - if (module_equal == NULL) { - jio_fprintf(defaultStream::output_stream(), "Bad value for -Xpatch, no module name specified\n"); - return JNI_ERR; - } else { - // Pick out the module name, in between the two equal signs - size_t module_len = module_equal - property_equal - 1; - char* module_name = NEW_C_HEAP_ARRAY(char, module_len+1, mtArguments); - memcpy(module_name, property_equal + 1, module_len); - *(module_name + module_len) = '\0'; - // The path piece begins one past the module_equal sign - Arguments::add_xpatchprefix(module_name, module_equal + 1, xpatch_javabase); - FREE_C_HEAP_ARRAY(char, module_name); - } - } - } // -Xint } else if (match_option(option, "-Xint")) { set_mode_flags(_int); @@ -3303,25 +3451,25 @@ return JNI_OK; } -void Arguments::add_xpatchprefix(const char* module_name, const char* path, bool* xpatch_javabase) { - // For java.base check for duplicate -Xpatch options being specified on the command line. +void Arguments::add_patch_mod_prefix(const char* module_name, const char* path, bool* patch_mod_javabase) { + // For java.base check for duplicate --patch-module options being specified on the command line. // This check is only required for java.base, all other duplicate module specifications // will be checked during module system initialization. The module system initialization // will throw an ExceptionInInitializerError if this situation occurs. if (strcmp(module_name, "java.base") == 0) { - if (*xpatch_javabase) { - vm_exit_during_initialization("Cannot specify java.base more than once to -Xpatch"); + if (*patch_mod_javabase) { + vm_exit_during_initialization("Cannot specify java.base more than once to --patch-module"); } else { - *xpatch_javabase = true; + *patch_mod_javabase = true; } } - // Create GrowableArray lazily, only if -Xpatch has been specified - if (_xpatchprefix == NULL) { - _xpatchprefix = new (ResourceObj::C_HEAP, mtArguments) GrowableArray(10, true); + // Create GrowableArray lazily, only if --patch-module has been specified + if (_patch_mod_prefix == NULL) { + _patch_mod_prefix = new (ResourceObj::C_HEAP, mtArguments) GrowableArray(10, true); } - _xpatchprefix->push(new ModuleXPatchPath(module_name, path)); + _patch_mod_prefix->push(new ModulePatchPath(module_name, path)); } // Set property jdk.boot.class.path.append to the contents of the bootclasspath @@ -3458,6 +3606,13 @@ return JNI_ERR; } + // Append the value of the last --add-modules option specified on the command line. + // This needs to be done here, to prevent overwriting possible values written + // to the jdk.module.addmods property by -javaagent and other options. + if (add_modules_value != NULL) { + append_to_addmods_property(add_modules_value); + } + Arguments::set_bootclassloader_append_index(((int)strlen(Arguments::get_sysclasspath()))+1); // This must be done after all arguments have been processed. @@ -3814,9 +3969,9 @@ void Arguments::set_shared_spaces_flags() { if (DumpSharedSpaces) { - if (Arguments::get_xpatchprefix() != NULL) { + if (Arguments::get_patch_mod_prefix() != NULL) { vm_exit_during_initialization( - "Cannot use the following option when dumping the shared archive", "-Xpatch"); + "Cannot use the following option when dumping the shared archive: --patch-module"); } if (RequireSharedSpaces) { @@ -4476,11 +4631,12 @@ } } -void Arguments::PropertyList_add(SystemProperty** plist, const char* k, const char* v) { +void Arguments::PropertyList_add(SystemProperty** plist, const char* k, const char* v, + bool writeable, bool internal) { if (plist == NULL) return; - SystemProperty* new_p = new SystemProperty(k, v, true); + SystemProperty* new_p = new SystemProperty(k, v, writeable, internal); PropertyList_add(plist, new_p); } @@ -4489,7 +4645,9 @@ } // This add maintains unique property key in the list. -void Arguments::PropertyList_unique_add(SystemProperty** plist, const char* k, const char* v, jboolean append) { +void Arguments::PropertyList_unique_add(SystemProperty** plist, const char* k, const char* v, + PropertyAppendable append, PropertyWriteable writeable, + PropertyInternal internal) { if (plist == NULL) return; @@ -4497,16 +4655,16 @@ SystemProperty* prop; for (prop = *plist; prop != NULL; prop = prop->next()) { if (strcmp(k, prop->key()) == 0) { - if (append) { + if (append == AppendProperty) { prop->append_value(v); } else { - prop->set_writeable_value(v); + prop->set_value(v); } return; } } - PropertyList_add(plist, k, v); + PropertyList_add(plist, k, v, writeable == WriteableProperty, internal == InternalProperty); } // Copies src into buf, replacing "%%" with "%" and "%p" with pid