/* * Copyright (c) 1998, 2014, 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/compilerOracle.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()->equals(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->equals(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, BoolType, CcstrType, DoubleType, UnknownType }; /* Methods to map real type names to OptionType */ template static OptionType get_type_for() { return UnknownType; }; template<> OptionType get_type_for() { return IntxType; } template<> OptionType get_type_for() { return UintxType; } template<> OptionType get_type_for() { return BoolType; } template<> OptionType get_type_for() { return CcstrType; } template<> OptionType get_type_for() { 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, OracleFirstCommand = 0, BreakCommand = OracleFirstCommand, PrintCommand, ExcludeCommand, InlineCommand, DontInlineCommand, CompileOnlyCommand, LogCommand, OptionCommand, QuietCommand, HelpCommand, OracleCommandCount }; // this must parallel the enum OracleCommand static const char * command_names[] = { "break", "print", "exclude", "inline", "dontinline", "compileonly", "log", "option", "quiet", "help" }; class MethodMatcher; static MethodMatcher* lists[OracleCommandCount] = { 0, }; static bool check_predicate(OracleCommand command, methodHandle method) { return ((lists[command] != NULL) && !method.is_null() && 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) { assert(command != OptionCommand, "must use add_option_string"); 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]; } 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; } template bool CompilerOracle::has_option_value(methodHandle method, const char* option, T& value) { return ::get_option_value(method, option, value); } // Explicit instantiation for all OptionTypes supported. template bool CompilerOracle::has_option_value(methodHandle method, const char* option, intx& value); template bool CompilerOracle::has_option_value(methodHandle method, const char* option, uintx& value); template bool CompilerOracle::has_option_value(methodHandle method, const char* option, bool& value); 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::should_exclude(methodHandle method, bool& quietly) { quietly = true; if (lists[ExcludeCommand] != NULL) { if (lists[ExcludeCommand]->match(method)) { quietly = _quiet; return true; } } if (lists[CompileOnlyCommand] != NULL) { return !lists[CompileOnlyCommand]->match(method); } return false; } bool CompilerOracle::should_inline(methodHandle method) { return (check_predicate(InlineCommand, method)); } bool CompilerOracle::should_not_inline(methodHandle method) { return (check_predicate(DontInlineCommand, method)); } bool CompilerOracle::should_print(methodHandle method) { return (check_predicate(PrintCommand, method)); } bool CompilerOracle::should_print_methods() { return lists[PrintCommand] != NULL; } bool CompilerOracle::should_log(methodHandle method) { if (!LogCompilation) return false; if (lists[LogCommand] == NULL) return true; // by default, log all 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"); *bytes_read = 0; char command[33]; int result = sscanf(line, "%32[a-z]%n", command, bytes_read); for (uint i = 0; i < ARRAY_SIZE(command_names); i++) { if (strcmp(command, command_names[i]) == 0) { return (OracleCommand)i; } } return UnknownCommand; } static void usage() { tty->cr(); tty->print_cr("The CompileCommand option enables the user of the JVM to control specific"); tty->print_cr("behavior of the dynamic compilers. Many commands require a pattern that defines"); tty->print_cr("the set of methods the command shall be applied to. The CompileCommand"); tty->print_cr("option provides the following commands:"); tty->cr(); tty->print_cr(" break, - debug breakpoint in compiler and in generated code"); tty->print_cr(" print, - print assembly"); tty->print_cr(" exclude, - don't compile or inline"); tty->print_cr(" inline, - always inline"); tty->print_cr(" dontinline, - don't inline"); tty->print_cr(" compileonly, - compile only"); tty->print_cr(" log, - log compilation"); tty->print_cr(" option,,