--- old/src/share/vm/runtime/thread.cpp 2012-02-15 12:29:19.000000000 +0100 +++ new/src/share/vm/runtime/thread.cpp 2012-02-15 12:29:19.000000000 +0100 @@ -3220,11 +3220,6 @@ return status; } - // Must be run after init_ft which initializes ft_enabled - if (TRACE_INITIALIZE() != JNI_OK) { - vm_exit_during_initialization("Failed to initialize tracing backend"); - } - // Should be done after the heap is fully created main_thread->cache_global_variables(); @@ -3366,6 +3361,7 @@ initialize_class(vmSymbols::java_lang_ArithmeticException(), CHECK_0); initialize_class(vmSymbols::java_lang_StackOverflowError(), CHECK_0); initialize_class(vmSymbols::java_lang_IllegalMonitorStateException(), CHECK_0); + initialize_class(vmSymbols::java_lang_IllegalArgumentException(), CHECK_0); } else { warning("java.lang.OutOfMemoryError has not been initialized"); warning("java.lang.NullPointerException has not been initialized"); @@ -3373,6 +3369,7 @@ warning("java.lang.ArrayStoreException has not been initialized"); warning("java.lang.ArithmeticException has not been initialized"); warning("java.lang.StackOverflowError has not been initialized"); + warning("java.lang.IllegalArgumentException has not been initialized"); } } @@ -3402,6 +3399,11 @@ quicken_jni_functions(); + // Must be run after init_ft which initializes ft_enabled + if (TRACE_INITIALIZE() != JNI_OK) { + vm_exit_during_initialization("Failed to initialize tracing backend"); + } + // Set flag that basic initialization has completed. Used by exceptions and various // debug stuff, that does not work until all basic classes have been initialized. set_init_completed(); --- old/src/share/vm/services/diagnosticArgument.cpp 2012-02-15 12:29:20.000000000 +0100 +++ new/src/share/vm/services/diagnosticArgument.cpp 2012-02-15 12:29:20.000000000 +0100 @@ -28,9 +28,16 @@ #include "services/diagnosticArgument.hpp" void GenDCmdArgument::read_value(const char* str, size_t len, TRAPS) { - if (is_set()) { + /* NOTE:Some argument types doesn't require a value, + * for instance boolean arguments: "enableFeatureX". is + * equivalent to "enableFeatureX=true". In these cases, + * str will be null. This is perfectly valid. + * All argument types must perform null checks on str. + */ + + if (is_set() && !allow_multiple()) { THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), - "Duplicates in diagnostic command arguments"); + "Duplicates in diagnostic command arguments\n"); } parse_value(str, len, CHECK); set_is_set(true); @@ -38,9 +45,9 @@ template <> void DCmdArgument::parse_value(const char* str, size_t len, TRAPS) { - if (sscanf(str, INT64_FORMAT, &_value) != 1) { + if (str == NULL || sscanf(str, INT64_FORMAT, &_value) != 1) { THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), - "Integer parsing error in diagnostic command arguments"); + "Integer parsing error in diagnostic command arguments\n"); } } @@ -89,16 +96,20 @@ template <> void DCmdArgument::parse_value(const char* str, size_t len, TRAPS) { - _value = NEW_C_HEAP_ARRAY(char, len+1); - strncpy(_value, str, len); - _value[len] = 0; + if (str == NULL) { + _value = NULL; + } else { + _value = NEW_C_HEAP_ARRAY(char, len+1); + strncpy(_value, str, len); + _value[len] = 0; + } } template <> void DCmdArgument::init_value(TRAPS) { - if (has_default()) { + if (has_default() && _default_string != NULL) { this->parse_value(_default_string, strlen(_default_string), THREAD); if (HAS_PENDING_EXCEPTION) { - fatal("Default string must be parsable"); + fatal("Default string must be parsable"); } } else { set_value(NULL); @@ -111,3 +122,153 @@ set_value(NULL); } } + +template <> void DCmdArgument::parse_value(const char* str, + size_t len, TRAPS) { + if (str == NULL) { + THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), + "Integer parsing error nanotime value: syntax error"); + } + + int argc = sscanf(str, INT64_FORMAT , &_value._time); + if (argc != 1) { + THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), + "Integer parsing error nanotime value: syntax error"); + } + size_t idx = 0; + while(idx < len && isdigit(str[idx])) { + idx++; + } + if (idx == len) { + // only accept missing unit if the value is 0 + if (_value._time != 0) { + THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), + "Integer parsing error nanotime value: unit required"); + } else { + _value._nanotime = 0; + strcpy(_value._unit, "ns"); + return; + } + } else if(len - idx > 2) { + THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), + "Integer parsing error nanotime value: illegal unit"); + } else { + strncpy(_value._unit, &str[idx], len - idx); + /*Write an extra null termination. This is safe because _value._unit + * is declared as char[3], and length is checked to be not larger than + * two above. Also, this is necessary, since length might be 1, and the + * default value already in the string is ns, which is two chars. + */ + _value._unit[len-idx] = '\0'; + } + + if (strcmp(_value._unit, "ns") == 0) { + _value._nanotime = _value._time; + } else if (strcmp(_value._unit, "us") == 0) { + _value._nanotime = _value._time * 1000; + } else if (strcmp(_value._unit, "ms") == 0) { + _value._nanotime = _value._time * 1000 * 1000; + } else if (strcmp(_value._unit, "s") == 0) { + _value._nanotime = _value._time * 1000 * 1000 * 1000; + } else if (strcmp(_value._unit, "m") == 0) { + _value._nanotime = _value._time * 60 * 1000 * 1000 * 1000; + } else if (strcmp(_value._unit, "h") == 0) { + _value._nanotime = _value._time * 60 * 60 * 1000 * 1000 * 1000; + } else if (strcmp(_value._unit, "d") == 0) { + _value._nanotime = _value._time * 24 * 60 * 60 * 1000 * 1000 * 1000; + } else { + THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), + "Integer parsing error nanotime value: illegal unit"); + } +} + +template <> void DCmdArgument::init_value(TRAPS) { + if (has_default()) { + this->parse_value(_default_string, strlen(_default_string), THREAD); + if (HAS_PENDING_EXCEPTION) { + fatal("Default string must be parsable"); + } + } else { + _value._time = 0; + _value._nanotime = 0; + strcmp(_value._unit, "ns"); + } +} + +template <> void DCmdArgument::destroy_value() { } + +// WARNING StringArrayArgument can only be used as an option, it cannot be +// used as an argument with the DCmdParser + +template <> void DCmdArgument::parse_value(const char* str, + size_t len, TRAPS) { + _value->add(str,len); +} + +template <> void DCmdArgument::init_value(TRAPS) { + _value = new StringArrayArgument(); + _allow_multiple = true; + if (has_default()) { + fatal("StringArrayArgument cannot have default value"); + } +} + +template <> void DCmdArgument::destroy_value() { + if (_value != NULL) { + delete _value; + set_value(NULL); + } +} + +template <> void DCmdArgument::parse_value(const char* str, + size_t len, TRAPS) { + if (str == NULL) { + THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), + "Integer parsing error nanotime value: syntax error"); + } + + if (*str == '-') { + THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), + "Parsing error memory size value: negative values not allowed"); + } + int res = sscanf(str, "%" FORMAT64_MODIFIER "u%c", &_value._val, &_value._multiplier); + if (res == 2) { + switch (_value._multiplier) { + case 'k': case 'K': + _value._size = _value._val * 1024; + break; + case 'm': case 'M': + _value._size = _value._val * 1024 * 1024; + break; + case 'g': case 'G': + _value._size = _value._val * 1024 * 1024 * 1024; + break; + default: + _value._size = _value._val; + _value._multiplier = ' '; + //default case should be to break with no error, since user + //can write size in bytes, or might have a delimiter and next arg + break; + } + } else if (res == 1) { + _value._size = _value._val; + } else { + THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), + "Parsing error memory size value: invalid value"); + } +} + +template <> void DCmdArgument::init_value(TRAPS) { + if (has_default()) { + this->parse_value(_default_string, strlen(_default_string), THREAD); + if (HAS_PENDING_EXCEPTION) { + fatal("Default string must be parsable"); + } + } else { + _value._size = 0; + _value._val = 0; + _value._multiplier = ' '; + } +} + +template <> void DCmdArgument::destroy_value() { } --- old/src/share/vm/services/diagnosticArgument.hpp 2012-02-15 12:29:21.000000000 +0100 +++ new/src/share/vm/services/diagnosticArgument.hpp 2012-02-15 12:29:21.000000000 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,6 +31,49 @@ #include "runtime/thread.hpp" #include "utilities/exceptions.hpp" +class StringArrayArgument : public CHeapObj { +private: + GrowableArray* _array; +public: + StringArrayArgument() { + _array = new(ResourceObj::C_HEAP)GrowableArray(32, true); + assert(_array != NULL, "Sanity check"); + } + void add(const char* str, size_t len) { + if (str != NULL) { + char* ptr = NEW_C_HEAP_ARRAY(char, len+1); + strncpy(ptr, str, len); + ptr[len] = 0; + _array->append(ptr); + } + } + GrowableArray* array() { + return _array; + } + ~StringArrayArgument() { + for (int i=0; i<_array->length(); i++) { + if(_array->at(i) != NULL) { // Safety check + FREE_C_HEAP_ARRAY(char, _array->at(i)); + } + } + delete _array; + } +}; + +class NanoTimeArgument { +public: + jlong _nanotime; + jlong _time; + char _unit[3]; +}; + +class MemorySizeArgument { +public: + u8 _size; + u8 _val; + char _multiplier; +}; + class GenDCmdArgument : public ResourceObj { protected: GenDCmdArgument* _next; @@ -40,6 +83,7 @@ const char* _default_string; bool _is_set; bool _is_mandatory; + bool _allow_multiple; GenDCmdArgument(const char* name, const char* description, const char* type, const char* default_string, bool mandatory) { _name = name; @@ -48,6 +92,7 @@ _default_string = default_string; _is_mandatory = mandatory; _is_set = false; + _allow_multiple = false; }; public: const char* name() { return _name; } @@ -56,6 +101,7 @@ const char* default_string() { return _default_string; } bool is_set() { return _is_set; } void set_is_set(bool b) { _is_set = b; } + bool allow_multiple() { return _allow_multiple; } bool is_mandatory() { return _is_mandatory; } bool has_value() { return _is_set || _default_string != NULL; } bool has_default() { return _default_string != NULL; } --- old/src/share/vm/services/diagnosticCommand.cpp 2012-02-15 12:29:21.000000000 +0100 +++ new/src/share/vm/services/diagnosticCommand.cpp 2012-02-15 12:29:21.000000000 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it --- old/src/share/vm/services/diagnosticCommand.hpp 2012-02-15 12:29:22.000000000 +0100 +++ new/src/share/vm/services/diagnosticCommand.hpp 2012-02-15 12:29:22.000000000 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it --- old/src/share/vm/services/diagnosticFramework.cpp 2012-02-15 12:29:22.000000000 +0100 +++ new/src/share/vm/services/diagnosticFramework.cpp 2012-02-15 12:29:22.000000000 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012NAME, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -61,7 +61,7 @@ bool DCmdArgIter::next(TRAPS) { if (_len == 0) return false; // skipping spaces - while (_cursor < _len - 1 && isspace(_buffer[_cursor])) { + while (_cursor < _len - 1 && _buffer[_cursor] == _delim) { _cursor++; } // handling end of command line @@ -73,8 +73,10 @@ _value_len = 0; return false; } + // extracting first item, argument or option name _key_addr = &_buffer[_cursor]; + while (_cursor <= _len - 1 && _buffer[_cursor] != '=' && _buffer[_cursor] != _delim) { // argument can be surrounded by single or double quotes if (_buffer[_cursor] == '\"' || _buffer[_cursor] == '\'') { --- old/src/share/vm/services/diagnosticFramework.hpp 2012-02-15 12:29:23.000000000 +0100 +++ new/src/share/vm/services/diagnosticFramework.hpp 2012-02-15 12:29:23.000000000 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -195,6 +195,7 @@ DCmdParser() { _options = NULL; _arguments_list = NULL; + _delim = ' '; } void add_dcmd_option(GenDCmdArgument* arg); void add_dcmd_argument(GenDCmdArgument* arg);