8136930: Simplify use of module-system options by custom launchers

Reviewed-by: coleenp, lfoltan, mchung
This commit is contained in:
Harold Seigel 2016-08-10 15:48:04 -07:00
parent bb1bd02549
commit d7ea24479b
47 changed files with 668 additions and 288 deletions

View file

@ -110,7 +110,7 @@ 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;
bool Arguments::_has_jimage = false;
@ -161,6 +161,30 @@ static void logOption(const char* opt) {
}
}
bool needs_module_property_warning = false;
#define MODULE_PROPERTY_PREFIX "jdk.module"
#define MODULE_PROPERTY_PREFIX_LEN 10
#define MODULE_MAIN_PROPERTY "jdk.module.main"
#define MODULE_MAIN_PROPERTY_LEN 15
// Return TRUE if option matches property, or property=, or property..
static bool matches_property_prefix(const char* option, const char* property, size_t len) {
return (strncmp(option, property, len) == 0) &&
(option[len] == '=' || option[len] == '.' || option[len] == '\0');
}
// Return true if the property is either "jdk.module" or starts with "jdk.module.",
// but does not start with "jdk.module.main".
// Return false if jdk.module.main because jdk.module.main and jdk.module.main.class
// are valid non-internal system properties.
// "property" should be passed without the leading "-D".
bool Arguments::is_internal_module_property(const char* property) {
assert((strncmp(property, "-D", 2) != 0), "Unexpected leading -D");
return (matches_property_prefix(property, MODULE_PROPERTY_PREFIX, MODULE_PROPERTY_PREFIX_LEN) &&
!matches_property_prefix(property, MODULE_MAIN_PROPERTY, MODULE_MAIN_PROPERTY_LEN));
}
// Process java launcher properties.
void Arguments::process_sun_java_launcher_properties(JavaVMInitArgs* args) {
// See if sun.java.launcher, sun.java.launcher.is_altjvm or
@ -197,7 +221,7 @@ void Arguments::init_system_properties() {
_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));
@ -1198,7 +1222,7 @@ 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 = "";
@ -1228,7 +1252,9 @@ bool Arguments::add_property(const char* prop) {
// 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;
@ -1248,7 +1274,7 @@ bool Arguments::add_property(const char* prop) {
}
// 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) {
@ -1260,9 +1286,9 @@ bool Arguments::add_property(const char* prop) {
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) {
@ -1277,7 +1303,7 @@ bool Arguments::append_to_addmods_property(const char* 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;
}
@ -1287,14 +1313,14 @@ 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++) {
@ -1326,7 +1352,7 @@ void Arguments::set_mode_flags(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;
@ -2516,6 +2542,41 @@ bool Arguments::parse_uintx(const char* value,
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) {
@ -2528,7 +2589,7 @@ Arguments::ArgsRange Arguments::parse_memory_size(const char* s,
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;
@ -2545,20 +2606,20 @@ jint Arguments::parse_vm_init_args(const JavaVMInitArgs *java_tool_options_args,
// 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;
}
@ -2617,7 +2678,35 @@ bool valid_jdwp_agent(char *name, bool is_path) {
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;
@ -2701,6 +2790,34 @@ jint Arguments::parse_each_vm_init_arg(const JavaVMInitArgs* args, bool* xpatch_
#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))) {
@ -2992,6 +3109,13 @@ jint Arguments::parse_each_vm_init_arg(const JavaVMInitArgs* args, bool* xpatch_
"-Djava.ext.dirs=%s is not supported. Use -classpath instead.\n", value);
return JNI_EINVAL;
}
// Check for 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_internal_module_property(option->optionString + 2)) {
needs_module_property_warning = true;
continue;
}
if (!add_property(tail)) {
return JNI_ENOMEM;
@ -3012,33 +3136,6 @@ jint Arguments::parse_each_vm_init_arg(const JavaVMInitArgs* args, bool* xpatch_
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);
@ -3298,25 +3395,25 @@ jint Arguments::parse_each_vm_init_arg(const JavaVMInitArgs* args, bool* xpatch_
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));
}
// Remove all empty paths from the app classpath (if IgnoreEmptyClassPaths is enabled)
@ -3441,6 +3538,15 @@ jint Arguments::finalize_vm_init_args() {
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) {
if (!append_to_addmods_property(add_modules_value)) {
return JNI_ENOMEM;
}
}
// This must be done after all arguments have been processed.
// java_compiler() true means set to "NONE" or empty.
if (java_compiler() && !xdebug_mode()) {
@ -3795,9 +3901,9 @@ jint Arguments::parse_options_buffer(const char* name, char* buffer, const size_
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) {
@ -4180,6 +4286,11 @@ jint Arguments::parse(const JavaVMInitArgs* initial_cmd_args) {
hotspotrc, hotspotrc);
}
if (needs_module_property_warning) {
warning("Ignoring system property options whose names start with '-Djdk.module'."
" They are reserved for internal use.");
}
#if defined(_ALLBSD_SOURCE) || defined(AIX) // UseLargePages is not yet supported on BSD and AIX.
UNSUPPORTED_OPTION(UseLargePages);
#endif
@ -4404,6 +4515,18 @@ int Arguments::PropertyList_count(SystemProperty* pl) {
return count;
}
// Return the number of readable properties.
int Arguments::PropertyList_readable_count(SystemProperty* pl) {
int count = 0;
while(pl != NULL) {
if (pl->is_readable()) {
count++;
}
pl = pl->next();
}
return count;
}
const char* Arguments::PropertyList_get_value(SystemProperty *pl, const char* key) {
assert(key != NULL, "just checking");
SystemProperty* prop;
@ -4413,6 +4536,27 @@ const char* Arguments::PropertyList_get_value(SystemProperty *pl, const char* ke
return NULL;
}
// Return the value of the requested property provided that it is a readable property.
const char* Arguments::PropertyList_get_readable_value(SystemProperty *pl, const char* key) {
assert(key != NULL, "just checking");
SystemProperty* prop;
// Return the property value if the keys match and the property is not internal or
// it's the special internal property "jdk.boot.class.path.append".
for (prop = pl; prop != NULL; prop = prop->next()) {
if (strcmp(key, prop->key()) == 0) {
if (!prop->internal()) {
return prop->value();
} else if (strcmp(key, "jdk.boot.class.path.append") == 0) {
return prop->value();
} else {
// Property is internal and not jdk.boot.class.path.append so return NULL.
return NULL;
}
}
}
return NULL;
}
const char* Arguments::PropertyList_get_key_at(SystemProperty *pl, int index) {
int count = 0;
const char* ret_val = NULL;
@ -4457,11 +4601,12 @@ void Arguments::PropertyList_add(SystemProperty** plist, SystemProperty *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);
}
@ -4470,7 +4615,9 @@ void Arguments::PropertyList_add(SystemProperty *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;
@ -4478,16 +4625,16 @@ void Arguments::PropertyList_unique_add(SystemProperty** plist, const char* k, c
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