--- a/hotspot/src/share/vm/runtime/arguments.cpp Fri Sep 04 12:47:57 2015 +0200
+++ b/hotspot/src/share/vm/runtime/arguments.cpp Tue Sep 08 16:10:37 2015 +0200
@@ -982,53 +982,61 @@
bool Arguments::add_property(const char* prop) {
const char* eq = strchr(prop, '=');
- char* key;
- // ns must be static--its address may be stored in a SystemProperty object.
- const static char ns[1] = {0};
- char* value = (char *)ns;
-
- size_t key_len = (eq == NULL) ? strlen(prop) : (eq - prop);
- key = AllocateHeap(key_len + 1, mtInternal);
- strncpy(key, prop, key_len);
- key[key_len] = '\0';
-
- if (eq != NULL) {
- size_t value_len = strlen(prop) - key_len - 1;
- value = AllocateHeap(value_len + 1, mtInternal);
- strncpy(value, &prop[key_len + 1], value_len + 1);
+ const char* key;
+ const char* value = "";
+
+ if (eq == NULL) {
+ // property doesn't have a value, thus use passed string
+ key = prop;
+ } else {
+ // property have a value, thus extract it and save to the
+ // allocated string
+ size_t key_len = eq - prop;
+ char* tmp_key = AllocateHeap(key_len + 1, mtInternal);
+
+ strncpy(tmp_key, prop, key_len);
+ tmp_key[key_len] = '\0';
+ key = tmp_key;
+
+ value = &prop[key_len + 1];
}
if (strcmp(key, "java.compiler") == 0) {
process_java_compiler_argument(value);
- FreeHeap(key);
- if (eq != NULL) {
- FreeHeap(value);
- }
- return true;
- } else if (strcmp(key, "sun.java.command") == 0) {
- _java_command = value;
-
// Record value in Arguments, but let it get passed to Java.
} else if (strcmp(key, "sun.java.launcher.is_altjvm") == 0 ||
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
- FreeHeap(key);
- if (eq != NULL) {
- FreeHeap(value);
- }
- return true;
- } else if (strcmp(key, "java.vendor.url.bug") == 0) {
- // save it in _java_vendor_url_bug, so JVM fatal error handler can access
- // its value without going through the property list or making a Java call.
- _java_vendor_url_bug = value;
} else if (strcmp(key, "sun.boot.library.path") == 0) {
PropertyList_unique_add(&_system_properties, key, value, true);
- return true;
- }
- // Create new property and add at the end of the list
- PropertyList_unique_add(&_system_properties, key, value);
+ } else {
+ if (strcmp(key, "sun.java.command") == 0) {
+ if (_java_command != NULL) {
+ os::free(_java_command);
+ }
+ _java_command = os::strdup_check_oom(value, mtInternal);
+ } else if (strcmp(key, "java.vendor.url.bug") == 0) {
+ if (_java_vendor_url_bug != DEFAULT_VENDOR_URL_BUG) {
+ assert(_java_vendor_url_bug != NULL, "_java_vendor_url_bug is NULL");
+ os::free((void *)_java_vendor_url_bug);
+ }
+ // save it in _java_vendor_url_bug, so JVM fatal error handler can access
+ // its value without going through the property list or making a Java call.
+ _java_vendor_url_bug = os::strdup_check_oom(value, mtInternal);
+ }
+
+ // Create new property and add at the end of the list
+ PropertyList_unique_add(&_system_properties, key, value);
+ }
+
+ if (key != prop) {
+ // SystemProperty copy passed value, thus free previously allocated
+ // memory
+ FreeHeap((void *)key);
+ }
+
return true;
}
@@ -1045,7 +1053,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",
- (char*)VM_Version::vm_info_string(), false);
+ VM_Version::vm_info_string(), false);
UseInterpreter = true;
UseCompiler = true;
@@ -1582,9 +1590,6 @@
#endif // _LP64
#endif // !ZERO
- // Set up runtime image flags.
- set_runtime_image_flags();
-
CodeCacheExtensions::set_ergonomics_flags();
}
@@ -1839,16 +1844,6 @@
}
}
- // Set up runtime image flags
-void Arguments::set_runtime_image_flags() {
-#ifdef _LP64
- // Memory map image file by default on 64 bit machines.
- if (FLAG_IS_DEFAULT(MemoryMapImage)) {
- FLAG_SET_ERGO(bool, MemoryMapImage, true);
- }
-#endif
-}
-
// This must be called after ergonomics.
void Arguments::set_bytecode_flags() {
if (!RewriteBytecodes) {
@@ -1857,7 +1852,7 @@
}
// Aggressive optimization flags -XX:+AggressiveOpts
-void Arguments::set_aggressive_opts_flags() {
+jint Arguments::set_aggressive_opts_flags() {
#ifdef COMPILER2
if (AggressiveUnboxing) {
if (FLAG_IS_DEFAULT(EliminateAutoBox)) {
@@ -1884,7 +1879,9 @@
// Feed the cache size setting into the JDK
char buffer[1024];
sprintf(buffer, "java.lang.Integer.IntegerCache.high=" INTX_FORMAT, AutoBoxCacheMax);
- add_property(buffer);
+ if (!add_property(buffer)) {
+ return JNI_ENOMEM;
+ }
}
if (AggressiveOpts && FLAG_IS_DEFAULT(BiasedLockingStartupDelay)) {
FLAG_SET_DEFAULT(BiasedLockingStartupDelay, 500);
@@ -1897,12 +1894,14 @@
// FLAG_SET_DEFAULT(EliminateZeroing, true);
// }
}
+
+ return JNI_OK;
}
//===========================================================================================================
// Parsing of java.compiler property
-void Arguments::process_java_compiler_argument(char* arg) {
+void Arguments::process_java_compiler_argument(const char* arg) {
// For backwards compatibility, Djava.compiler=NONE or ""
// causes us to switch to -Xint mode UNLESS -Xdebug
// is also specified.
@@ -3129,8 +3128,10 @@
jio_fprintf(defaultStream::output_stream(),
"CreateMinidumpOnCrash is replaced by CreateCoredumpOnCrash: CreateCoredumpOnCrash is off\n");
} else if (match_option(option, "-XX:", &tail)) { // -XX:xxxx
- // Skip -XX:Flags= since that case has already been handled
- if (strncmp(tail, "Flags=", strlen("Flags=")) != 0) {
+ // Skip -XX:Flags= and -XX:VMOptionsFile= since those cases have
+ // already been handled
+ if ((strncmp(tail, "Flags=", strlen("Flags=")) != 0) &&
+ (strncmp(tail, "VMOptionsFile=", strlen("VMOptionsFile=")) != 0)) {
if (!process_argument(tail, args->ignoreUnrecognized, origin)) {
return JNI_EINVAL;
}
@@ -3382,6 +3383,7 @@
class ScopedVMInitArgs : public StackObj {
private:
JavaVMInitArgs _args;
+ bool _is_set;
public:
ScopedVMInitArgs() {
@@ -3389,6 +3391,7 @@
_args.nOptions = 0;
_args.options = NULL;
_args.ignoreUnrecognized = false;
+ _is_set = false;
}
// Populates the JavaVMInitArgs object represented by this
@@ -3397,6 +3400,7 @@
// returns anything other than JNI_OK, then this object is in a
// partially constructed state, and should be abandoned.
jint set_args(GrowableArray<JavaVMOption>* options) {
+ _is_set = true;
JavaVMOption* options_arr = NEW_C_HEAP_ARRAY_RETURN_NULL(
JavaVMOption, options->length(), mtInternal);
if (options_arr == NULL) {
@@ -3420,6 +3424,7 @@
}
JavaVMInitArgs* get() { return &_args; }
+ bool is_set() { return _is_set; }
~ScopedVMInitArgs() {
if (_args.options == NULL) return;
@@ -3428,6 +3433,35 @@
}
FREE_C_HEAP_ARRAY(JavaVMOption, _args.options);
}
+
+ // Insert options into this option list, to replace option at
+ // vm_options_file_pos (-XX:VMOptionsFile)
+ jint insert(const JavaVMInitArgs* args,
+ const JavaVMInitArgs* args_to_insert,
+ const int vm_options_file_pos) {
+ assert(_args.options == NULL, "shouldn't be set yet");
+ assert(args_to_insert->nOptions != 0, "there should be args to insert");
+ assert(vm_options_file_pos != -1, "vm_options_file_pos should be set");
+
+ int length = args->nOptions + args_to_insert->nOptions - 1;
+ GrowableArray<JavaVMOption> *options = new (ResourceObj::C_HEAP, mtInternal)
+ GrowableArray<JavaVMOption>(length, true); // Construct new option array
+ for (int i = 0; i < args->nOptions; i++) {
+ if (i == vm_options_file_pos) {
+ // insert the new options starting at the same place as the
+ // -XX:VMOptionsFile option
+ for (int j = 0; j < args_to_insert->nOptions; j++) {
+ options->push(args_to_insert->options[j]);
+ }
+ } else {
+ options->push(args->options[i]);
+ }
+ }
+ // make into options array
+ jint result = set_args(options);
+ delete options;
+ return result;
+ }
};
jint Arguments::parse_java_options_environment_variable(ScopedVMInitArgs* args) {
@@ -3452,54 +3486,137 @@
return JNI_ENOMEM;
}
+ int retcode = parse_options_buffer(name, buffer, strlen(buffer), vm_args);
+
+ os::free(buffer);
+ return retcode;
+}
+
+const int OPTION_BUFFER_SIZE = 1024;
+
+jint Arguments::parse_vm_options_file(const char* file_name, ScopedVMInitArgs* vm_args) {
+ // read file into buffer
+ int fd = ::open(file_name, O_RDONLY);
+ if (fd < 0) {
+ jio_fprintf(defaultStream::error_stream(),
+ "Could not open options file '%s'\n",
+ file_name);
+ return JNI_ERR;
+ }
+
+ // '+ 1' for NULL termination even with max bytes
+ int bytes_alloc = OPTION_BUFFER_SIZE + 1;
+
+ char *buf = NEW_C_HEAP_ARRAY_RETURN_NULL(char, bytes_alloc, mtInternal);
+ if (NULL == buf) {
+ jio_fprintf(defaultStream::error_stream(),
+ "Could not allocate read buffer for options file parse\n");
+ os::close(fd);
+ return JNI_ENOMEM;
+ }
+
+ memset(buf, 0, (unsigned)bytes_alloc);
+
+ // Fill buffer
+ // Use ::read() instead of os::read because os::read()
+ // might do a thread state transition
+ // and it is too early for that here
+
+ int bytes_read = ::read(fd, (void *)buf, (unsigned)bytes_alloc);
+ os::close(fd);
+ if (bytes_read < 0) {
+ FREE_C_HEAP_ARRAY(char, buf);
+ jio_fprintf(defaultStream::error_stream(),
+ "Could not read options file '%s'\n", file_name);
+ return JNI_ERR;
+ }
+
+ if (bytes_read == 0) {
+ // tell caller there is no option data and that is ok
+ FREE_C_HEAP_ARRAY(char, buf);
+ return JNI_OK;
+ }
+
+ // file is larger than OPTION_BUFFER_SIZE
+ if (bytes_read > bytes_alloc - 1) {
+ FREE_C_HEAP_ARRAY(char, buf);
+ jio_fprintf(defaultStream::error_stream(),
+ "Options file '%s' is larger than %d bytes.\n",
+ file_name, bytes_alloc - 1);
+ return JNI_EINVAL;
+ }
+
+ int retcode = parse_options_buffer(file_name, buf, bytes_read, vm_args);
+
+ FREE_C_HEAP_ARRAY(char, buf);
+ return retcode;
+}
+
+jint Arguments::parse_options_buffer(const char* name, char* buffer, const size_t buf_len, ScopedVMInitArgs* vm_args) {
GrowableArray<JavaVMOption> *options = new (ResourceObj::C_HEAP, mtInternal) GrowableArray<JavaVMOption>(2, true); // Construct option array
- jio_fprintf(defaultStream::error_stream(),
- "Picked up %s: %s\n", name, buffer);
- char* rd = buffer; // pointer to the input string (rd)
- while (true) { // repeat for all options in the input string
- while (isspace(*rd)) rd++; // skip whitespace
- if (*rd == 0) break; // we re done when the input string is read completely
-
- // The output, option string, overwrites the input string.
- // Because of quoting, the pointer to the option string (wrt) may lag the pointer to
- // input string (rd).
- char* wrt = rd;
-
- JavaVMOption option;
- option.optionString = wrt;
- options->append(option); // Fill in option
- while (*rd != 0 && !isspace(*rd)) { // unquoted strings terminate with a space or NULL
+
+ // some pointers to help with parsing
+ char *buffer_end = buffer + buf_len;
+ char *opt_hd = buffer;
+ char *wrt = buffer;
+ char *rd = buffer;
+
+ // parse all options
+ while (rd < buffer_end) {
+ // skip leading white space from the input string
+ while (rd < buffer_end && isspace(*rd)) {
+ rd++;
+ }
+
+ if (rd >= buffer_end) {
+ break;
+ }
+
+ // Remember this is where we found the head of the token.
+ opt_hd = wrt;
+
+ // Tokens are strings of non white space characters separated
+ // by one or more white spaces.
+ while (rd < buffer_end && !isspace(*rd)) {
if (*rd == '\'' || *rd == '"') { // handle a quoted string
int quote = *rd; // matching quote to look for
rd++; // don't copy open quote
- while (*rd != quote) { // include everything (even spaces) up until quote
- if (*rd == 0) { // string termination means unmatched string
- jio_fprintf(defaultStream::error_stream(),
- "Unmatched quote in %s\n", name);
- delete options;
- os::free(buffer);
- return JNI_ERR;
- }
+ while (rd < buffer_end && *rd != quote) {
+ // include everything (even spaces)
+ // up until the close quote
*wrt++ = *rd++; // copy to option string
}
- rd++; // don't copy close quote
+
+ if (rd < buffer_end) {
+ rd++; // don't copy close quote
+ } else {
+ // did not see closing quote
+ jio_fprintf(defaultStream::error_stream(),
+ "Unmatched quote in %s\n", name);
+ delete options;
+ return JNI_ERR;
+ }
} else {
*wrt++ = *rd++; // copy to option string
}
}
- if (*rd != 0) {
- // In this case, the assignment to wrt below will make *rd nul,
- // which will interfere with the next loop iteration.
- rd++;
- }
- *wrt = 0; // Zero terminate option
+
+ // steal a white space character and set it to NULL
+ *wrt++ = '\0';
+ // We now have a complete token
+
+ JavaVMOption option;
+ option.optionString = opt_hd;
+
+ options->append(option); // Fill in option
+
+ rd++; // Advance to next character
}
// Fill out JavaVMInitArgs structure.
jint status = vm_args->set_args(options);
delete options;
- os::free(buffer);
return status;
}
@@ -3581,12 +3698,44 @@
return false;
}
+
#endif // PRODUCT
-static jint match_special_option_and_act(const JavaVMInitArgs* args,
- char** flags_file) {
+jint Arguments::insert_vm_options_file(const JavaVMInitArgs* args,
+ char** flags_file,
+ char** vm_options_file,
+ const int vm_options_file_pos,
+ ScopedVMInitArgs *vm_options_file_args,
+ ScopedVMInitArgs* args_out) {
+ jint code = parse_vm_options_file(*vm_options_file, vm_options_file_args);
+ if (code != JNI_OK) {
+ return code;
+ }
+
+ // Now set global settings from the vm_option file, giving an error if
+ // it has VMOptionsFile in it
+ code = match_special_option_and_act(vm_options_file_args->get(), flags_file,
+ NULL, NULL, NULL);
+ if (code != JNI_OK) {
+ return code;
+ }
+
+ if (vm_options_file_args->get()->nOptions < 1) {
+ return 0;
+ }
+
+ return args_out->insert(args, vm_options_file_args->get(),
+ vm_options_file_pos);
+}
+
+jint Arguments::match_special_option_and_act(const JavaVMInitArgs* args,
+ char ** flags_file,
+ char ** vm_options_file,
+ ScopedVMInitArgs* vm_options_file_args,
+ ScopedVMInitArgs* args_out) {
// Remaining part of option string
const char* tail;
+ int vm_options_file_pos = -1;
for (int index = 0; index < args->nOptions; index++) {
const JavaVMOption* option = args->options + index;
@@ -3595,6 +3744,35 @@
}
if (match_option(option, "-XX:Flags=", &tail)) {
*flags_file = (char *) tail;
+ if (*flags_file == NULL) {
+ jio_fprintf(defaultStream::error_stream(),
+ "Cannot copy flags_file name.\n");
+ return JNI_ENOMEM;
+ }
+ 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(),
+ "Only one VM Options file is supported "
+ "on the command line\n");
+ return JNI_EINVAL;
+ }
+
+ *vm_options_file = (char *) tail;
+ vm_options_file_pos = index; // save position of -XX:VMOptionsFile
+ if (*vm_options_file == NULL) {
+ jio_fprintf(defaultStream::error_stream(),
+ "Cannot copy vm_options_file name.\n");
+ return JNI_ENOMEM;
+ }
+ } else {
+ jio_fprintf(defaultStream::error_stream(),
+ "VM options file is only supported on the command line\n");
+ return JNI_EINVAL;
+ }
continue;
}
if (match_option(option, "-XX:+PrintVMOptions")) {
@@ -3648,6 +3826,12 @@
}
#endif
}
+
+ // If there's a VMOptionsFile, parse that (also can set flags_file)
+ if ((vm_options_file != NULL) && (*vm_options_file != NULL)) {
+ return insert_vm_options_file(args, flags_file, vm_options_file,
+ vm_options_file_pos, vm_options_file_args, args_out);
+ }
return JNI_OK;
}
@@ -3672,10 +3856,15 @@
// If flag "-XX:Flags=flags-file" is used it will be the first option to be processed.
const char* hotspotrc = ".hotspotrc";
char* flags_file = NULL;
+ 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;
+ // Pass in vm_options_file_args to keep memory for flags_file from being
+ // deallocated if found in the vm options file.
+ ScopedVMInitArgs vm_options_file_args;
jint code =
parse_java_tool_options_environment_variable(&java_tool_options_args);
@@ -3688,18 +3877,27 @@
return code;
}
- code =
- match_special_option_and_act(java_tool_options_args.get(), &flags_file);
+ code = match_special_option_and_act(java_tool_options_args.get(),
+ &flags_file, NULL, NULL, NULL);
+ if (code != JNI_OK) {
+ return code;
+ }
+
+ code = match_special_option_and_act(args, &flags_file, &vm_options_file,
+ &vm_options_file_args,
+ &modified_cmd_line_args);
if (code != JNI_OK) {
return code;
}
- code = match_special_option_and_act(args, &flags_file);
- if (code != JNI_OK) {
- return code;
- }
-
- code = match_special_option_and_act(java_options_args.get(), &flags_file);
+
+ // 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(), &flags_file,
+ NULL, NULL, NULL);
if (code != JNI_OK) {
return code;
}
@@ -3740,7 +3938,8 @@
// 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);
+ java_options_args.get(),
+ args); // command line arguments
if (result != JNI_OK) {
return result;
@@ -3869,7 +4068,10 @@
set_bytecode_flags();
// Set flags if Aggressive optimization flags (-XX:+AggressiveOpts) enabled
- set_aggressive_opts_flags();
+ jint code = set_aggressive_opts_flags();
+ if (code != JNI_OK) {
+ return code;
+ }
// Turn off biased locking for locking debug mode flags,
// which are subtly different from each other but neither works with
@@ -4035,7 +4237,7 @@
}
}
-void Arguments::PropertyList_add(SystemProperty** plist, const char* k, char* v) {
+void Arguments::PropertyList_add(SystemProperty** plist, const char* k, const char* v) {
if (plist == NULL)
return;
@@ -4048,7 +4250,7 @@
}
// This add maintains unique property key in the list.
-void Arguments::PropertyList_unique_add(SystemProperty** plist, const char* k, char* v, jboolean append) {
+void Arguments::PropertyList_unique_add(SystemProperty** plist, const char* k, const char* v, jboolean append) {
if (plist == NULL)
return;