< prev index next >

src/share/vm/runtime/arguments.cpp

Print this page
rev 11608 : Harold's patch v1
rev 11609 : imported patch bug_8136930.hs2.patch

@@ -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

@@ -159,10 +159,34 @@
   if (PrintVMOptions) {
     jio_fprintf(defaultStream::output_stream(), "VM option '%s'\n", 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
   // sun.java.launcher.pid is defined.
   // Must do this before setting up other system properties,

@@ -1196,11 +1220,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) {

@@ -1226,11 +1250,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) {

@@ -1246,11 +1272,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

@@ -1258,13 +1284,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;
   }

@@ -1275,28 +1301,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(

@@ -1319,11 +1345,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;
 

@@ -2517,10 +2543,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);

@@ -2529,11 +2590,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;

@@ -2546,24 +2607,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

@@ -2618,11 +2679,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++) {

@@ -2703,10 +2792,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, '=');

@@ -2994,10 +3111,17 @@
         // 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;
       }
+      // 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;
       }
       // Out of the box management support

@@ -3014,37 +3138,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")) {

@@ -3300,29 +3397,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.

@@ -3455,10 +3552,19 @@
       "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) {
+    if (!append_to_addmods_property(add_modules_value)) {
+      return JNI_ENOMEM;
+    }
+  }
+
   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()) {

@@ -3811,13 +3917,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");
     }

@@ -4196,10 +4302,15 @@
     warning("%s file is present but has been ignored.  "
             "Run with -XX:Flags=%s to load the file.",
             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
 
   ArgumentsExt::report_unsupported_options();

@@ -4420,19 +4531,52 @@
     pl = pl->next();
   }
   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;
   for (prop = pl; prop != NULL; prop = prop->next()) {
     if (strcmp(key, prop->key()) == 0) return prop->value();
   }
   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;
 
   while(pl != NULL) {

@@ -4473,41 +4617,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 >