8135068: Extract method matchers from CompilerOracle
Summary: Ecapsulate code to enable reuse
Reviewed-by: roland, kvn
--- a/hotspot/src/share/vm/c1/c1_GraphBuilder.cpp Thu Sep 17 13:42:50 2015 -0700
+++ b/hotspot/src/share/vm/c1/c1_GraphBuilder.cpp Fri Sep 18 10:11:11 2015 +0200
@@ -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
--- a/hotspot/src/share/vm/ci/ciMethod.cpp Thu Sep 17 13:42:50 2015 -0700
+++ b/hotspot/src/share/vm/ci/ciMethod.cpp Fri Sep 18 10:11:11 2015 +0200
@@ -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?
--- a/hotspot/src/share/vm/ci/ciMethod.hpp Thu Sep 17 13:42:50 2015 -0700
+++ b/hotspot/src/share/vm/ci/ciMethod.hpp Fri Sep 18 10:11:11 2015 +0200
@@ -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();
--- a/hotspot/src/share/vm/compiler/compileBroker.cpp Thu Sep 17 13:42:50 2015 -0700
+++ b/hotspot/src/share/vm/compiler/compileBroker.cpp Fri Sep 18 10:11:11 2015 +0200
@@ -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;
--- a/hotspot/src/share/vm/compiler/compilerOracle.cpp Thu Sep 17 13:42:50 2015 -0700
+++ b/hotspot/src/share/vm/compiler/compilerOracle.cpp Fri Sep 18 10:11:11 2015 +0200
@@ -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<mtCompiler> {
- 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<typename T>
-static const T copy_value(const T value) {
- return value;
-}
-
-template<> const ccstr copy_value<ccstr>(const ccstr value) {
- return (const ccstr)os::strdup_check_oom(value);
-}
-
-template <typename T>
-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<T>()), _value(copy_value<T>(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(" <unknown option type>");
- tty->cr();
- }
-};
-
-template<>
-void TypedMethodOptionMatcher<intx>::print() {
- ttyLocker ttyl;
- print_base();
- tty->print(" intx %s", _option);
- tty->print(" = " INTX_FORMAT, _value);
- tty->cr();
-};
-
-template<>
-void TypedMethodOptionMatcher<uintx>::print() {
- ttyLocker ttyl;
- print_base();
- tty->print(" uintx %s", _option);
- tty->print(" = " UINTX_FORMAT, _value);
- tty->cr();
-};
-
-template<>
-void TypedMethodOptionMatcher<bool>::print() {
- ttyLocker ttyl;
- print_base();
- tty->print(" bool %s", _option);
- tty->print(" = %s", _value ? "true" : "false");
- tty->cr();
-};
-
-template<>
-void TypedMethodOptionMatcher<ccstr>::print() {
- ttyLocker ttyl;
- print_base();
- tty->print(" const char* %s", _option);
- tty->print(" = '%s'", _value);
- tty->cr();
-};
-
-template<>
-void TypedMethodOptionMatcher<double>::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<typename T> T value();
+ template<typename T> 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<intx>() {
+ return _u.intx_value;
+}
+
+template<> uintx TypedMethodOptionMatcher::value<uintx>() {
+ return _u.uintx_value;
+}
+
+template<> bool TypedMethodOptionMatcher::value<bool>() {
+ return _u.bool_value;
+}
+
+template<> double TypedMethodOptionMatcher::value<double>() {
+ return _u.double_value;
+}
+
+template<> ccstr TypedMethodOptionMatcher::value<ccstr>() {
+ 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<intx>());
+ break;
+ case UintxType:
+ tty->print_cr(" uintx %s = " UINTX_FORMAT, _option, value<uintx>());
+ break;
+ case BoolType:
+ tty->print_cr(" bool %s = %s", _option, value<bool>() ? "true" : "false");
+ break;
+ case DoubleType:
+ tty->print_cr(" double %s = %f", _option, value<double>());
+ break;
+ case CcstrType:
+ tty->print_cr(" const char* %s = '%s'", _option, value<ccstr>());
+ 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<typename T>
+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<T>(), option_list);
+ matcher->set_value<T>(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<typename T>
-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<T>(class_name, c_mode, method_name, m_mode,
- signature, option, value, lists[OptionCommand]);
- return lists[OptionCommand];
-}
-
-template<typename T>
-static bool get_option_value(methodHandle method, const char* option, T& value) {
- TypedMethodOptionMatcher<T>* m;
- if (lists[OptionCommand] != NULL
- && (m = ((TypedMethodOptionMatcher<T>*)lists[OptionCommand])->match(method, option)) != NULL
- && m->get_type() == get_type_for<T>()) {
- 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<typename T>
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<T>());
+ if (m != NULL) {
+ value = m->value<T>();
+ return true;
+ }
+ }
+ return false;
}
// Explicit instantiation for all OptionTypes supported.
@@ -405,6 +331,12 @@
template bool CompilerOracle::has_option_value<ccstr>(methodHandle method, const char* option, ccstr& value);
template bool CompilerOracle::has_option_value<double>(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;
--- a/hotspot/src/share/vm/compiler/compilerOracle.hpp Thu Sep 17 13:42:50 2015 -0700
+++ b/hotspot/src/share/vm/compiler/compilerOracle.hpp Fri Sep 18 10:11:11 2015 +0200
@@ -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:
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/compiler/methodMatcher.cpp Fri Sep 18 10:11:11 2015 +0200
@@ -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("<init>", method_name, 255) != 0) && (strncmp("<clinit>", method_name, 255) != 0)) {
+ error_msg = "Chars '<' and '>' only allowed in <init> and <clinit>";
+ 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);
+ }
+}
+
+
+
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/compiler/methodMatcher.hpp Fri Sep 18 10:11:11 2015 +0200
@@ -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<mtCompiler> {
+ 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
+
--- a/hotspot/src/share/vm/opto/bytecodeInfo.cpp Thu Sep 17 13:42:50 2015 -0700
+++ b/hotspot/src/share/vm/opto/bytecodeInfo.cpp Fri Sep 18 10:11:11 2015 +0200
@@ -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;
}
--- a/hotspot/src/share/vm/prims/whitebox.cpp Thu Sep 17 13:42:50 2015 -0700
+++ b/hotspot/src/share/vm/prims/whitebox.cpp Fri Sep 18 10:11:11 2015 +0200
@@ -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},
--- a/hotspot/src/share/vm/runtime/globals.hpp Thu Sep 17 13:42:50 2015 -0700
+++ b/hotspot/src/share/vm/runtime/globals.hpp Fri Sep 18 10:11:11 2015 +0200
@@ -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 " \
--- a/hotspot/test/compiler/c2/5091921/Test7005594.sh Thu Sep 17 13:42:50 2015 -0700
+++ b/hotspot/test/compiler/c2/5091921/Test7005594.sh Fri Sep 18 10:11:11 2015 +0200
@@ -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=$?
--- a/hotspot/test/compiler/oracle/CheckCompileCommandOption.java Thu Sep 17 13:42:50 2015 -0700
+++ b/hotspot/test/compiler/oracle/CheckCompileCommandOption.java Fri Sep 18 10:11:11 2015 +0200
@@ -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);
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/compiler/oracle/MethodMatcherTest.java Fri Sep 18 10:11:11 2015 +0200
@@ -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::<init>(Ljava/lang/String;)V", NO_MATCH);
+ testCases.add(toString, "java.lang.String::<clinit>(Ljava/lang/String;)V", NO_MATCH);
+ testCases.add(toString, "java.lang.String::<init(Ljava/lang/String;)V", PARSING_FAILURE);
+ testCases.add(toString, "java.lang.String::init>(Ljava/lang/String;)V", PARSING_FAILURE);
+
+ testCases.add(toString, "java/lang/String.toString()Ljava/lang/String;", MATCH);
+ testCases.add(toString, "java/lang/Str<ing.toString()Ljava/lang/String;", PARSING_FAILURE);
+ testCases.add(toString, "java/lang/Str>ing.toString()Ljava/lang/String;", PARSING_FAILURE);
+ testCases.add(toString, "java/lang/<init>.toString()Ljava/lang/String;", PARSING_FAILURE);
+ testCases.add(toString, "java/lang/<clinit>.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<TestCase> {
+ 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() {
+ }
+ }
+}
--- a/hotspot/test/compiler/oracle/TestCompileCommand.java Thu Sep 17 13:42:50 2015 -0700
+++ b/hotspot/test/compiler/oracle/TestCompileCommand.java Fri Sep 18 10:11:11 2015 +0200
@@ -40,7 +40,7 @@
private static final String[][] ARGUMENTS = {
{
- "-XX:CompileCommand=print,*01234567890123456789012345678901234567890123456789,*0123456789012345678901234567890123456789",
+ "-XX:CompileCommand=print,*01234567890123456789012345678901234567890123456789.*0123456789012345678901234567890123456789",
"-version"
}
};
--- a/hotspot/test/compiler/oracle/command1.txt Thu Sep 17 13:42:50 2015 -0700
+++ b/hotspot/test/compiler/oracle/command1.txt Fri Sep 18 10:11:11 2015 +0200
@@ -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
--- a/hotspot/test/runtime/CommandLine/CompilerConfigFileWarning.java Thu Sep 17 13:42:50 2015 -0700
+++ b/hotspot/test/runtime/CommandLine/CompilerConfigFileWarning.java Fri Sep 18 10:11:11 2015 +0200
@@ -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()) {