/* * Copyright (c) 1998, 2017, 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 "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/symbol.hpp" #include "prims/jvm.h" #include "runtime/handles.inline.hpp" #include "runtime/jniHandles.hpp" #include "runtime/os.hpp" 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; } // 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; class TypedMethodOptionMatcher; static BasicMatcher* lists[OracleCommandCount] = { 0, }; static TypedMethodOptionMatcher* option_list = NULL; static bool any_set = false; 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(const 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); } } 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(const 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; any_set = true; return; } static bool check_predicate(OracleCommand command, const methodHandle& method) { return ((lists[command] != NULL) && !method.is_null() && lists[command]->match(method)); } static void add_predicate(OracleCommand command, BasicMatcher* bm) { 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."); } bm->set_next(lists[command]); lists[command] = bm; if ((command != DontInlineCommand) && (command != InlineCommand)) { any_set = true; } return; } template bool CompilerOracle::has_option_value(const methodHandle& method, const char* option, T& 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; } bool CompilerOracle::has_any_option() { return any_set; } // Explicit instantiation for all OptionTypes supported. template bool CompilerOracle::has_option_value(const methodHandle& method, const char* option, intx& value); template bool CompilerOracle::has_option_value(const methodHandle& method, const char* option, uintx& value); template bool CompilerOracle::has_option_value(const methodHandle& method, const char* option, bool& value); template bool CompilerOracle::has_option_value(const methodHandle& method, const char* option, ccstr& value); template bool CompilerOracle::has_option_value(const methodHandle& method, const char* option, double& value); bool CompilerOracle::has_option_string(const methodHandle& method, const char* option) { bool value = false; has_option_value(method, option, value); return value; } bool CompilerOracle::should_exclude(const methodHandle& method) { if (check_predicate(ExcludeCommand, method)) { return true; } if (lists[CompileOnlyCommand] != NULL) { return !lists[CompileOnlyCommand]->match(method); } return false; } bool CompilerOracle::should_inline(const methodHandle& method) { return (check_predicate(InlineCommand, method)); } bool CompilerOracle::should_not_inline(const methodHandle& method) { return check_predicate(DontInlineCommand, method) || check_predicate(ExcludeCommand, method); } bool CompilerOracle::should_print(const methodHandle& method) { return check_predicate(PrintCommand, method); } bool CompilerOracle::should_print_methods() { return lists[PrintCommand] != NULL; } bool CompilerOracle::should_log(const 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(const 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,,