< prev index next >
src/share/vm/runtime/arguments.cpp
Print this page
@@ -109,11 +109,11 @@
SystemProperty *Arguments::_java_library_path = NULL;
SystemProperty *Arguments::_java_home = NULL;
SystemProperty *Arguments::_java_class_path = NULL;
SystemProperty *Arguments::_jdk_boot_class_path_append = NULL;
-GrowableArray<ModuleXPatchPath*> *Arguments::_xpatchprefix = NULL;
+GrowableArray<ModulePatchPath*> *Arguments::_patch_mod_prefix = NULL;
PathString *Arguments::_system_boot_class_path = NULL;
char* Arguments::_ext_dirs = NULL;
// Check if head of 'option' matches 'name', and sets 'tail' to the remaining
@@ -138,10 +138,87 @@
} else {
return false;
}
}
+#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.<digits> or matches property.<digits>=.
+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 "<property_name>.<digit>[=]".
+ 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.
static bool match_option(const JavaVMOption* option, const char** names, const char** tail,
bool tail_allowed) {
@@ -1197,11 +1274,11 @@
const char* Arguments::get_property(const char* key) {
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 = "";
if (eq == NULL) {
@@ -1227,11 +1304,13 @@
strcmp(key, "sun.java.launcher.pid") == 0) {
// sun.java.launcher.is_altjvm and sun.java.launcher.pid property are
// 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;
_java_command = os::strdup_check_oom(value, mtArguments);
if (old_java_command != NULL) {
@@ -1247,11 +1326,11 @@
os::free((void *)old_java_vendor_url_bug);
}
}
// 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) {
// SystemProperty copy passed value, thus free previously allocated
// memory
@@ -1259,13 +1338,13 @@
}
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) {
buf_len += strlen(old_value) + 1;
}
@@ -1276,28 +1355,28 @@
if (old_value == NULL) {
jio_snprintf(new_value, buf_len, "%s=%s", key, module_name);
} 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;
}
#if INCLUDE_CDS
void Arguments::check_unsupported_dumping_properties() {
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++) {
if (strcmp(sp->key(), unsupported_properties[i]) == 0) {
vm_exit_during_initialization(
@@ -1320,11 +1399,11 @@
_mode = mode;
// 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;
UseLoopCounter = true;
@@ -2518,10 +2597,45 @@
}
}
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) {
if (!atojulong(s, long_arg)) return arg_unreadable;
return check_memory_size(*long_arg, min_size);
@@ -2530,11 +2644,11 @@
// Parse JavaVMInitArgs structure
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;
Arguments::_UseOnStackReplacement = UseOnStackReplacement;
Arguments::_ClipInlining = ClipInlining;
@@ -2547,24 +2661,24 @@
// Setup flags for mixed which is the default
set_mode_flags(_mixed);
// 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;
}
// Do final processing now that all arguments have been parsed
@@ -2619,11 +2733,39 @@
}
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=<module>=<file>(<pathsep><file>)*
+ 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;
// iterate over arguments
for (int index = 0; index < args->nOptions; index++) {
@@ -2704,10 +2846,38 @@
return JNI_ERR;
}
#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=<module>=<file>(<pathsep><file>)*
+ 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))) {
if(tail != NULL) {
const char* pos = strchr(tail, '=');
@@ -2995,10 +3165,15 @@
// abort if -Djava.ext.dirs is set
jio_fprintf(defaultStream::output_stream(),
"-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;
}
// Out of the box management support
@@ -3015,37 +3190,10 @@
jio_fprintf(defaultStream::output_stream(),
"-Dcom.sun.management is not supported in this VM.\n");
return JNI_ERR;
#endif
}
- if (match_option(option, "-Djdk.launcher.patch.", &tail)) {
- // -Djdk.launcher.patch.#=<module>=<file>(<pathsep><file>)*
- // 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);
// -Xmixed
} else if (match_option(option, "-Xmixed")) {
@@ -3301,29 +3449,29 @@
#endif // LINUX
fix_appclasspath();
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<ModuleXPatchPath*>(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<ModulePatchPath*>(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
// that follows either the jimage file or exploded module directories. The
// property will contain -Xbootclasspath/a and/or jvmti appended additions.
@@ -3456,10 +3604,17 @@
"Use -classpath instead.\n.");
os::closedir(dir);
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.
// java_compiler() true means set to "NONE" or empty.
if (java_compiler() && !xdebug_mode()) {
@@ -3812,13 +3967,13 @@
return status;
}
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) {
warning("Cannot dump shared archive while using shared archive");
}
@@ -4474,41 +4629,44 @@
}
p->set_next(new_p);
}
}
-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);
}
void Arguments::PropertyList_add(SystemProperty *element) {
PropertyList_add(&_system_properties, element);
}
// 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;
// If property key exist then update with new value.
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
// Returns true if all of the source pointed by src has been copied over to
// the destination buffer pointed by buf. Otherwise, returns false.
< prev index next >