hotspot/src/share/vm/runtime/arguments.cpp
changeset 35466 4ace9ef0201b
parent 35219 b9ef87beb87c
child 35489 368deab8e88b
--- a/hotspot/src/share/vm/runtime/arguments.cpp	Fri Jan 08 12:56:16 2016 +0000
+++ b/hotspot/src/share/vm/runtime/arguments.cpp	Fri Jan 08 15:38:08 2016 -0800
@@ -2622,7 +2622,7 @@
                                        SysClassPath* scp_p,
                                        bool* scp_assembly_required_p,
                                        Flag::Flags origin) {
-  // Remaining part of option string
+  // For match_option to return remaining or value part of option string
   const char* tail;
 
   // iterate over arguments
@@ -3502,15 +3502,19 @@
 class ScopedVMInitArgs : public StackObj {
  private:
   JavaVMInitArgs _args;
+  char*          _container_name;
   bool           _is_set;
+  char*          _vm_options_file_arg;
 
  public:
-  ScopedVMInitArgs() {
+  ScopedVMInitArgs(const char *container_name) {
     _args.version = JNI_VERSION_1_2;
     _args.nOptions = 0;
     _args.options = NULL;
     _args.ignoreUnrecognized = false;
+    _container_name = (char *)container_name;
     _is_set = false;
+    _vm_options_file_arg = NULL;
   }
 
   // Populates the JavaVMInitArgs object represented by this
@@ -3542,10 +3546,23 @@
     return JNI_OK;
   }
 
-  JavaVMInitArgs* get() { return &_args; }
-  bool is_set()         { return _is_set; }
+  JavaVMInitArgs* get()             { return &_args; }
+  char* container_name()            { return _container_name; }
+  bool  is_set()                    { return _is_set; }
+  bool  found_vm_options_file_arg() { return _vm_options_file_arg != NULL; }
+  char* vm_options_file_arg()       { return _vm_options_file_arg; }
+
+  void set_vm_options_file_arg(const char *vm_options_file_arg) {
+    if (_vm_options_file_arg != NULL) {
+      os::free(_vm_options_file_arg);
+    }
+    _vm_options_file_arg = os::strdup_check_oom(vm_options_file_arg);
+  }
 
   ~ScopedVMInitArgs() {
+    if (_vm_options_file_arg != NULL) {
+      os::free(_vm_options_file_arg);
+    }
     if (_args.options == NULL) return;
     for (int i = 0; i < _args.nOptions; i++) {
       os::free(_args.options[i].optionString);
@@ -3826,12 +3843,23 @@
 
 #endif // PRODUCT
 
+bool Arguments::args_contains_vm_options_file_arg(const JavaVMInitArgs* args) {
+  for (int index = 0; index < args->nOptions; index++) {
+    const JavaVMOption* option = args->options + index;
+    const char* tail;
+    if (match_option(option, "-XX:VMOptionsFile=", &tail)) {
+      return true;
+    }
+  }
+  return false;
+}
+
 jint Arguments::insert_vm_options_file(const JavaVMInitArgs* args,
-                                       char** vm_options_file,
+                                       const char* vm_options_file,
                                        const int vm_options_file_pos,
-                                       ScopedVMInitArgs *vm_options_file_args,
+                                       ScopedVMInitArgs* vm_options_file_args,
                                        ScopedVMInitArgs* args_out) {
-  jint code = parse_vm_options_file(*vm_options_file, vm_options_file_args);
+  jint code = parse_vm_options_file(vm_options_file, vm_options_file_args);
   if (code != JNI_OK) {
     return code;
   }
@@ -3840,17 +3868,46 @@
     return JNI_OK;
   }
 
+  if (args_contains_vm_options_file_arg(vm_options_file_args->get())) {
+    jio_fprintf(defaultStream::error_stream(),
+                "A VM options file may not refer to a VM options file. "
+                "Specification of '-XX:VMOptionsFile=<file-name>' in the "
+                "options file '%s' in options container '%s' is an error.\n",
+                vm_options_file_args->vm_options_file_arg(),
+                vm_options_file_args->container_name());
+    return JNI_EINVAL;
+  }
+
   return args_out->insert(args, vm_options_file_args->get(),
                           vm_options_file_pos);
 }
 
+// Expand -XX:VMOptionsFile found in args_in as needed.
+// mod_args and args_out parameters may return values as needed.
+jint Arguments::expand_vm_options_as_needed(const JavaVMInitArgs* args_in,
+                                            ScopedVMInitArgs* mod_args,
+                                            JavaVMInitArgs** args_out) {
+  jint code = match_special_option_and_act(args_in, mod_args);
+  if (code != JNI_OK) {
+    return code;
+  }
+
+  if (mod_args->is_set()) {
+    // args_in contains -XX:VMOptionsFile and mod_args contains the
+    // original options from args_in along with the options expanded
+    // from the VMOptionsFile. Return a short-hand to the caller.
+    *args_out = mod_args->get();
+  } else {
+    *args_out = (JavaVMInitArgs *)args_in;  // no changes so use args_in
+  }
+  return JNI_OK;
+}
+
 jint Arguments::match_special_option_and_act(const JavaVMInitArgs* args,
-                                             char ** vm_options_file,
                                              ScopedVMInitArgs* args_out) {
   // Remaining part of option string
   const char* tail;
-  int   vm_options_file_pos = -1;
-  ScopedVMInitArgs vm_options_file_args;
+  ScopedVMInitArgs vm_options_file_args(args_out->container_name());
 
   for (int index = 0; index < args->nOptions; index++) {
     const JavaVMOption* option = args->options + index;
@@ -3862,39 +3919,34 @@
       continue;
     }
     if (match_option(option, "-XX:VMOptionsFile=", &tail)) {
-      if (vm_options_file != NULL) {
-        // The caller accepts -XX:VMOptionsFile
-        if (*vm_options_file != NULL) {
-          jio_fprintf(defaultStream::error_stream(),
-                      "The VM Options file can only be specified once and "
-                      "only on the command line.\n");
-          return JNI_EINVAL;
-        }
-
-        *vm_options_file = (char *) tail;
-        vm_options_file_pos = index;  // save position of -XX:VMOptionsFile
-        // If there's a VMOptionsFile, parse that (also can set flags_file)
-        jint code = insert_vm_options_file(args, vm_options_file,
-                                           vm_options_file_pos,
-                                           &vm_options_file_args, args_out);
-        if (code != JNI_OK) {
-          return code;
-        }
-        if (args_out->is_set()) {
-          // The VMOptions file inserted some options so switch 'args'
-          // to the new set of options, and continue processing which
-          // preserves "last option wins" semantics.
-          args = args_out->get();
-          // The first option from the VMOptionsFile replaces the
-          // current option.  So we back track to process the
-          // replacement option.
-          index--;
-        }
-      } else {
+      if (vm_options_file_args.found_vm_options_file_arg()) {
         jio_fprintf(defaultStream::error_stream(),
-                    "VM options file is only supported on the command line\n");
+                    "The option '%s' is already specified in the options "
+                    "container '%s' so the specification of '%s' in the "
+                    "same options container is an error.\n",
+                    vm_options_file_args.vm_options_file_arg(),
+                    vm_options_file_args.container_name(),
+                    option->optionString);
         return JNI_EINVAL;
       }
+      vm_options_file_args.set_vm_options_file_arg(option->optionString);
+      // If there's a VMOptionsFile, parse that
+      jint code = insert_vm_options_file(args, tail, index,
+                                         &vm_options_file_args, args_out);
+      if (code != JNI_OK) {
+        return code;
+      }
+      args_out->set_vm_options_file_arg(vm_options_file_args.vm_options_file_arg());
+      if (args_out->is_set()) {
+        // The VMOptions file inserted some options so switch 'args'
+        // to the new set of options, and continue processing which
+        // preserves "last option wins" semantics.
+        args = args_out->get();
+        // The first option from the VMOptionsFile replaces the
+        // current option.  So we back track to process the
+        // replacement option.
+        index--;
+      }
       continue;
     }
     if (match_option(option, "-XX:+PrintVMOptions")) {
@@ -3963,7 +4015,7 @@
 
 // Parse entry point called from JNI_CreateJavaVM
 
-jint Arguments::parse(const JavaVMInitArgs* args) {
+jint Arguments::parse(const JavaVMInitArgs* initial_cmd_args) {
   assert(verify_special_jvm_flags(), "deprecated and obsolete flag table inconsistent");
 
   // Initialize ranges and constraints
@@ -3972,67 +4024,74 @@
 
   // If flag "-XX:Flags=flags-file" is used it will be the first option to be processed.
   const char* hotspotrc = ".hotspotrc";
-  char* vm_options_file = NULL;
   bool settings_file_specified = false;
   bool needs_hotspotrc_warning = false;
-  ScopedVMInitArgs java_tool_options_args;
-  ScopedVMInitArgs java_options_args;
-  ScopedVMInitArgs modified_cmd_line_args;
+  ScopedVMInitArgs initial_java_tool_options_args("env_var='JAVA_TOOL_OPTIONS'");
+  ScopedVMInitArgs initial_java_options_args("env_var='_JAVA_OPTIONS'");
+
+  // Pointers to current working set of containers
+  JavaVMInitArgs* cur_cmd_args;
+  JavaVMInitArgs* cur_java_options_args;
+  JavaVMInitArgs* cur_java_tool_options_args;
+
+  // Containers for modified/expanded options
+  ScopedVMInitArgs mod_cmd_args("cmd_line_args");
+  ScopedVMInitArgs mod_java_tool_options_args("env_var='JAVA_TOOL_OPTIONS'");
+  ScopedVMInitArgs mod_java_options_args("env_var='_JAVA_OPTIONS'");
+
 
   jint code =
-      parse_java_tool_options_environment_variable(&java_tool_options_args);
+      parse_java_tool_options_environment_variable(&initial_java_tool_options_args);
   if (code != JNI_OK) {
     return code;
   }
 
-  code = parse_java_options_environment_variable(&java_options_args);
-  if (code != JNI_OK) {
-    return code;
-  }
-
-  code = match_special_option_and_act(java_tool_options_args.get(),
-                                      NULL, NULL);
+  code = parse_java_options_environment_variable(&initial_java_options_args);
   if (code != JNI_OK) {
     return code;
   }
 
-  code = match_special_option_and_act(args, &vm_options_file,
-                                      &modified_cmd_line_args);
+  code = expand_vm_options_as_needed(initial_java_tool_options_args.get(),
+                                     &mod_java_tool_options_args,
+                                     &cur_java_tool_options_args);
   if (code != JNI_OK) {
     return code;
   }
 
-
-  // The command line arguments have been modified to include VMOptionsFile arguments.
-  if (modified_cmd_line_args.is_set()) {
-    args = modified_cmd_line_args.get();
-  }
-
-  code = match_special_option_and_act(java_options_args.get(),
-                                      NULL, NULL);
+  code = expand_vm_options_as_needed(initial_cmd_args,
+                                     &mod_cmd_args,
+                                     &cur_cmd_args);
   if (code != JNI_OK) {
     return code;
   }
 
-  const char * flags_file = Arguments::get_jvm_flags_file();
+  code = expand_vm_options_as_needed(initial_java_options_args.get(),
+                                     &mod_java_options_args,
+                                     &cur_java_options_args);
+  if (code != JNI_OK) {
+    return code;
+  }
+
+  const char* flags_file = Arguments::get_jvm_flags_file();
   settings_file_specified = (flags_file != NULL);
 
   if (IgnoreUnrecognizedVMOptions) {
-    // uncast const to modify the flag args->ignoreUnrecognized
-    *(jboolean*)(&args->ignoreUnrecognized) = true;
-    java_tool_options_args.get()->ignoreUnrecognized = true;
-    java_options_args.get()->ignoreUnrecognized = true;
+    cur_cmd_args->ignoreUnrecognized = true;
+    cur_java_tool_options_args->ignoreUnrecognized = true;
+    cur_java_options_args->ignoreUnrecognized = true;
   }
 
   // Parse specified settings file
   if (settings_file_specified) {
-    if (!process_settings_file(flags_file, true, args->ignoreUnrecognized)) {
+    if (!process_settings_file(flags_file, true,
+                               cur_cmd_args->ignoreUnrecognized)) {
       return JNI_EINVAL;
     }
   } else {
 #ifdef ASSERT
     // Parse default .hotspotrc settings file
-    if (!process_settings_file(".hotspotrc", false, args->ignoreUnrecognized)) {
+    if (!process_settings_file(".hotspotrc", false,
+                               cur_cmd_args->ignoreUnrecognized)) {
       return JNI_EINVAL;
     }
 #else
@@ -4044,15 +4103,15 @@
   }
 
   if (PrintVMOptions) {
-    print_options(java_tool_options_args.get());
-    print_options(args);
-    print_options(java_options_args.get());
+    print_options(cur_java_tool_options_args);
+    print_options(cur_cmd_args);
+    print_options(cur_java_options_args);
   }
 
   // Parse JavaVMInitArgs structure passed in, as well as JAVA_TOOL_OPTIONS and _JAVA_OPTIONS
-  jint result = parse_vm_init_args(java_tool_options_args.get(),
-                                   java_options_args.get(),
-                                   args);   // command line arguments
+  jint result = parse_vm_init_args(cur_java_tool_options_args,
+                                   cur_java_options_args,
+                                   cur_cmd_args);
 
   if (result != JNI_OK) {
     return result;