# HG changeset patch # User coleenp # Date 1442608632 14400 # Node ID 1a17229eb64d1a019dcc9f6b628a451ade0e5b59 # Parent 54f3f085b165e68e4c91c3f5f06fc43914c639ca# Parent d8eed614f2985def452671d5a4033faec5b63e5c Merge diff -r 54f3f085b165 -r 1a17229eb64d hotspot/src/share/vm/c1/c1_GraphBuilder.cpp --- a/hotspot/src/share/vm/c1/c1_GraphBuilder.cpp Thu Sep 17 09:03:57 2015 +0200 +++ b/hotspot/src/share/vm/c1/c1_GraphBuilder.cpp Fri Sep 18 16:37:12 2015 -0400 @@ -3363,11 +3363,9 @@ return NULL; } - // negative filter: should callee NOT be inlined? returns NULL, ok to inline, or rejection msg const char* GraphBuilder::should_not_inline(ciMethod* callee) const { - if ( callee->should_exclude()) return "excluded by CompilerOracle"; - if ( callee->should_not_inline()) return "disallowed by CompilerOracle"; + if ( callee->should_not_inline()) return "disallowed by CompileCommand"; if ( callee->dont_inline()) return "don't inline by annotation"; return NULL; } @@ -3698,7 +3696,7 @@ const char* msg = ""; if (callee->force_inline()) msg = "force inline by annotation"; - if (callee->should_inline()) msg = "force inline by CompileOracle"; + if (callee->should_inline()) msg = "force inline by CompileCommand"; print_inlining(callee, msg); } else { // use heuristic controls on inlining diff -r 54f3f085b165 -r 1a17229eb64d hotspot/src/share/vm/ci/ciMethod.cpp --- a/hotspot/src/share/vm/ci/ciMethod.cpp Thu Sep 17 09:03:57 2015 +0200 +++ b/hotspot/src/share/vm/ci/ciMethod.cpp Fri Sep 18 16:37:12 2015 -0400 @@ -1044,18 +1044,6 @@ } // ------------------------------------------------------------------ -// ciMethod::should_exclude -// -// Should this method be excluded from compilation? -bool ciMethod::should_exclude() { - check_is_loaded(); - VM_ENTRY_MARK; - methodHandle mh(THREAD, get_Method()); - bool ignore; - return CompilerOracle::should_exclude(mh, ignore); -} - -// ------------------------------------------------------------------ // ciMethod::should_inline // // Should this method be inlined during compilation? diff -r 54f3f085b165 -r 1a17229eb64d hotspot/src/share/vm/ci/ciMethod.hpp --- a/hotspot/src/share/vm/ci/ciMethod.hpp Thu Sep 17 09:03:57 2015 +0200 +++ b/hotspot/src/share/vm/ci/ciMethod.hpp Fri Sep 18 16:37:12 2015 -0400 @@ -266,7 +266,6 @@ int resolve_vtable_index(ciKlass* caller, ciKlass* receiver); // Compilation directives - bool should_exclude(); bool should_inline(); bool should_not_inline(); bool should_print_assembly(); diff -r 54f3f085b165 -r 1a17229eb64d hotspot/src/share/vm/compiler/compileBroker.cpp --- a/hotspot/src/share/vm/compiler/compileBroker.cpp Thu Sep 17 09:03:57 2015 +0200 +++ b/hotspot/src/share/vm/compiler/compileBroker.cpp Fri Sep 18 16:37:12 2015 -0400 @@ -1157,7 +1157,7 @@ method->print_short_name(tty); tty->cr(); } - method->set_not_compilable(CompLevel_all, !quietly, "excluded by CompilerOracle"); + method->set_not_compilable(CompLevel_all, !quietly, "excluded by CompileCommand"); } return false; diff -r 54f3f085b165 -r 1a17229eb64d hotspot/src/share/vm/compiler/compilerOracle.cpp --- a/hotspot/src/share/vm/compiler/compilerOracle.cpp Thu Sep 17 09:03:57 2015 +0200 +++ b/hotspot/src/share/vm/compiler/compilerOracle.cpp Fri Sep 18 16:37:12 2015 -0400 @@ -24,149 +24,17 @@ #include "precompiled.hpp" #include "compiler/compilerOracle.hpp" +#include "compiler/methodMatcher.hpp" #include "memory/allocation.inline.hpp" #include "memory/oopFactory.hpp" #include "memory/resourceArea.hpp" #include "oops/klass.hpp" #include "oops/method.hpp" -#include "oops/oop.inline.hpp" #include "oops/symbol.hpp" #include "runtime/handles.inline.hpp" #include "runtime/jniHandles.hpp" #include "runtime/os.hpp" -class MethodMatcher : public CHeapObj { - public: - enum Mode { - Exact, - Prefix = 1, - Suffix = 2, - Substring = Prefix | Suffix, - Any, - Unknown = -1 - }; - - protected: - Symbol* _class_name; - Symbol* _method_name; - Symbol* _signature; - Mode _class_mode; - Mode _method_mode; - MethodMatcher* _next; - - static bool match(Symbol* candidate, Symbol* match, Mode match_mode); - - Symbol* class_name() const { return _class_name; } - Symbol* method_name() const { return _method_name; } - Symbol* signature() const { return _signature; } - - public: - MethodMatcher(Symbol* class_name, Mode class_mode, - Symbol* method_name, Mode method_mode, - Symbol* signature, MethodMatcher* next); - MethodMatcher(Symbol* class_name, Symbol* method_name, MethodMatcher* next); - - // utility method - MethodMatcher* find(methodHandle method) { - Symbol* class_name = method->method_holder()->name(); - Symbol* method_name = method->name(); - for (MethodMatcher* current = this; current != NULL; current = current->_next) { - if (match(class_name, current->class_name(), current->_class_mode) && - match(method_name, current->method_name(), current->_method_mode) && - (current->signature() == NULL || current->signature() == method->signature())) { - return current; - } - } - return NULL; - } - - bool match(methodHandle method) { - return find(method) != NULL; - } - - MethodMatcher* next() const { return _next; } - - static void print_symbol(Symbol* h, Mode mode) { - ResourceMark rm; - - if (mode == Suffix || mode == Substring || mode == Any) { - tty->print("*"); - } - if (mode != Any) { - h->print_symbol_on(tty); - } - if (mode == Prefix || mode == Substring) { - tty->print("*"); - } - } - - void print_base() { - print_symbol(class_name(), _class_mode); - tty->print("."); - print_symbol(method_name(), _method_mode); - if (signature() != NULL) { - signature()->print_symbol_on(tty); - } - } - - virtual void print() { - print_base(); - tty->cr(); - } -}; - -MethodMatcher::MethodMatcher(Symbol* class_name, Symbol* method_name, MethodMatcher* next) { - _class_name = class_name; - _method_name = method_name; - _next = next; - _class_mode = MethodMatcher::Exact; - _method_mode = MethodMatcher::Exact; - _signature = NULL; -} - - -MethodMatcher::MethodMatcher(Symbol* class_name, Mode class_mode, - Symbol* method_name, Mode method_mode, - Symbol* signature, MethodMatcher* next): - _class_mode(class_mode) - , _method_mode(method_mode) - , _next(next) - , _class_name(class_name) - , _method_name(method_name) - , _signature(signature) { -} - -bool MethodMatcher::match(Symbol* candidate, Symbol* match, Mode match_mode) { - if (match_mode == Any) { - return true; - } - - if (match_mode == Exact) { - return candidate == match; - } - - ResourceMark rm; - const char * candidate_string = candidate->as_C_string(); - const char * match_string = match->as_C_string(); - - switch (match_mode) { - case Prefix: - return strstr(candidate_string, match_string) == candidate_string; - - case Suffix: { - size_t clen = strlen(candidate_string); - size_t mlen = strlen(match_string); - return clen >= mlen && strcmp(candidate_string + clen - mlen, match_string) == 0; - } - - case Substring: - return strstr(candidate_string, match_string) != NULL; - - default: - return false; - } -} - enum OptionType { IntxType, UintxType, @@ -202,114 +70,6 @@ return DoubleType; } -template -static const T copy_value(const T value) { - return value; -} - -template<> const ccstr copy_value(const ccstr value) { - return (const ccstr)os::strdup_check_oom(value); -} - -template -class TypedMethodOptionMatcher : public MethodMatcher { - const char* _option; - OptionType _type; - const T _value; - -public: - TypedMethodOptionMatcher(Symbol* class_name, Mode class_mode, - Symbol* method_name, Mode method_mode, - Symbol* signature, const char* opt, - const T value, MethodMatcher* next) : - MethodMatcher(class_name, class_mode, method_name, method_mode, signature, next), - _type(get_type_for()), _value(copy_value(value)) { - _option = os::strdup_check_oom(opt); - } - - ~TypedMethodOptionMatcher() { - os::free((void*)_option); - } - - TypedMethodOptionMatcher* match(methodHandle method, const char* opt) { - TypedMethodOptionMatcher* current = this; - while (current != NULL) { - current = (TypedMethodOptionMatcher*)current->find(method); - if (current == NULL) { - return NULL; - } - if (strcmp(current->_option, opt) == 0) { - return current; - } - current = current->next(); - } - return NULL; - } - - TypedMethodOptionMatcher* next() { - return (TypedMethodOptionMatcher*)_next; - } - - OptionType get_type(void) { - return _type; - }; - - T value() { return _value; } - - void print() { - ttyLocker ttyl; - print_base(); - tty->print(" %s", _option); - tty->print(" "); - tty->cr(); - } -}; - -template<> -void TypedMethodOptionMatcher::print() { - ttyLocker ttyl; - print_base(); - tty->print(" intx %s", _option); - tty->print(" = " INTX_FORMAT, _value); - tty->cr(); -}; - -template<> -void TypedMethodOptionMatcher::print() { - ttyLocker ttyl; - print_base(); - tty->print(" uintx %s", _option); - tty->print(" = " UINTX_FORMAT, _value); - tty->cr(); -}; - -template<> -void TypedMethodOptionMatcher::print() { - ttyLocker ttyl; - print_base(); - tty->print(" bool %s", _option); - tty->print(" = %s", _value ? "true" : "false"); - tty->cr(); -}; - -template<> -void TypedMethodOptionMatcher::print() { - ttyLocker ttyl; - print_base(); - tty->print(" const char* %s", _option); - tty->print(" = '%s'", _value); - tty->cr(); -}; - -template<> -void TypedMethodOptionMatcher::print() { - ttyLocker ttyl; - print_base(); - tty->print(" double %s", _option); - tty->print(" = %f", _value); - tty->cr(); -}; - // this must parallel the command_names below enum OracleCommand { UnknownCommand = -1, @@ -342,8 +102,198 @@ }; class MethodMatcher; -static MethodMatcher* lists[OracleCommandCount] = { 0, }; +class TypedMethodOptionMatcher; + +static BasicMatcher* lists[OracleCommandCount] = { 0, }; +static TypedMethodOptionMatcher* option_list = NULL; + +class TypedMethodOptionMatcher : public MethodMatcher { + private: + TypedMethodOptionMatcher* _next; + const char* _option; + OptionType _type; + public: + + union { + bool bool_value; + intx intx_value; + uintx uintx_value; + double double_value; + ccstr ccstr_value; + } _u; + + TypedMethodOptionMatcher() : MethodMatcher(), + _next(NULL), + _type(UnknownType) { + _option = NULL; + memset(&_u, 0, sizeof(_u)); + } + + static TypedMethodOptionMatcher* parse_method_pattern(char*& line, const char*& error_msg); + TypedMethodOptionMatcher* match(methodHandle method, const char* opt, OptionType type); + + void init(const char* opt, OptionType type, TypedMethodOptionMatcher* next) { + _next = next; + _type = type; + _option = os::strdup_check_oom(opt); + } + + void set_next(TypedMethodOptionMatcher* next) {_next = next; } + TypedMethodOptionMatcher* next() { return _next; } + OptionType type() { return _type; } + template T value(); + template void set_value(T value); + void print(); + void print_all(); + TypedMethodOptionMatcher* clone(); + ~TypedMethodOptionMatcher(); +}; + +// A few templated accessors instead of a full template class. +template<> intx TypedMethodOptionMatcher::value() { + return _u.intx_value; +} + +template<> uintx TypedMethodOptionMatcher::value() { + return _u.uintx_value; +} + +template<> bool TypedMethodOptionMatcher::value() { + return _u.bool_value; +} + +template<> double TypedMethodOptionMatcher::value() { + return _u.double_value; +} + +template<> ccstr TypedMethodOptionMatcher::value() { + return _u.ccstr_value; +} + +template<> void TypedMethodOptionMatcher::set_value(intx value) { + _u.intx_value = value; +} + +template<> void TypedMethodOptionMatcher::set_value(uintx value) { + _u.uintx_value = value; +} + +template<> void TypedMethodOptionMatcher::set_value(double value) { + _u.double_value = value; +} + +template<> void TypedMethodOptionMatcher::set_value(bool value) { + _u.bool_value = value; +} + +template<> void TypedMethodOptionMatcher::set_value(ccstr value) { + _u.ccstr_value = (const ccstr)os::strdup_check_oom(value); +} +void TypedMethodOptionMatcher::print() { + ttyLocker ttyl; + print_base(tty); + switch (_type) { + case IntxType: + tty->print_cr(" intx %s = " INTX_FORMAT, _option, value()); + break; + case UintxType: + tty->print_cr(" uintx %s = " UINTX_FORMAT, _option, value()); + break; + case BoolType: + tty->print_cr(" bool %s = %s", _option, value() ? "true" : "false"); + break; + case DoubleType: + tty->print_cr(" double %s = %f", _option, value()); + break; + case CcstrType: + tty->print_cr(" const char* %s = '%s'", _option, value()); + break; + default: + ShouldNotReachHere(); + } +} + +void TypedMethodOptionMatcher::print_all() { + print(); + if (_next != NULL) { + tty->print(" "); + _next->print_all(); + } + } + +TypedMethodOptionMatcher* TypedMethodOptionMatcher::clone() { + TypedMethodOptionMatcher* m = new TypedMethodOptionMatcher(); + m->_class_mode = _class_mode; + m->_class_name = _class_name; + m->_method_mode = _method_mode; + m->_method_name = _method_name; + m->_signature = _signature; + // Need to ref count the symbols + if (_class_name != NULL) { + _class_name->increment_refcount(); + } + if (_method_name != NULL) { + _method_name->increment_refcount(); + } + if (_signature != NULL) { + _signature->increment_refcount(); + } + return m; +} + +TypedMethodOptionMatcher::~TypedMethodOptionMatcher() { + if (_option != NULL) { + os::free((void*)_option); + } + if (_class_name != NULL) { + _class_name->decrement_refcount(); + } + if (_method_name != NULL) { + _method_name->decrement_refcount(); + } + if (_signature != NULL) { + _signature->decrement_refcount(); + } +} + +TypedMethodOptionMatcher* TypedMethodOptionMatcher::parse_method_pattern(char*& line, const char*& error_msg) { + assert(error_msg == NULL, "Dont call here with error_msg already set"); + TypedMethodOptionMatcher* tom = new TypedMethodOptionMatcher(); + MethodMatcher::parse_method_pattern(line, error_msg, tom); + if (error_msg != NULL) { + delete tom; + return NULL; + } + return tom; +} + +TypedMethodOptionMatcher* TypedMethodOptionMatcher::match(methodHandle method, const char* opt, OptionType type) { + TypedMethodOptionMatcher* current = this; + while (current != NULL) { + // Fastest compare first. + if (current->type() == type) { + if (strcmp(current->_option, opt) == 0) { + if (current->matches(method)) { + return current; + } + } + } + current = current->next(); + } + return NULL; +} + +template +static void add_option_string(TypedMethodOptionMatcher* matcher, + const char* option, + T value) { + assert(matcher != option_list, "No circular lists please"); + matcher->init(option, get_type_for(), option_list); + matcher->set_value(value); + option_list = matcher; + return; +} static bool check_predicate(OracleCommand command, methodHandle method) { return ((lists[command] != NULL) && @@ -351,51 +301,27 @@ lists[command]->match(method)); } - -static MethodMatcher* add_predicate(OracleCommand command, - Symbol* class_name, MethodMatcher::Mode c_mode, - Symbol* method_name, MethodMatcher::Mode m_mode, - Symbol* signature) { +static void add_predicate(OracleCommand command, BasicMatcher* bm) { assert(command != OptionCommand, "must use add_option_string"); - if (command == LogCommand && !LogCompilation && lists[LogCommand] == NULL) + if (command == LogCommand && !LogCompilation && lists[LogCommand] == NULL) { tty->print_cr("Warning: +LogCompilation must be enabled in order for individual methods to be logged."); - lists[command] = new MethodMatcher(class_name, c_mode, method_name, m_mode, signature, lists[command]); - return lists[command]; -} + } + bm->set_next(lists[command]); + lists[command] = bm; -template -static MethodMatcher* add_option_string(Symbol* class_name, MethodMatcher::Mode c_mode, - Symbol* method_name, MethodMatcher::Mode m_mode, - Symbol* signature, - const char* option, - T value) { - lists[OptionCommand] = new TypedMethodOptionMatcher(class_name, c_mode, method_name, m_mode, - signature, option, value, lists[OptionCommand]); - return lists[OptionCommand]; -} - -template -static bool get_option_value(methodHandle method, const char* option, T& value) { - TypedMethodOptionMatcher* m; - if (lists[OptionCommand] != NULL - && (m = ((TypedMethodOptionMatcher*)lists[OptionCommand])->match(method, option)) != NULL - && m->get_type() == get_type_for()) { - value = m->value(); - return true; - } else { - return false; - } -} - -bool CompilerOracle::has_option_string(methodHandle method, const char* option) { - bool value = false; - get_option_value(method, option, value); - return value; + return; } template bool CompilerOracle::has_option_value(methodHandle method, const char* option, T& value) { - return ::get_option_value(method, option, value); + if (option_list != NULL) { + TypedMethodOptionMatcher* m = option_list->match(method, option, get_type_for()); + if (m != NULL) { + value = m->value(); + return true; + } + } + return false; } // Explicit instantiation for all OptionTypes supported. @@ -405,6 +331,12 @@ template bool CompilerOracle::has_option_value(methodHandle method, const char* option, ccstr& value); template bool CompilerOracle::has_option_value(methodHandle method, const char* option, double& value); +bool CompilerOracle::has_option_string(methodHandle method, const char* option) { + bool value = false; + has_option_value(method, option, value); + return value; +} + bool CompilerOracle::should_exclude(methodHandle method, bool& quietly) { quietly = true; if (lists[ExcludeCommand] != NULL) { @@ -420,19 +352,18 @@ return false; } - bool CompilerOracle::should_inline(methodHandle method) { return (check_predicate(InlineCommand, method)); } - +// Check both DontInlineCommand and ExcludeCommand here +// - consistent behavior for all compilers bool CompilerOracle::should_not_inline(methodHandle method) { - return (check_predicate(DontInlineCommand, method)); + return check_predicate(DontInlineCommand, method) || check_predicate(ExcludeCommand, method); } - bool CompilerOracle::should_print(methodHandle method) { - return (check_predicate(PrintCommand, method)); + return check_predicate(PrintCommand, method); } bool CompilerOracle::should_print_methods() { @@ -445,12 +376,10 @@ return (check_predicate(LogCommand, method)); } - bool CompilerOracle::should_break_at(methodHandle method) { return check_predicate(BreakCommand, method); } - static OracleCommand parse_command_name(const char * line, int* bytes_read) { assert(ARRAY_SIZE(command_names) == OracleCommandCount, "command_names size mismatch"); @@ -516,84 +445,12 @@ tty->cr(); }; -// The JVM specification defines the allowed characters. -// Tokens that are disallowed by the JVM specification can have -// a meaning to the parser so we need to include them here. -// The parser does not enforce all rules of the JVMS - a successful parse -// does not mean that it is an allowed name. Illegal names will -// be ignored since they never can match a class or method. -// -// '\0' and 0xf0-0xff are disallowed in constant string values -// 0x20 ' ', 0x09 '\t' and, 0x2c ',' are used in the matching -// 0x5b '[' and 0x5d ']' can not be used because of the matcher -// 0x28 '(' and 0x29 ')' are used for the signature -// 0x2e '.' is always replaced before the matching -// 0x2f '/' is only used in the class name as package separator - -#define RANGEBASE "\x1\x2\x3\x4\x5\x6\x7\x8\xa\xb\xc\xd\xe\xf" \ - "\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" \ - "\x21\x22\x23\x24\x25\x26\x27\x2a\x2b\x2c\x2d" \ - "\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f" \ - "\x40\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f" \ - "\x50\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5a\x5c\x5e\x5f" \ - "\x60\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f" \ - "\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f" \ - "\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f" \ - "\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f" \ - "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf" \ - "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf" \ - "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf" \ - "\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf" \ - "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef" - -#define RANGE0 "[*" RANGEBASE "]" -#define RANGESLASH "[*" RANGEBASE "/]" - -static MethodMatcher::Mode check_mode(char name[], const char*& error_msg) { - int match = MethodMatcher::Exact; - while (name[0] == '*') { - match |= MethodMatcher::Suffix; - // Copy remaining string plus NUL to the beginning - memmove(name, name + 1, strlen(name + 1) + 1); - } - - if (strcmp(name, "*") == 0) return MethodMatcher::Any; - - size_t len = strlen(name); - while (len > 0 && name[len - 1] == '*') { - match |= MethodMatcher::Prefix; - name[--len] = '\0'; - } - - if (strstr(name, "*") != NULL) { - error_msg = " Embedded * not allowed"; - return MethodMatcher::Unknown; - } - return (MethodMatcher::Mode)match; -} - -static bool scan_line(const char * line, - char class_name[], MethodMatcher::Mode* c_mode, - char method_name[], MethodMatcher::Mode* m_mode, - int* bytes_read, const char*& error_msg) { - *bytes_read = 0; - error_msg = NULL; - if (2 == sscanf(line, "%*[ \t]%255" RANGESLASH "%*[ ]" "%255" RANGE0 "%n", class_name, method_name, bytes_read)) { - *c_mode = check_mode(class_name, error_msg); - *m_mode = check_mode(method_name, error_msg); - return *c_mode != MethodMatcher::Unknown && *m_mode != MethodMatcher::Unknown; - } - return false; -} - // Scan next flag and value in line, return MethodMatcher object on success, NULL on failure. // On failure, error_msg contains description for the first error. // For future extensions: set error_msg on first error. -static MethodMatcher* scan_flag_and_value(const char* type, const char* line, int& total_bytes_read, - Symbol* c_name, MethodMatcher::Mode c_match, - Symbol* m_name, MethodMatcher::Mode m_match, - Symbol* signature, - char* errorbuf, const int buf_size) { +static void scan_flag_and_value(const char* type, const char* line, int& total_bytes_read, + TypedMethodOptionMatcher* matcher, + char* errorbuf, const int buf_size) { total_bytes_read = 0; int bytes_read = 0; char flag[256]; @@ -608,7 +465,8 @@ intx value; if (sscanf(line, "%*[ \t]" INTX_FORMAT "%n", &value, &bytes_read) == 1) { total_bytes_read += bytes_read; - return add_option_string(c_name, c_match, m_name, m_match, signature, flag, value); + add_option_string(matcher, flag, value); + return; } else { jio_snprintf(errorbuf, buf_size, " Value cannot be read for flag %s of type %s ", flag, type); } @@ -616,7 +474,8 @@ uintx value; if (sscanf(line, "%*[ \t]" UINTX_FORMAT "%n", &value, &bytes_read) == 1) { total_bytes_read += bytes_read; - return add_option_string(c_name, c_match, m_name, m_match, signature, flag, value); + add_option_string(matcher, flag, value); + return; } else { jio_snprintf(errorbuf, buf_size, " Value cannot be read for flag %s of type %s", flag, type); } @@ -625,7 +484,8 @@ char* value = NEW_RESOURCE_ARRAY(char, strlen(line) + 1); if (sscanf(line, "%*[ \t]%255[_a-zA-Z0-9]%n", value, &bytes_read) == 1) { total_bytes_read += bytes_read; - return add_option_string(c_name, c_match, m_name, m_match, signature, flag, (ccstr)value); + add_option_string(matcher, flag, (ccstr)value); + return; } else { jio_snprintf(errorbuf, buf_size, " Value cannot be read for flag %s of type %s", flag, type); } @@ -646,7 +506,8 @@ next_value += bytes_read; end_value = next_value-1; } - return add_option_string(c_name, c_match, m_name, m_match, signature, flag, (ccstr)value); + add_option_string(matcher, flag, (ccstr)value); + return; } else { jio_snprintf(errorbuf, buf_size, " Value cannot be read for flag %s of type %s", flag, type); } @@ -655,10 +516,12 @@ if (sscanf(line, "%*[ \t]%255[a-zA-Z]%n", value, &bytes_read) == 1) { if (strcmp(value, "true") == 0) { total_bytes_read += bytes_read; - return add_option_string(c_name, c_match, m_name, m_match, signature, flag, true); + add_option_string(matcher, flag, true); + return; } else if (strcmp(value, "false") == 0) { total_bytes_read += bytes_read; - return add_option_string(c_name, c_match, m_name, m_match, signature, flag, false); + add_option_string(matcher, flag, false); + return; } else { jio_snprintf(errorbuf, buf_size, " Value cannot be read for flag %s of type %s", flag, type); } @@ -673,7 +536,8 @@ char value[512] = ""; jio_snprintf(value, sizeof(value), "%s.%s", buffer[0], buffer[1]); total_bytes_read += bytes_read; - return add_option_string(c_name, c_match, m_name, m_match, signature, flag, atof(value)); + add_option_string(matcher, flag, atof(value)); + return; } else { jio_snprintf(errorbuf, buf_size, " Value cannot be read for flag %s of type %s", flag, type); } @@ -683,7 +547,7 @@ } else { jio_snprintf(errorbuf, buf_size, " Flag name for type %s should be alphanumeric ", type); } - return NULL; + return; } int skip_whitespace(char* line) { @@ -693,31 +557,20 @@ return whitespace_read; } +void CompilerOracle::print_parse_error(const char*& error_msg, char* original_line) { + assert(error_msg != NULL, "Must have error_message"); + + ttyLocker ttyl; + tty->print_cr("CompileCommand: An error occurred during parsing"); + tty->print_cr("Line: %s", original_line); + tty->print_cr("Error: %s", error_msg); + CompilerOracle::print_tip(); +} + void CompilerOracle::parse_from_line(char* line) { if (line[0] == '\0') return; if (line[0] == '#') return; - bool have_colon = (strstr(line, "::") != NULL); - for (char* lp = line; *lp != '\0'; lp++) { - // Allow '.' to separate the class name from the method name. - // This is the preferred spelling of methods: - // exclude java/lang/String.indexOf(I)I - // Allow ',' for spaces (eases command line quoting). - // exclude,java/lang/String.indexOf - // For backward compatibility, allow space as separator also. - // exclude java/lang/String indexOf - // exclude,java/lang/String,indexOf - // For easy cut-and-paste of method names, allow VM output format - // as produced by Method::print_short_name: - // exclude java.lang.String::indexOf - // For simple implementation convenience here, convert them all to space. - if (have_colon) { - if (*lp == '.') *lp = '/'; // dots build the package prefix - if (*lp == ':') *lp = ' '; - } - if (*lp == ',' || *lp == '.') *lp = ' '; - } - char* original_line = line; int bytes_read; OracleCommand command = parse_command_name(line, &bytes_read); @@ -742,109 +595,86 @@ return; } - MethodMatcher::Mode c_match = MethodMatcher::Exact; - MethodMatcher::Mode m_match = MethodMatcher::Exact; - char class_name[256]; - char method_name[256]; - char sig[1024]; - char errorbuf[1024]; - const char* error_msg = NULL; // description of first error that appears - MethodMatcher* match = NULL; + const char* error_msg = NULL; + if (command == OptionCommand) { + // Look for trailing options. + // + // Two types of trailing options are + // supported: + // + // (1) CompileCommand=option,Klass::method,flag + // (2) CompileCommand=option,Klass::method,type,flag,value + // + // Type (1) is used to enable a boolean flag for a method. + // + // Type (2) is used to support options with a value. Values can have the + // the following types: intx, uintx, bool, ccstr, ccstrlist, and double. + // + // For future extensions: extend scan_flag_and_value() - if (scan_line(line, class_name, &c_match, method_name, &m_match, &bytes_read, error_msg)) { - EXCEPTION_MARK; - Symbol* c_name = SymbolTable::new_symbol(class_name, CHECK); - Symbol* m_name = SymbolTable::new_symbol(method_name, CHECK); - Symbol* signature = NULL; - - line += bytes_read; - - // there might be a signature following the method. - // signatures always begin with ( so match that by hand - line += skip_whitespace(line); - if (1 == sscanf(line, "(%254[[);/" RANGEBASE "]%n", sig + 1, &bytes_read)) { - sig[0] = '('; - line += bytes_read; - signature = SymbolTable::new_symbol(sig, CHECK); + char option[256]; // stores flag for Type (1) and type of Type (2) + line++; // skip the ',' + TypedMethodOptionMatcher* archetype = TypedMethodOptionMatcher::parse_method_pattern(line, error_msg); + if (archetype == NULL) { + assert(error_msg != NULL, "Must have error_message"); + print_parse_error(error_msg, original_line); + return; } - if (command == OptionCommand) { - // Look for trailing options. - // - // Two types of trailing options are - // supported: - // - // (1) CompileCommand=option,Klass::method,flag - // (2) CompileCommand=option,Klass::method,type,flag,value - // - // Type (1) is used to enable a boolean flag for a method. - // - // Type (2) is used to support options with a value. Values can have the - // the following types: intx, uintx, bool, ccstr, ccstrlist, and double. - // - // For future extensions: extend scan_flag_and_value() - char option[256]; // stores flag for Type (1) and type of Type (2) + line += skip_whitespace(line); + + // This is unnecessarily complex. Should retire multi-option lines and skip while loop + while (sscanf(line, "%255[a-zA-Z0-9]%n", option, &bytes_read) == 1) { + line += bytes_read; - line += skip_whitespace(line); - while (sscanf(line, "%255[a-zA-Z0-9]%n", option, &bytes_read) == 1) { - if (match != NULL && !_quiet) { - // Print out the last match added - ttyLocker ttyl; - tty->print("CompileCommand: %s ", command_names[command]); - match->print(); + // typed_matcher is used as a blueprint for each option, deleted at the end + TypedMethodOptionMatcher* typed_matcher = archetype->clone(); + if (strcmp(option, "intx") == 0 + || strcmp(option, "uintx") == 0 + || strcmp(option, "bool") == 0 + || strcmp(option, "ccstr") == 0 + || strcmp(option, "ccstrlist") == 0 + || strcmp(option, "double") == 0 + ) { + char errorbuf[1024] = {0}; + // Type (2) option: parse flag name and value. + scan_flag_and_value(option, line, bytes_read, typed_matcher, errorbuf, sizeof(errorbuf)); + if (*errorbuf != '\0') { + error_msg = errorbuf; + print_parse_error(error_msg, original_line); + return; } line += bytes_read; - - if (strcmp(option, "intx") == 0 - || strcmp(option, "uintx") == 0 - || strcmp(option, "bool") == 0 - || strcmp(option, "ccstr") == 0 - || strcmp(option, "ccstrlist") == 0 - || strcmp(option, "double") == 0 - ) { + } else { + // Type (1) option + add_option_string(typed_matcher, option, true); + } + if (typed_matcher != NULL && !_quiet) { + // Print out the last match added + assert(error_msg == NULL, "No error here"); + ttyLocker ttyl; + tty->print("CompileCommand: %s ", command_names[command]); + typed_matcher->print(); + } + line += skip_whitespace(line); + } // while( + delete archetype; + } else { // not an OptionCommand) + assert(error_msg == NULL, "Don't call here with error_msg already set"); - // Type (2) option: parse flag name and value. - match = scan_flag_and_value(option, line, bytes_read, - c_name, c_match, m_name, m_match, signature, - errorbuf, sizeof(errorbuf)); - if (match == NULL) { - error_msg = errorbuf; - break; - } - line += bytes_read; - } else { - // Type (1) option - match = add_option_string(c_name, c_match, m_name, m_match, signature, option, true); - } - line += skip_whitespace(line); - } // while( - } else { - match = add_predicate(command, c_name, c_match, m_name, m_match, signature); + BasicMatcher* matcher = BasicMatcher::parse_method_pattern(line, error_msg); + if (error_msg != NULL) { + assert(matcher == NULL, "consistency"); + print_parse_error(error_msg, original_line); + return; } - } - ttyLocker ttyl; - if (error_msg != NULL) { - // an error has happened - tty->print_cr("CompileCommand: An error occured during parsing"); - tty->print_cr(" \"%s\"", original_line); - if (error_msg != NULL) { - tty->print_cr("%s", error_msg); - } - CompilerOracle::print_tip(); - - } else { - // check for remaining characters - bytes_read = 0; - sscanf(line, "%*[ \t]%n", &bytes_read); - if (line[bytes_read] != '\0') { - tty->print_cr("CompileCommand: Bad pattern"); - tty->print_cr(" \"%s\"", original_line); - tty->print_cr(" Unrecognized text %s after command ", line); - CompilerOracle::print_tip(); - } else if (match != NULL && !_quiet) { + add_predicate(command, matcher); + if (!_quiet) { + ttyLocker ttyl; tty->print("CompileCommand: %s ", command_names[command]); - match->print(); + matcher->print(tty); + tty->cr(); } } } @@ -1045,10 +875,12 @@ Symbol* m_name = SymbolTable::new_symbol(methodName, CHECK); Symbol* signature = NULL; - add_predicate(CompileOnlyCommand, c_name, c_match, m_name, m_match, signature); + BasicMatcher* bm = new BasicMatcher(); + bm->init(c_name, c_match, m_name, m_match, signature); + add_predicate(CompileOnlyCommand, bm); if (PrintVMOptions) { tty->print("CompileOnly: compileonly "); - lists[CompileOnlyCommand]->print(); + lists[CompileOnlyCommand]->print_all(tty); } className = NULL; diff -r 54f3f085b165 -r 1a17229eb64d hotspot/src/share/vm/compiler/compilerOracle.hpp --- a/hotspot/src/share/vm/compiler/compilerOracle.hpp Thu Sep 17 09:03:57 2015 +0200 +++ b/hotspot/src/share/vm/compiler/compilerOracle.hpp Fri Sep 18 16:37:12 2015 -0400 @@ -35,6 +35,7 @@ private: static bool _quiet; static void print_tip(); + static void print_parse_error(const char*& error_msg, char* original_line); public: diff -r 54f3f085b165 -r 1a17229eb64d hotspot/src/share/vm/compiler/methodMatcher.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/share/vm/compiler/methodMatcher.cpp Fri Sep 18 16:37:12 2015 -0400 @@ -0,0 +1,347 @@ +/* + * Copyright (c) 2015, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "precompiled.hpp" +#include "compiler/methodMatcher.hpp" +#include "memory/oopFactory.hpp" +#include "oops/oop.inline.hpp" + +// The JVM specification defines the allowed characters. +// Tokens that are disallowed by the JVM specification can have +// a meaning to the parser so we need to include them here. +// The parser does not enforce all rules of the JVMS - a successful parse +// does not mean that it is an allowed name. Illegal names will +// be ignored since they never can match a class or method. +// +// '\0' and 0xf0-0xff are disallowed in constant string values +// 0x20 ' ', 0x09 '\t' and, 0x2c ',' are used in the matching +// 0x5b '[' and 0x5d ']' can not be used because of the matcher +// 0x28 '(' and 0x29 ')' are used for the signature +// 0x2e '.' is always replaced before the matching +// 0x2f '/' is only used in the class name as package separator + +#define RANGEBASE "\x1\x2\x3\x4\x5\x6\x7\x8\xa\xb\xc\xd\xe\xf" \ + "\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" \ + "\x21\x22\x23\x24\x25\x26\x27\x2a\x2b\x2c\x2d" \ + "\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f" \ + "\x40\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f" \ + "\x50\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5a\x5c\x5e\x5f" \ + "\x60\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f" \ + "\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f" \ + "\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f" \ + "\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f" \ + "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf" \ + "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf" \ + "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf" \ + "\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf" \ + "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef" + +#define RANGE0 "[*" RANGEBASE "]" +#define RANGESLASH "[*" RANGEBASE "/]" + +MethodMatcher::MethodMatcher(): + _class_mode(Exact) + , _method_mode(Exact) + , _class_name(NULL) + , _method_name(NULL) + , _signature(NULL) { +} + +MethodMatcher::~MethodMatcher() { + if (_class_name != NULL) { + _class_name->decrement_refcount(); + } + if (_method_name != NULL) { + _method_name->decrement_refcount(); + } + if (_signature != NULL) { + _signature->decrement_refcount(); + } +} + +void MethodMatcher::init(Symbol* class_name, Mode class_mode, + Symbol* method_name, Mode method_mode, + Symbol* signature) { + _class_mode = class_mode; + _method_mode = method_mode; + _class_name = class_name; + _method_name = method_name; + _signature = signature; +} + +bool MethodMatcher::canonicalize(char * line, const char *& error_msg) { + char* colon = strstr(line, "::"); + bool have_colon = (colon != NULL); + if (have_colon) { + // Don't allow multiple '::' + if (colon + 2 != '\0') { + if (strstr(colon+2, "::")) { + error_msg = "Method pattern only allows one '::' allowed"; + return false; + } + } + + bool in_signature = false; + char* pos = line; + if (pos != NULL) { + for (char* lp = pos + 1; *lp != '\0'; lp++) { + if (*lp == '(') { + break; + } + + if (*lp == '/') { + error_msg = "Method pattern uses '/' together with '::'"; + return false; + } + } + } + } else { + // Don't allow mixed package separators + char* pos = strchr(line, '.'); + bool in_signature = false; + if (pos != NULL) { + for (char* lp = pos + 1; *lp != '\0'; lp++) { + if (*lp == '(') { + in_signature = true; + } + + // After any comma the method pattern has ended + if (*lp == ',') { + break; + } + + if (!in_signature && (*lp == '/')) { + error_msg = "Method pattern uses mixed '/' and '.' package separators"; + return false; + } + + if (*lp == '.') { + error_msg = "Method pattern uses multiple '.' in pattern"; + return false; + } + } + } + } + + for (char* lp = line; *lp != '\0'; lp++) { + // Allow '.' to separate the class name from the method name. + // This is the preferred spelling of methods: + // exclude java/lang/String.indexOf(I)I + // Allow ',' for spaces (eases command line quoting). + // exclude,java/lang/String.indexOf + // For backward compatibility, allow space as separator also. + // exclude java/lang/String indexOf + // exclude,java/lang/String,indexOf + // For easy cut-and-paste of method names, allow VM output format + // as produced by Method::print_short_name: + // exclude java.lang.String::indexOf + // For simple implementation convenience here, convert them all to space. + + if (have_colon) { + if (*lp == '.') *lp = '/'; // dots build the package prefix + if (*lp == ':') *lp = ' '; + } + if (*lp == ',' || *lp == '.') *lp = ' '; + } + return true; +} + +bool MethodMatcher::match(Symbol* candidate, Symbol* match, Mode match_mode) const { + if (match_mode == Any) { + return true; + } + + if (match_mode == Exact) { + return candidate == match; + } + + ResourceMark rm; + const char * candidate_string = candidate->as_C_string(); + const char * match_string = match->as_C_string(); + + switch (match_mode) { + case Prefix: + return strstr(candidate_string, match_string) == candidate_string; + + case Suffix: { + size_t clen = strlen(candidate_string); + size_t mlen = strlen(match_string); + return clen >= mlen && strcmp(candidate_string + clen - mlen, match_string) == 0; + } + + case Substring: + return strstr(candidate_string, match_string) != NULL; + + default: + return false; + } +} + +static MethodMatcher::Mode check_mode(char name[], const char*& error_msg) { + int match = MethodMatcher::Exact; + if (name[0] == '*') { + if (strlen(name) == 1) { + return MethodMatcher::Any; + } + match |= MethodMatcher::Suffix; + memmove(name, name + 1, strlen(name + 1) + 1); + } + + size_t len = strlen(name); + if (len > 0 && name[len - 1] == '*') { + match |= MethodMatcher::Prefix; + name[--len] = '\0'; + } + + if (strlen(name) == 0) { + error_msg = "** Not a valid pattern"; + return MethodMatcher::Any; + } + + if (strstr(name, "*") != NULL) { + error_msg = " Embedded * not allowed"; + return MethodMatcher::Unknown; + } + return (MethodMatcher::Mode)match; +} + +// Skip any leading spaces +void skip_leading_spaces(char*& line, int* total_bytes_read ) { + int bytes_read = 0; + sscanf(line, "%*[ \t]%n", &bytes_read); + if (bytes_read > 0) { + line += bytes_read; + *total_bytes_read += bytes_read; + } +} + +void MethodMatcher::parse_method_pattern(char*& line, const char*& error_msg, MethodMatcher* matcher) { + MethodMatcher::Mode c_match; + MethodMatcher::Mode m_match; + char class_name[256] = {0}; + char method_name[256] = {0}; + char sig[1024] = {0}; + int bytes_read = 0; + int total_bytes_read = 0; + + assert(error_msg == NULL, "Dont call here with error_msg already set"); + + if (!MethodMatcher::canonicalize(line, error_msg)) { + assert(error_msg != NULL, "Message must be set if parsing failed"); + return; + } + + skip_leading_spaces(line, &total_bytes_read); + + if (2 == sscanf(line, "%255" RANGESLASH "%*[ ]" "%255" RANGE0 "%n", class_name, method_name, &bytes_read)) { + c_match = check_mode(class_name, error_msg); + m_match = check_mode(method_name, error_msg); + + if ((strchr(class_name, '<') != NULL) || (strchr(class_name, '>') != NULL)) { + error_msg = "Chars '<' and '>' not allowed in class name"; + return; + } + if ((strchr(method_name, '<') != NULL) || (strchr(method_name, '>') != NULL)) { + if ((strncmp("", method_name, 255) != 0) && (strncmp("", method_name, 255) != 0)) { + error_msg = "Chars '<' and '>' only allowed in and "; + return; + } + } + + if (c_match == MethodMatcher::Unknown || m_match == MethodMatcher::Unknown) { + assert(error_msg != NULL, "Must have been set by check_mode()"); + return; + } + + EXCEPTION_MARK; + Symbol* signature = NULL; + line += bytes_read; + bytes_read = 0; + + skip_leading_spaces(line, &total_bytes_read); + + // there might be a signature following the method. + // signatures always begin with ( so match that by hand + if (line[0] == '(') { + line++; + sig[0] = '('; + // scan the rest + if (1 == sscanf(line, "%254[[);/" RANGEBASE "]%n", sig+1, &bytes_read)) { + if (strchr(sig, '*') != NULL) { + error_msg = " Wildcard * not allowed in signature"; + return; + } + line += bytes_read; + } + signature = SymbolTable::new_symbol(sig, CHECK); + } + Symbol* c_name = SymbolTable::new_symbol(class_name, CHECK); + Symbol* m_name = SymbolTable::new_symbol(method_name, CHECK); + + matcher->init(c_name, c_match, m_name, m_match, signature); + return; + } else { + error_msg = "Could not parse method pattern"; + } +} + +bool MethodMatcher::matches(methodHandle method) const { + Symbol* class_name = method->method_holder()->name(); + Symbol* method_name = method->name(); + Symbol* signature = method->signature(); + + if (match(class_name, this->class_name(), _class_mode) && + match(method_name, this->method_name(), _method_mode) && + ((this->signature() == NULL) || match(signature, this->signature(), Prefix))) { + return true; + } + return false; +} + +void MethodMatcher::print_symbol(outputStream* st, Symbol* h, Mode mode) { + ResourceMark rm; + + if (mode == Suffix || mode == Substring || mode == Any) { + st->print("*"); + } + if (mode != Any) { + h->print_symbol_on(st); + } + if (mode == Prefix || mode == Substring) { + st->print("*"); + } +} + +void MethodMatcher::print_base(outputStream* st) { + print_symbol(st, class_name(), _class_mode); + st->print("."); + print_symbol(st, method_name(), _method_mode); + if (signature() != NULL) { + signature()->print_symbol_on(st); + } +} + + + + diff -r 54f3f085b165 -r 1a17229eb64d hotspot/src/share/vm/compiler/methodMatcher.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/share/vm/compiler/methodMatcher.hpp Fri Sep 18 16:37:12 2015 -0400 @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2015, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef SHARE_VM_COMPILER_METHODMATCHER_HPP +#define SHARE_VM_COMPILER_METHODMATCHER_HPP + +#include "memory/allocation.inline.hpp" +#include "runtime/handles.inline.hpp" +#include "memory/resourceArea.hpp" + +class MethodMatcher : public CHeapObj { + public: + enum Mode { + Exact, + Prefix = 1, + Suffix = 2, + Substring = Prefix | Suffix, + Any, + Unknown = -1 + }; + + protected: + Symbol* _class_name; + Symbol* _method_name; + Symbol* _signature; + Mode _class_mode; + Mode _method_mode; + + public: + Symbol* class_name() const { return _class_name; } + Mode class_mode() const { return _class_mode; } + Symbol* method_name() const { return _method_name; } + Mode method_mode() const { return _method_mode; } + Symbol* signature() const { return _signature; } + + MethodMatcher(); + ~MethodMatcher(); + + void init(Symbol* class_name, Mode class_mode, Symbol* method_name, Mode method_mode, Symbol* signature); + static void parse_method_pattern(char*& line, const char*& error_msg, MethodMatcher* m); + static void print_symbol(outputStream* st, Symbol* h, Mode mode); + bool matches(methodHandle method) const; + void print_base(outputStream* st); + + private: + static bool canonicalize(char * line, const char *& error_msg); + bool match(Symbol* candidate, Symbol* match, Mode match_mode) const; +}; + +class BasicMatcher : public MethodMatcher { +private: + BasicMatcher* _next; +public: + + BasicMatcher() : MethodMatcher(), + _next(NULL) { + } + + BasicMatcher(BasicMatcher* next) : + _next(next) { + } + + static BasicMatcher* parse_method_pattern(char* line, const char*& error_msg) { + assert(error_msg == NULL, "Dont call here with error_msg already set"); + BasicMatcher* bm = new BasicMatcher(); + MethodMatcher::parse_method_pattern(line, error_msg, bm); + if (error_msg != NULL) { + delete bm; + return NULL; + } + + // check for bad trailing characters + int bytes_read = 0; + sscanf(line, "%*[ \t]%n", &bytes_read); + if (line[bytes_read] != '\0') { + error_msg = "Unrecognized trailing text after method pattern"; + delete bm; + return NULL; + } + return bm; + } + + bool match(methodHandle method) { + for (BasicMatcher* current = this; current != NULL; current = current->next()) { + if (current->matches(method)) { + return true; + } + } + return false; + } + + void set_next(BasicMatcher* next) { _next = next; } + BasicMatcher* next() { return _next; } + + void print(outputStream* st) { print_base(st); } + void print_all(outputStream* st) { + print_base(st); + if (_next != NULL) { + _next->print_all(st); + } + } +}; + +#endif // SHARE_VM_COMPILER_METHODMATCHER_HPP + diff -r 54f3f085b165 -r 1a17229eb64d hotspot/src/share/vm/opto/bytecodeInfo.cpp --- a/hotspot/src/share/vm/opto/bytecodeInfo.cpp Thu Sep 17 09:03:57 2015 +0200 +++ b/hotspot/src/share/vm/opto/bytecodeInfo.cpp Fri Sep 18 16:37:12 2015 -0400 @@ -114,7 +114,7 @@ CompileTask::print_inline_indent(inline_level()); tty->print_cr("Inlined method is hot: "); } - set_msg("force inline by CompilerOracle"); + set_msg("force inline by CompileCommand"); _forced_inline = true; return true; } @@ -223,12 +223,12 @@ // ignore heuristic controls on inlining if (callee_method->should_inline()) { - set_msg("force inline by CompilerOracle"); + set_msg("force inline by CompileCommand"); return false; } if (callee_method->should_not_inline()) { - set_msg("disallowed by CompilerOracle"); + set_msg("disallowed by CompileCommand"); return true; } @@ -470,11 +470,6 @@ } } } - // We will attempt to see if a class/field/etc got properly loaded. If it - // did not, it may attempt to throw an exception during our probing. Catch - // and ignore such exceptions and do not attempt to compile the method. - if( callee_method->should_exclude() ) return false; - return true; } diff -r 54f3f085b165 -r 1a17229eb64d hotspot/src/share/vm/prims/whitebox.cpp --- a/hotspot/src/share/vm/prims/whitebox.cpp Thu Sep 17 09:03:57 2015 +0200 +++ b/hotspot/src/share/vm/prims/whitebox.cpp Fri Sep 18 16:37:12 2015 -0400 @@ -29,6 +29,7 @@ #include "classfile/classLoaderData.hpp" #include "classfile/stringTable.hpp" #include "code/codeCache.hpp" +#include "compiler/methodMatcher.hpp" #include "jvmtifiles/jvmtiEnv.hpp" #include "memory/metadataFactory.hpp" #include "memory/metaspaceShared.hpp" @@ -625,6 +626,32 @@ return (mh->queued_for_compilation() || nm != NULL); WB_END + +WB_ENTRY(jint, WB_MatchesMethod(JNIEnv* env, jobject o, jobject method, jstring pattern)) + jmethodID jmid = reflected_method_to_jmid(thread, env, method); + CHECK_JNI_EXCEPTION_(env, JNI_FALSE); + + methodHandle mh(THREAD, Method::checked_resolve_jmethod_id(jmid)); + + ResourceMark rm; + char* method_str = java_lang_String::as_utf8_string(JNIHandles::resolve_non_null(pattern)); + + const char* error_msg = NULL; + + BasicMatcher* m = BasicMatcher::parse_method_pattern(method_str, error_msg); + if (m == NULL) { + assert(error_msg != NULL, "Must have error_msg"); + tty->print_cr("Got error: %s", error_msg); + return -1; + } + + // Pattern works - now check if it matches + int result = m->matches(mh); + delete m; + assert(result == 0 || result == 1, "Result out of range"); + return result; +WB_END + class AlwaysFalseClosure : public BoolObjectClosure { public: bool do_object_b(oop p) { return false; } @@ -1430,6 +1457,9 @@ CC"(Ljava/lang/reflect/Executable;)V", (void*)&WB_ClearMethodState}, {CC"lockCompilation", CC"()V", (void*)&WB_LockCompilation}, {CC"unlockCompilation", CC"()V", (void*)&WB_UnlockCompilation}, + {CC"matchesMethod", + CC"(Ljava/lang/reflect/Executable;Ljava/lang/String;)I", + (void*)&WB_MatchesMethod}, {CC"isConstantVMFlag", CC"(Ljava/lang/String;)Z", (void*)&WB_IsConstantVMFlag}, {CC"isLockedVMFlag", CC"(Ljava/lang/String;)Z", (void*)&WB_IsLockedVMFlag}, {CC"setBooleanVMFlag", CC"(Ljava/lang/String;Z)V",(void*)&WB_SetBooleanVMFlag}, diff -r 54f3f085b165 -r 1a17229eb64d hotspot/src/share/vm/runtime/globals.hpp --- a/hotspot/src/share/vm/runtime/globals.hpp Thu Sep 17 09:03:57 2015 +0200 +++ b/hotspot/src/share/vm/runtime/globals.hpp Fri Sep 18 16:37:12 2015 -0400 @@ -3135,7 +3135,7 @@ \ develop(intx, MaxForceInlineLevel, 100, \ "maximum number of nested calls that are forced for inlining " \ - "(using CompilerOracle or marked w/ @ForceInline)") \ + "(using CompileCommand or marked w/ @ForceInline)") \ \ product_pd(intx, InlineSmallCode, \ "Only inline already compiled methods if their code size is " \ diff -r 54f3f085b165 -r 1a17229eb64d hotspot/test/compiler/c2/5091921/Test7005594.sh --- a/hotspot/test/compiler/c2/5091921/Test7005594.sh Thu Sep 17 09:03:57 2015 +0200 +++ b/hotspot/test/compiler/c2/5091921/Test7005594.sh Fri Sep 18 16:37:12 2015 -0400 @@ -78,7 +78,7 @@ ${COMPILEJAVA}/bin/javac ${TESTJAVACOPTS} -d . Test7005594.java -${TESTJAVA}/bin/java ${TESTOPTS} -Xmx1600m -Xms1600m -XX:+IgnoreUnrecognizedVMOptions -XX:-ZapUnusedHeapArea -Xcomp -XX:CompileOnly=Test7005594.test Test7005594 > test.out 2>&1 +${TESTJAVA}/bin/java ${TESTOPTS} -Xmx1600m -Xms1600m -XX:+IgnoreUnrecognizedVMOptions -XX:-ZapUnusedHeapArea -Xcomp -XX:CompileOnly=Test7005594.test -XX:CompileCommand=quiet Test7005594 > test.out 2>&1 result=$? diff -r 54f3f085b165 -r 1a17229eb64d hotspot/test/compiler/oracle/CheckCompileCommandOption.java --- a/hotspot/test/compiler/oracle/CheckCompileCommandOption.java Thu Sep 17 09:03:57 2015 +0200 +++ b/hotspot/test/compiler/oracle/CheckCompileCommandOption.java Fri Sep 18 16:37:12 2015 -0400 @@ -66,7 +66,6 @@ "CompileCommand: option com/oracle/Test.test bool MyBoolOption1 = true", "CompileCommand: option com/oracle/Test.test bool MyBoolOption2 = true", "CompileCommand: option com/oracle/Test.test bool MyBoolOption3 = true", - "CompileCommand: option com/oracle/Test.test bool MyBoolOption4 = true", "CompileCommand: option com/oracle/Test.test bool MyBoolOption5 = true", "CompileCommand: option com/oracle/Test.test bool MyBoolOption6 = true", "CompileCommand: option com/oracle/Test.test bool MyBoolOption7 = true", @@ -74,7 +73,6 @@ "CompileCommand: option com/oracle/Test.test(I) bool MyBoolOption9 = true", "CompileCommand: option com/oracle/Test.test(I) bool MyBoolOption10 = true", "CompileCommand: option com/oracle/Test.test(I) bool MyBoolOption11 = true", - "CompileCommand: option com/oracle/Test.test(I) bool MyBoolOption12 = true", "CompileCommand: option com/oracle/Test.test(I) bool MyBoolOption13 = true", "CompileCommand: option com/oracle/Test.test(I) bool MyBoolOption14 = true", "CompileCommand: option com/oracle/Test.test(I) bool MyBoolOption15 = true", @@ -96,7 +94,6 @@ "-XX:CompileCommand=option,com/oracle/Test.test,MyBoolOption1", "-XX:CompileCommand=option,com/oracle/Test,test,MyBoolOption2", "-XX:CompileCommand=option,com.oracle.Test::test,MyBoolOption3", - "-XX:CompileCommand=option,com/oracle/Test::test,MyBoolOption4", "-XX:CompileCommand=option,com/oracle/Test.test,MyBoolOption5,MyBoolOption6", "-XX:CompileCommand=option,com/oracle/Test,test,MyBoolOption7,MyBoolOption8", "-version" @@ -108,7 +105,6 @@ "CompileCommand: option com/oracle/Test.test bool MyBoolOption1 = true", "CompileCommand: option com/oracle/Test.test bool MyBoolOption2 = true", "CompileCommand: option com/oracle/Test.test bool MyBoolOption3 = true", - "CompileCommand: option com/oracle/Test.test bool MyBoolOption4 = true", "CompileCommand: option com/oracle/Test.test bool MyBoolOption5 = true", "CompileCommand: option com/oracle/Test.test bool MyBoolOption6 = true", "CompileCommand: option com/oracle/Test.test bool MyBoolOption7 = true", @@ -198,7 +194,7 @@ out.shouldContain(expected_output); } - out.shouldNotContain("CompileCommand: An error occured during parsing"); + out.shouldNotContain("CompileCommand: An error occurred during parsing"); out.shouldHaveExitValue(0); } @@ -209,7 +205,7 @@ pb = ProcessTools.createJavaProcessBuilder(arguments); out = new OutputAnalyzer(pb.start()); - out.shouldContain("CompileCommand: An error occured during parsing"); + out.shouldContain("CompileCommand: An error occurred during parsing"); out.shouldHaveExitValue(0); } diff -r 54f3f085b165 -r 1a17229eb64d hotspot/test/compiler/oracle/MethodMatcherTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/compiler/oracle/MethodMatcherTest.java Fri Sep 18 16:37:12 2015 -0400 @@ -0,0 +1,239 @@ +/* + * Copyright (c) 2015, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test MethodMatcherTest + * @library /testlibrary /../../test/lib + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI MethodMatcherTest + * @summary Testing of compiler/MethodMatcher + * @bug 8135068 + */ + +import java.lang.reflect.Method; +import java.util.ArrayList; + +import sun.hotspot.WhiteBox; + +public class MethodMatcherTest { + + /** Instance of WhiteBox */ + protected static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox(); + + Method helper; + Method getDate; + Method inner; + Method toString; + + static final int MATCH = 1; + static final int NO_MATCH = 0; + static final int PARSING_FAILURE = -1; + + public MethodMatcherTest() { + } + + public void test() throws Exception { + // instantiate before calling getMethod on innerHelper + TestCases testCases = new TestCases(); + + helper = getMethod(MethodMatcherTest.class, "helper"); + getDate = getMethod(java.util.Date.class, "getDate"); + inner = getMethod(TestCases.class, "innerHelper"); + toString = getMethod(String.class, "toString"); + + testCases.add(helper, "pool/sub/Klass.method(I[Ljava/lang/String;Ljava/lang/Integer;[B[[D)V", NO_MATCH); + + // These should be improved to parsing failed in the future + testCases.add(helper, "*Klass*,*$method*::", NO_MATCH); + testCases.add(helper, "*Klass *+*", NO_MATCH); + testCases.add(helper, "*Klass*::*method*", NO_MATCH); + + testCases.add(helper, "*,**", PARSING_FAILURE); + testCases.add(helper, "*,*(I[Ljava/lang/String;Lj]ava/lang/Integer;[B[[D)V", PARSING_FAILURE); + testCases.add(helper, "*,*)method*.", PARSING_FAILURE); + testCases.add(helper, "{pool.subpack.Klass}* *", PARSING_FAILURE); + testCases.add(helper, "*Klass met]hod/", PARSING_FAILURE); + testCases.add(helper, "pool::su@%b::Klass* *)method.", PARSING_FAILURE); + testCases.add(helper, "0pool/sub/Klass,*{method}*.(I[Ljava/lang/String;Lj]ava/lang/Integer;[B[[D)V", PARSING_FAILURE); + testCases.add(helper, "*Klass nonexistent::)(I[Ljava/lang/String;Ljava/lang/Integer;[B[[D)V", PARSING_FAILURE); + testCases.add(helper, "pool,su]b,Klass*,*)method*/", PARSING_FAILURE); + testCases.add(helper, "_pool,sub,Klass*,met@%hod,(0)V", PARSING_FAILURE); + + testCases.add(helper, "*.*", MATCH); + testCases.add(helper, "MethodMatcherTest.*", MATCH); + testCases.add(helper, "MethodMatcherTest.helper", MATCH); + testCases.add(helper, "MethodMatcherTest.helper()", MATCH); + testCases.add(helper, "MethodMatcherTest.helper()V", MATCH); + testCases.add(helper, "MethodMatcherTest.helper()V;", NO_MATCH); + testCases.add(helper, "MethodMatcherTest.helper()I", NO_MATCH); + testCases.add(helper, "MethodMatcherTest.helperX", NO_MATCH); + testCases.add(helper, "MethodMatcherTestX.helper;", NO_MATCH); + testCases.add(helper, "abc.*", NO_MATCH); + testCases.add(helper, "*.abc", NO_MATCH); + + testCases.add(getDate, "*.*", MATCH); + testCases.add(getDate, "*.getDate", MATCH); + testCases.add(getDate, "java/util/Date.getDate", MATCH); + testCases.add(getDate, "java/util/Date.*", MATCH); + + testCases.add(inner, "*.*", MATCH); + testCases.add(inner, "MethodMatcherTest$TestCases.innerHelper", MATCH); + testCases.add(inner, "MethodMatcherTest*.innerHelper", MATCH); + testCases.add(inner, "MethodMatcherTest$*.innerHelper", MATCH); + testCases.add(inner, "*$TestCases.innerHelper", MATCH); + testCases.add(inner, "*TestCases.innerHelper", MATCH); + testCases.add(inner, "TestCases.innerHelper", NO_MATCH); + testCases.add(inner, "MethodMatcherTest.innerHelper", NO_MATCH); + + testCases.add(toString, "*.*", MATCH); + testCases.add(toString, "java/lang/String.toString", MATCH); + testCases.add(toString, "java.lang.String::toString", MATCH); + + testCases.add(toString, "java/lang/String::toString", PARSING_FAILURE); + testCases.add(toString, "java.lang/String::toString", PARSING_FAILURE); + testCases.add(toString, "java.lang/String.toString", PARSING_FAILURE); + testCases.add(toString, "java::lang::String::toString", PARSING_FAILURE); + + testCases.add(toString, "java/lang/String.toString(*)", PARSING_FAILURE); + testCases.add(toString, "java/lang/String.toString(L*", PARSING_FAILURE); + testCases.add(toString, "java/lang/String.toString*(lsd)l", NO_MATCH); + testCases.add(toString, "java/lang/String.toString(lsd)l", NO_MATCH); + testCases.add(toString, "java/lang/String.toString (", MATCH); + testCases.add(toString, "java/lang/String.toString ()", MATCH); + testCases.add(toString, "java/lang/String.toString ()L", MATCH); + testCases.add(toString, "java/lang/String.toString ()Lj", MATCH); + testCases.add(toString, "java/lang/String.toString ()Ls", NO_MATCH); + testCases.add(toString, "java/lang/String.toString*(", MATCH); + testCases.add(toString, "java/lang/String.toString* (", MATCH); + testCases.add(toString, "java/lang/String.toString*(;", NO_MATCH); + testCases.add(toString, "java/lang/String.toString*();sf", NO_MATCH); + testCases.add(toString, "java/lang/String.toString*()Ljava/lang/String;", MATCH); + testCases.add(toString, "java/lang/String.toString()Ljava/lang/String;", MATCH); + testCases.add(toString, "java/lang/String.toString ()Ljava/lang/String;", MATCH); + testCases.add(toString, "java/lang/String.toString ()Ljava/lang/String", MATCH); + testCases.add(toString, "java/lang/String.toString ()L", MATCH); + testCases.add(toString, "java/lang/String.toString ()I;", NO_MATCH); + + testCases.add(toString, "*Internal.*", NO_MATCH); + testCases.add(toString, "*Internal.**", PARSING_FAILURE); + testCases.add(toString, "*Internal.***", PARSING_FAILURE); + testCases.add(toString, "*Internal.*a**", PARSING_FAILURE); + testCases.add(toString, "*Internal.**a*", PARSING_FAILURE); + + testCases.add(toString, "java.lang.String::(Ljava/lang/String;)V", NO_MATCH); + testCases.add(toString, "java.lang.String::(Ljava/lang/String;)V", NO_MATCH); + testCases.add(toString, "java.lang.String::(Ljava/lang/String;)V", PARSING_FAILURE); + + testCases.add(toString, "java/lang/String.toString()Ljava/lang/String;", MATCH); + testCases.add(toString, "java/lang/String.toString()Ljava/lang/String;", PARSING_FAILURE); + testCases.add(toString, "java/lang/.toString()Ljava/lang/String;", PARSING_FAILURE); + testCases.add(toString, "java/lang/.toString()Ljava/lang/String;", PARSING_FAILURE); + + int failures = 0; + for (TestCase t : testCases) { + System.out.println("Test case: " + t.pattern); + if (!t.test()) { + failures++; + System.out.println(" * FAILED"); + } + } + if (failures != 0) { + throw new Exception("There where " + failures + " failures in this test"); + } + } + + public static void main(String... args) throws Exception { + MethodMatcherTest test = new MethodMatcherTest(); + test.test(); + } + + public void helper() { + + } + + private static Method getMethod(Class klass, String name, Class... parameterTypes) { + try { + return klass.getDeclaredMethod(name, parameterTypes); + } catch (NoSuchMethodException | SecurityException e) { + throw new RuntimeException("exception on getting method Helper." + name, e); + } + } + + class TestCase { + String pattern; + Method testTarget; + int expectedResult; + + public TestCase(Method testTarget, String pattern, int expectedResult) { + this.testTarget = testTarget; + this.pattern = pattern; + this.expectedResult = expectedResult; + } + + public String resultAsStr(int errorCode) { + switch (errorCode) { + case PARSING_FAILURE: + return "Parsing failed"; + case NO_MATCH: + return "No match"; + case MATCH: + return "Match"; + default: + return "Unknown error"; + } + } + + boolean test() { + int result = WHITE_BOX.matchesMethod(testTarget, pattern); + if (result != expectedResult) { + System.out + .println("FAIL Wrong result, Got: " + resultAsStr(result) + "\n TestCase: " + this.toString()); + return false; + } + return true; + } + + @Override + public String toString() { + return "Method: '" + testTarget.toString() + "' Pattern: '" + pattern + "' Expected: " + + resultAsStr(expectedResult); + } + + public void innerHelper() { + } + } + + class TestCases extends ArrayList { + private static final long serialVersionUID = 1L; + + public boolean add(Method testTarget, String pattern, int expectedResult) { + return super.add(new TestCase(testTarget, pattern, expectedResult)); + } + + public void innerHelper() { + } + } +} diff -r 54f3f085b165 -r 1a17229eb64d hotspot/test/compiler/oracle/TestCompileCommand.java --- a/hotspot/test/compiler/oracle/TestCompileCommand.java Thu Sep 17 09:03:57 2015 +0200 +++ b/hotspot/test/compiler/oracle/TestCompileCommand.java Fri Sep 18 16:37:12 2015 -0400 @@ -40,7 +40,7 @@ private static final String[][] ARGUMENTS = { { - "-XX:CompileCommand=print,*01234567890123456789012345678901234567890123456789,*0123456789012345678901234567890123456789", + "-XX:CompileCommand=print,*01234567890123456789012345678901234567890123456789.*0123456789012345678901234567890123456789", "-version" } }; diff -r 54f3f085b165 -r 1a17229eb64d hotspot/test/compiler/oracle/command1.txt --- a/hotspot/test/compiler/oracle/command1.txt Thu Sep 17 09:03:57 2015 +0200 +++ b/hotspot/test/compiler/oracle/command1.txt Fri Sep 18 16:37:12 2015 -0400 @@ -1,12 +1,10 @@ option,com/oracle/Test.test,MyBoolOption1 option,com/oracle/Test,test,MyBoolOption2 option,com.oracle.Test::test,MyBoolOption3 -option,com/oracle/Test::test,MyBoolOption4 option,com/oracle/Test.test,MyBoolOption5,MyBoolOption6 option,com/oracle/Test,test,MyBoolOption7,MyBoolOption8 option,com/oracle/Test.test(I),MyBoolOption9 option,com/oracle/Test,test,(I),MyBoolOption10 option,com.oracle.Test::test(I),MyBoolOption11 -option,com/oracle/Test::test(I),MyBoolOption12 option,com/oracle/Test.test(I),MyBoolOption13,MyBoolOption14 option,com/oracle/Test,test(I),MyBoolOption15,MyBoolOption16 diff -r 54f3f085b165 -r 1a17229eb64d hotspot/test/runtime/CommandLine/CompilerConfigFileWarning.java --- a/hotspot/test/runtime/CommandLine/CompilerConfigFileWarning.java Thu Sep 17 09:03:57 2015 +0200 +++ b/hotspot/test/runtime/CommandLine/CompilerConfigFileWarning.java Fri Sep 18 16:37:12 2015 -0400 @@ -46,7 +46,7 @@ pb = ProcessTools.createJavaProcessBuilder("-XX:CompileCommandFile=hs_comp.txt", "-version"); output = new OutputAnalyzer(pb.start()); output.shouldContain("CompileCommand: unrecognized command"); - output.shouldContain("aaa aaa"); + output.shouldContain("aaa, aaa"); // Skip on debug builds since we'll always read the file there if (!Platform.isDebugBuild()) {