8256508: Improve CompileCommand flag

Reviewed-by: redestad, kvn
This commit is contained in:
Nils Eliasson 2020-11-25 14:20:35 +00:00
parent 7aed9b65d0
commit cfb175dfdf
22 changed files with 796 additions and 482 deletions

View file

@ -3384,7 +3384,7 @@ void LIRGenerator::do_ProfileInvoke(ProfileInvoke* x) {
// Notify the runtime very infrequently only to take care of counter overflows // Notify the runtime very infrequently only to take care of counter overflows
int freq_log = Tier23InlineeNotifyFreqLog; int freq_log = Tier23InlineeNotifyFreqLog;
double scale; double scale;
if (_method->has_option_value("CompileThresholdScaling", scale)) { if (_method->has_option_value(CompileCommand::CompileThresholdScaling, scale)) {
freq_log = CompilerConfig::scaled_freq_log(freq_log, scale); freq_log = CompilerConfig::scaled_freq_log(freq_log, scale);
} }
increment_event_counter_impl(info, x->inlinee(), LIR_OprFact::intConst(InvocationCounter::count_increment), right_n_bits(freq_log), InvocationEntryBci, false, true); increment_event_counter_impl(info, x->inlinee(), LIR_OprFact::intConst(InvocationCounter::count_increment), right_n_bits(freq_log), InvocationEntryBci, false, true);
@ -3425,7 +3425,7 @@ void LIRGenerator::increment_event_counter(CodeEmitInfo* info, LIR_Opr step, int
} }
// Increment the appropriate invocation/backedge counter and notify the runtime. // Increment the appropriate invocation/backedge counter and notify the runtime.
double scale; double scale;
if (_method->has_option_value("CompileThresholdScaling", scale)) { if (_method->has_option_value(CompileCommand::CompileThresholdScaling, scale)) {
freq_log = CompilerConfig::scaled_freq_log(freq_log, scale); freq_log = CompilerConfig::scaled_freq_log(freq_log, scale);
} }
increment_event_counter_impl(info, info->scope()->method(), step, right_n_bits(freq_log), bci, backedge, true); increment_event_counter_impl(info, info->scope()->method(), step, right_n_bits(freq_log), bci, backedge, true);

View file

@ -1043,17 +1043,17 @@ MethodCounters* ciMethod::ensure_method_counters() {
// ------------------------------------------------------------------ // ------------------------------------------------------------------
// ciMethod::has_option // ciMethod::has_option
// //
bool ciMethod::has_option(const char* option) { bool ciMethod::has_option(enum CompileCommand option) {
check_is_loaded(); check_is_loaded();
VM_ENTRY_MARK; VM_ENTRY_MARK;
methodHandle mh(THREAD, get_Method()); methodHandle mh(THREAD, get_Method());
return CompilerOracle::has_option_string(mh, option); return CompilerOracle::has_option(mh, option);
} }
// ------------------------------------------------------------------ // ------------------------------------------------------------------
// ciMethod::has_option_value // ciMethod::has_option_value
// //
bool ciMethod::has_option_value(const char* option, double& value) { bool ciMethod::has_option_value(enum CompileCommand option, double& value) {
check_is_loaded(); check_is_loaded();
VM_ENTRY_MARK; VM_ENTRY_MARK;
methodHandle mh(THREAD, get_Method()); methodHandle mh(THREAD, get_Method());

View file

@ -293,8 +293,8 @@ class ciMethod : public ciMetadata {
// Find the proper vtable index to invoke this method. // Find the proper vtable index to invoke this method.
int resolve_vtable_index(ciKlass* caller, ciKlass* receiver); int resolve_vtable_index(ciKlass* caller, ciKlass* receiver);
bool has_option(const char *option); bool has_option(enum CompileCommand option);
bool has_option_value(const char* option, double& value); bool has_option_value(enum CompileCommand option, double& value);
bool can_be_compiled(); bool can_be_compiled();
bool can_be_parsed() const { return _can_be_parsed; } bool can_be_parsed() const { return _can_be_parsed; }
bool has_compiled_code(); bool has_compiled_code();

View file

@ -978,15 +978,15 @@ void nmethod::print_nmethod(bool printmethod) {
#if defined(SUPPORT_DATA_STRUCTS) #if defined(SUPPORT_DATA_STRUCTS)
if (AbstractDisassembler::show_structs()) { if (AbstractDisassembler::show_structs()) {
methodHandle mh(Thread::current(), _method); methodHandle mh(Thread::current(), _method);
if (printmethod || PrintDebugInfo || CompilerOracle::has_option_string(mh, "PrintDebugInfo")) { if (printmethod || PrintDebugInfo || CompilerOracle::has_option(mh, CompileCommand::PrintDebugInfo)) {
print_scopes(); print_scopes();
tty->print_cr("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "); tty->print_cr("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
} }
if (printmethod || PrintRelocations || CompilerOracle::has_option_string(mh, "PrintRelocations")) { if (printmethod || PrintRelocations || CompilerOracle::has_option(mh, CompileCommand::PrintRelocations)) {
print_relocations(); print_relocations();
tty->print_cr("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "); tty->print_cr("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
} }
if (printmethod || PrintDependencies || CompilerOracle::has_option_string(mh, "PrintDependencies")) { if (printmethod || PrintDependencies || CompilerOracle::has_option(mh, CompileCommand::PrintDependencies)) {
print_dependencies(); print_dependencies();
tty->print_cr("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "); tty->print_cr("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
} }

View file

@ -1585,8 +1585,8 @@ bool CompileBroker::compilation_is_prohibited(const methodHandle& method, int os
// The method may be explicitly excluded by the user. // The method may be explicitly excluded by the user.
double scale; double scale;
if (excluded || (CompilerOracle::has_option_value(method, "CompileThresholdScaling", scale) && scale == 0)) { if (excluded || (CompilerOracle::has_option_value(method, CompileCommand::CompileThresholdScaling, scale) && scale == 0)) {
bool quietly = CompilerOracle::should_exclude_quietly(); bool quietly = CompilerOracle::be_quiet();
if (PrintCompilation && !quietly) { if (PrintCompilation && !quietly) {
// This does not happen quietly... // This does not happen quietly...
ResourceMark rm; ResourceMark rm;

View file

@ -140,7 +140,7 @@ bool CompilerDirectives::match(const methodHandle& method) {
} }
bool CompilerDirectives::add_match(char* str, const char*& error_msg) { bool CompilerDirectives::add_match(char* str, const char*& error_msg) {
BasicMatcher* bm = BasicMatcher::parse_method_pattern(str, error_msg); BasicMatcher* bm = BasicMatcher::parse_method_pattern(str, error_msg, false);
if (bm == NULL) { if (bm == NULL) {
assert(error_msg != NULL, "Must have error message"); assert(error_msg != NULL, "Must have error message");
return false; return false;
@ -326,7 +326,7 @@ DirectiveSet* DirectiveSet::compilecommand_compatibility_init(const methodHandle
// Early bail out - checking all options is expensive - we rely on them not being used // Early bail out - checking all options is expensive - we rely on them not being used
// Only set a flag if it has not been modified and value changes. // Only set a flag if it has not been modified and value changes.
// Only copy set if a flag needs to be set // Only copy set if a flag needs to be set
if (!CompilerDirectivesIgnoreCompileCommandsOption && CompilerOracle::has_any_option()) { if (!CompilerDirectivesIgnoreCompileCommandsOption && CompilerOracle::has_any_command_set()) {
DirectiveSetPtr set(this); DirectiveSetPtr set(this);
// All CompileCommands are not equal so this gets a bit verbose // All CompileCommands are not equal so this gets a bit verbose
@ -359,8 +359,7 @@ DirectiveSet* DirectiveSet::compilecommand_compatibility_init(const methodHandle
} }
// inline and dontinline (including exclude) are implemented in the directiveset accessors // inline and dontinline (including exclude) are implemented in the directiveset accessors
// ignore flags whose cc_flags are X #define init_default_cc(name, type, dvalue, cc_flag) { type v; if (!_modified[name##Index] && CompilerOracle::has_option_value(method, CompileCommand::cc_flag, v) && v != this->name##Option) { set.cloned()->name##Option = v; } }
#define init_default_cc(name, type, dvalue, cc_flag) { type v; if (!_modified[name##Index] && CompilerOracle::has_option_value(method, #cc_flag, v) && v != this->name##Option) { set.cloned()->name##Option = v; } }
compilerdirectives_common_flags(init_default_cc) compilerdirectives_common_flags(init_default_cc)
compilerdirectives_c2_flags(init_default_cc) compilerdirectives_c2_flags(init_default_cc)
compilerdirectives_c1_flags(init_default_cc) compilerdirectives_c1_flags(init_default_cc)
@ -370,7 +369,7 @@ DirectiveSet* DirectiveSet::compilecommand_compatibility_init(const methodHandle
bool need_reset = true; // if Control/DisableIntrinsic redefined, only need to reset control_words once bool need_reset = true; // if Control/DisableIntrinsic redefined, only need to reset control_words once
if (!_modified[ControlIntrinsicIndex] && if (!_modified[ControlIntrinsicIndex] &&
CompilerOracle::has_option_value(method, "ControlIntrinsic", option_value)) { CompilerOracle::has_option_value(method, CompileCommand::ControlIntrinsic, option_value)) {
ControlIntrinsicIter iter(option_value); ControlIntrinsicIter iter(option_value);
if (need_reset) { if (need_reset) {
@ -390,7 +389,7 @@ DirectiveSet* DirectiveSet::compilecommand_compatibility_init(const methodHandle
if (!_modified[DisableIntrinsicIndex] && if (!_modified[DisableIntrinsicIndex] &&
CompilerOracle::has_option_value(method, "DisableIntrinsic", option_value)) { CompilerOracle::has_option_value(method, CompileCommand::DisableIntrinsic, option_value)) {
ControlIntrinsicIter iter(option_value, true/*disable_all*/); ControlIntrinsicIter iter(option_value, true/*disable_all*/);
if (need_reset) { if (need_reset) {

View file

@ -34,11 +34,11 @@
// Directives flag name, type, default value, compile command name // Directives flag name, type, default value, compile command name
#define compilerdirectives_common_flags(cflags) \ #define compilerdirectives_common_flags(cflags) \
cflags(Enable, bool, false, X) \ cflags(Enable, bool, false, Unknown) \
cflags(Exclude, bool, false, X) \ cflags(Exclude, bool, false, Unknown) \
cflags(BreakAtExecute, bool, false, BreakAtExecute) \ cflags(BreakAtExecute, bool, false, BreakAtExecute) \
cflags(BreakAtCompile, bool, false, BreakAtCompile) \ cflags(BreakAtCompile, bool, false, BreakAtCompile) \
cflags(Log, bool, LogCompilation, X) \ cflags(Log, bool, LogCompilation, Unknown) \
cflags(PrintAssembly, bool, PrintAssembly, PrintAssembly) \ cflags(PrintAssembly, bool, PrintAssembly, PrintAssembly) \
cflags(PrintInlining, bool, PrintInlining, PrintInlining) \ cflags(PrintInlining, bool, PrintInlining, PrintInlining) \
cflags(PrintNMethods, bool, PrintNMethods, PrintNMethods) \ cflags(PrintNMethods, bool, PrintNMethods, PrintNMethods) \
@ -46,7 +46,7 @@
cflags(ReplayInline, bool, false, ReplayInline) \ cflags(ReplayInline, bool, false, ReplayInline) \
cflags(DumpReplay, bool, false, DumpReplay) \ cflags(DumpReplay, bool, false, DumpReplay) \
cflags(DumpInline, bool, false, DumpInline) \ cflags(DumpInline, bool, false, DumpInline) \
cflags(CompilerDirectivesIgnoreCompileCommands, bool, CompilerDirectivesIgnoreCompileCommands, X) \ cflags(CompilerDirectivesIgnoreCompileCommands, bool, CompilerDirectivesIgnoreCompileCommands, Unknown) \
cflags(DisableIntrinsic, ccstrlist, DisableIntrinsic, DisableIntrinsic) \ cflags(DisableIntrinsic, ccstrlist, DisableIntrinsic, DisableIntrinsic) \
cflags(ControlIntrinsic, ccstrlist, ControlIntrinsic, ControlIntrinsic) \ cflags(ControlIntrinsic, ccstrlist, ControlIntrinsic, ControlIntrinsic) \
cflags(RepeatCompilation, intx, RepeatCompilation, RepeatCompilation) cflags(RepeatCompilation, intx, RepeatCompilation, RepeatCompilation)

View file

@ -38,83 +38,72 @@
#include "runtime/jniHandles.hpp" #include "runtime/jniHandles.hpp"
#include "runtime/os.hpp" #include "runtime/os.hpp"
enum OptionType { static const char* optiontype_names[] = {
IntxType, #define enum_of_types(type, name) name,
UintxType, OPTION_TYPES(enum_of_types)
BoolType, #undef enum_of_types
CcstrType,
DoubleType,
UnknownType
}; };
const char* optiontype2name(enum OptionType type) {
return optiontype_names[static_cast<int>(type)];
}
static enum OptionType option_types[] = {
#define enum_of_options(option, name, ctype) OptionType::ctype,
COMPILECOMMAND_OPTIONS(enum_of_options)
#undef enum_of_options
};
enum OptionType option2type(enum CompileCommand option) {
return option_types[static_cast<int>(option)];
}
static const char* option_names[] = {
#define enum_of_options(option, name, ctype) name,
COMPILECOMMAND_OPTIONS(enum_of_options)
#undef enum_of_options
};
const char* option2name(enum CompileCommand option) {
return option_names[static_cast<int>(option)];
}
/* Methods to map real type names to OptionType */ /* Methods to map real type names to OptionType */
template<typename T> template<typename T>
static OptionType get_type_for() { static OptionType get_type_for() {
return UnknownType; return OptionType::Unknown;
}; };
template<> OptionType get_type_for<intx>() { template<> OptionType get_type_for<intx>() {
return IntxType; return OptionType::Intx;
} }
template<> OptionType get_type_for<uintx>() { template<> OptionType get_type_for<uintx>() {
return UintxType; return OptionType::Uintx;
} }
template<> OptionType get_type_for<bool>() { template<> OptionType get_type_for<bool>() {
return BoolType; return OptionType::Bool;
} }
template<> OptionType get_type_for<ccstr>() { template<> OptionType get_type_for<ccstr>() {
return CcstrType; return OptionType::Ccstr;
} }
template<> OptionType get_type_for<double>() { template<> OptionType get_type_for<double>() {
return DoubleType; return OptionType::Double;
} }
// 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 MethodMatcher;
class TypedMethodOptionMatcher; class TypedMethodOptionMatcher;
static BasicMatcher* lists[OracleCommandCount] = { 0, };
static TypedMethodOptionMatcher* option_list = NULL; static TypedMethodOptionMatcher* option_list = NULL;
static bool any_set = false; static bool any_set = false;
class TypedMethodOptionMatcher : public MethodMatcher { class TypedMethodOptionMatcher : public MethodMatcher {
private: private:
TypedMethodOptionMatcher* _next; TypedMethodOptionMatcher* _next;
const char* _option; enum CompileCommand _option;
OptionType _type; OptionType _type;
public: public:
@ -128,29 +117,36 @@ class TypedMethodOptionMatcher : public MethodMatcher {
TypedMethodOptionMatcher() : MethodMatcher(), TypedMethodOptionMatcher() : MethodMatcher(),
_next(NULL), _next(NULL),
_type(UnknownType) { _option(CompileCommand::Unknown),
_option = NULL; _type(OptionType::Unknown) {
memset(&_u, 0, sizeof(_u)); memset(&_u, 0, sizeof(_u));
} }
static TypedMethodOptionMatcher* parse_method_pattern(char*& line, const char*& error_msg); ~TypedMethodOptionMatcher();
TypedMethodOptionMatcher* match(const methodHandle& method, const char* opt, OptionType type); static TypedMethodOptionMatcher* parse_method_pattern(char*& line, char* errorbuf, const int buf_size);
TypedMethodOptionMatcher* match(const methodHandle &method, enum CompileCommand option, OptionType type);
void init(const char* opt, OptionType type, TypedMethodOptionMatcher* next) { void init(enum CompileCommand option, OptionType type, TypedMethodOptionMatcher* next) {
_next = next; _next = next;
_type = type; _type = type;
_option = os::strdup_check_oom(opt); _option = option;
}
void init_matcher(Symbol* class_name, Mode class_mode,
Symbol* method_name, Mode method_mode,
Symbol* signature) {
MethodMatcher::init(class_name, class_mode, method_name, method_mode, signature);
} }
void set_next(TypedMethodOptionMatcher* next) {_next = next; } void set_next(TypedMethodOptionMatcher* next) {_next = next; }
TypedMethodOptionMatcher* next() { return _next; } TypedMethodOptionMatcher* next() { return _next; }
OptionType type() { return _type; } OptionType type() { return _type; }
enum CompileCommand option() { return _option; }
template<typename T> T value(); template<typename T> T value();
template<typename T> void set_value(T value); template<typename T> void set_value(T value);
void print(); void print();
void print_all(); void print_all();
TypedMethodOptionMatcher* clone(); TypedMethodOptionMatcher* clone();
~TypedMethodOptionMatcher();
}; };
// A few templated accessors instead of a full template class. // A few templated accessors instead of a full template class.
@ -197,21 +193,22 @@ template<> void TypedMethodOptionMatcher::set_value(ccstr value) {
void TypedMethodOptionMatcher::print() { void TypedMethodOptionMatcher::print() {
ttyLocker ttyl; ttyLocker ttyl;
print_base(tty); print_base(tty);
const char* name = option2name(_option);
switch (_type) { switch (_type) {
case IntxType: case OptionType::Intx:
tty->print_cr(" intx %s = " INTX_FORMAT, _option, value<intx>()); tty->print_cr(" intx %s = " INTX_FORMAT, name, value<intx>());
break; break;
case UintxType: case OptionType::Uintx:
tty->print_cr(" uintx %s = " UINTX_FORMAT, _option, value<uintx>()); tty->print_cr(" uintx %s = " UINTX_FORMAT, name, value<uintx>());
break; break;
case BoolType: case OptionType::Bool:
tty->print_cr(" bool %s = %s", _option, value<bool>() ? "true" : "false"); tty->print_cr(" bool %s = %s", name, value<bool>() ? "true" : "false");
break; break;
case DoubleType: case OptionType::Double:
tty->print_cr(" double %s = %f", _option, value<double>()); tty->print_cr(" double %s = %f", name, value<double>());
break; break;
case CcstrType: case OptionType::Ccstr:
tty->print_cr(" const char* %s = '%s'", _option, value<ccstr>()); tty->print_cr(" const char* %s = '%s'", name, value<ccstr>());
break; break;
default: default:
ShouldNotReachHere(); ShouldNotReachHere();
@ -247,78 +244,90 @@ TypedMethodOptionMatcher* TypedMethodOptionMatcher::clone() {
} }
TypedMethodOptionMatcher::~TypedMethodOptionMatcher() { TypedMethodOptionMatcher::~TypedMethodOptionMatcher() {
if (type() == CcstrType) { if (type() == OptionType::Ccstr) {
ccstr v = value<ccstr>(); ccstr v = value<ccstr>();
os::free((void*)v); os::free((void*)v);
} }
if (_option != NULL) {
os::free((void*)_option);
}
} }
TypedMethodOptionMatcher* TypedMethodOptionMatcher::parse_method_pattern(char*& line, const char*& error_msg) { TypedMethodOptionMatcher* TypedMethodOptionMatcher::parse_method_pattern(char*& line, char* errorbuf, const int buf_size) {
assert(error_msg == NULL, "Dont call here with error_msg already set"); assert(*errorbuf == '\0', "Dont call here with error_msg already set");
const char* error_msg = NULL;
TypedMethodOptionMatcher* tom = new TypedMethodOptionMatcher(); TypedMethodOptionMatcher* tom = new TypedMethodOptionMatcher();
MethodMatcher::parse_method_pattern(line, error_msg, tom); MethodMatcher::parse_method_pattern(line, error_msg, tom);
if (error_msg != NULL) { if (error_msg != NULL) {
jio_snprintf(errorbuf, buf_size, error_msg);
delete tom; delete tom;
return NULL; return NULL;
} }
return tom; return tom;
} }
TypedMethodOptionMatcher* TypedMethodOptionMatcher::match(const methodHandle& method, const char* opt, OptionType type) { TypedMethodOptionMatcher* TypedMethodOptionMatcher::match(const methodHandle& method, enum CompileCommand option, OptionType type) {
TypedMethodOptionMatcher* current = this; TypedMethodOptionMatcher* current = this;
while (current != NULL) { while (current != NULL) {
// Fastest compare first. if (current->_option == option) {
if (current->type() == type) {
if (strcmp(current->_option, opt) == 0) {
if (current->matches(method)) { if (current->matches(method)) {
return current; return current;
} }
} }
}
current = current->next(); current = current->next();
} }
return NULL; return NULL;
} }
template<typename T> template<typename T>
static void add_option_string(TypedMethodOptionMatcher* matcher, static void register_command(TypedMethodOptionMatcher* matcher,
const char* option, enum CompileCommand option,
T value) { T value) {
assert(matcher != option_list, "No circular lists please"); assert(matcher != option_list, "No circular lists please");
matcher->init(option, get_type_for<T>(), option_list); if (option == CompileCommand::Log && !LogCompilation) {
tty->print_cr("Warning: +LogCompilation must be enabled in order for individual methods to be logged with ");
tty->print_cr(" CompileCommand=log,<method pattern>");
}
enum OptionType type = option2type(option);
if (type == OptionType::Ccstrlist) {
type = OptionType::Ccstr; // ccstrlists are stores as ccstr
}
assert(type == get_type_for<T>(), "sanity");
matcher->init(option, type, option_list);
matcher->set_value<T>(value); matcher->set_value<T>(value);
option_list = matcher; option_list = matcher;
if ((option != CompileCommand::DontInline) &&
(option != CompileCommand::Inline) &&
(option != CompileCommand::Log)) {
any_set = true; any_set = true;
return;
} }
if (!CompilerOracle::be_quiet()) {
static bool check_predicate(OracleCommand command, const methodHandle& method) { // Print out the succesful registration of a comile command
return ((lists[command] != NULL) && ttyLocker ttyl;
!method.is_null() && tty->print("CompileCommand: %s ", option2name(option));
lists[command]->match(method)); matcher->print();
}
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; return;
} }
template<typename T> template<typename T>
bool CompilerOracle::has_option_value(const methodHandle& method, const char* option, T& value) { bool CompilerOracle::has_option_value(const methodHandle& method, enum CompileCommand option, T& value, bool verify_type) {
enum OptionType type = option2type(option);
if (type == OptionType::Unknown) {
return false; // Can't query options with type Unknown.
}
if (type == OptionType::Ccstrlist) {
type = OptionType::Ccstr; // CCstrList type options are stored as Ccstr
}
if (verify_type) {
if (type != get_type_for<T>()) {
// Whitebox API expects false if option and type doesn't match
return false;
}
} else {
assert(type == get_type_for<T>(), "Value type (%s) must match option %s (%s)",
optiontype2name(get_type_for<T>()),
option2name(option), optiontype2name(option2type(option)));
}
if (option_list != NULL) { if (option_list != NULL) {
TypedMethodOptionMatcher* m = option_list->match(method, option, get_type_for<T>()); TypedMethodOptionMatcher* m = option_list->match(method, option, type);
if (m != NULL) { if (m != NULL) {
value = m->value<T>(); value = m->value<T>();
return true; return true;
@ -327,98 +336,144 @@ bool CompilerOracle::has_option_value(const methodHandle& method, const char* op
return false; return false;
} }
bool CompilerOracle::has_any_option() { static bool check_predicate(enum CompileCommand option, const methodHandle& method) {
bool value = false;
if (CompilerOracle::has_option_value(method, option, value)) {
return value;
}
return false;
}
static bool has_command(enum CompileCommand option) {
TypedMethodOptionMatcher* m = option_list;
while (m != NULL) {
if (m->option() == option) {
return true;
} else {
m = m->next();
}
}
return false;
}
bool CompilerOracle::has_any_command_set() {
return any_set; return any_set;
} }
// Explicit instantiation for all OptionTypes supported. // Explicit instantiation for all OptionTypes supported.
template bool CompilerOracle::has_option_value<intx>(const methodHandle& method, const char* option, intx& value); template bool CompilerOracle::has_option_value<intx>(const methodHandle& method, enum CompileCommand option, intx& value, bool verify_type);
template bool CompilerOracle::has_option_value<uintx>(const methodHandle& method, const char* option, uintx& value); template bool CompilerOracle::has_option_value<uintx>(const methodHandle& method, enum CompileCommand option, uintx& value, bool verify_type);
template bool CompilerOracle::has_option_value<bool>(const methodHandle& method, const char* option, bool& value); template bool CompilerOracle::has_option_value<bool>(const methodHandle& method, enum CompileCommand option, bool& value, bool verify_type);
template bool CompilerOracle::has_option_value<ccstr>(const methodHandle& method, const char* option, ccstr& value); template bool CompilerOracle::has_option_value<ccstr>(const methodHandle& method, enum CompileCommand option, ccstr& value, bool verify_type);
template bool CompilerOracle::has_option_value<double>(const methodHandle& method, const char* option, double& value); template bool CompilerOracle::has_option_value<double>(const methodHandle& method, enum CompileCommand option, double& value, bool verify_type);
bool CompilerOracle::has_option_string(const methodHandle& method, const char* option) { bool CompilerOracle::has_option(const methodHandle& method, enum CompileCommand option) {
bool value = false; bool value = false;
has_option_value(method, option, value); has_option_value(method, option, value);
return value; return value;
} }
bool CompilerOracle::should_exclude(const methodHandle& method) { bool CompilerOracle::should_exclude(const methodHandle& method) {
if (check_predicate(ExcludeCommand, method)) { if (check_predicate(CompileCommand::Exclude, method)) {
return true; return true;
} }
if (lists[CompileOnlyCommand] != NULL) { if (has_command(CompileCommand::CompileOnly)) {
return !lists[CompileOnlyCommand]->match(method); return !check_predicate(CompileCommand::CompileOnly, method);
} }
return false; return false;
} }
bool CompilerOracle::should_inline(const methodHandle& method) { bool CompilerOracle::should_inline(const methodHandle& method) {
return (check_predicate(InlineCommand, method)); return (check_predicate(CompileCommand::Inline, method));
} }
bool CompilerOracle::should_not_inline(const methodHandle& method) { bool CompilerOracle::should_not_inline(const methodHandle& method) {
return check_predicate(DontInlineCommand, method) || check_predicate(ExcludeCommand, method); return check_predicate(CompileCommand::DontInline, method) || check_predicate(CompileCommand::Exclude, method);
} }
bool CompilerOracle::should_print(const methodHandle& method) { bool CompilerOracle::should_print(const methodHandle& method) {
return check_predicate(PrintCommand, method); return check_predicate(CompileCommand::Print, method);
} }
bool CompilerOracle::should_print_methods() { bool CompilerOracle::should_print_methods() {
return lists[PrintCommand] != NULL; return has_command(CompileCommand::Print);
} }
bool CompilerOracle::should_log(const methodHandle& method) { bool CompilerOracle::should_log(const methodHandle& method) {
if (!LogCompilation) return false; if (!LogCompilation) return false;
if (lists[LogCommand] == NULL) return true; // by default, log all if (!has_command(CompileCommand::Log)) {
return (check_predicate(LogCommand, method)); return true; // by default, log all
}
return (check_predicate(CompileCommand::Log, method));
} }
bool CompilerOracle::should_break_at(const methodHandle& method) { bool CompilerOracle::should_break_at(const methodHandle& method) {
return check_predicate(BreakCommand, method); return check_predicate(CompileCommand::Break, method);
} }
static OracleCommand parse_command_name(const char * line, int* bytes_read) { static enum CompileCommand parse_option_name(const char* line, int* bytes_read, char* errorbuf, int bufsize) {
assert(ARRAY_SIZE(command_names) == OracleCommandCount, assert(ARRAY_SIZE(option_names) == static_cast<int>(CompileCommand::Count), "option_names size mismatch");
"command_names size mismatch");
*bytes_read = 0; *bytes_read = 0;
char command[33]; char option_buf[256];
int matches = sscanf(line, "%32[a-z]%n", command, bytes_read); int matches = sscanf(line, "%255[a-zA-Z0-9]%n", option_buf, bytes_read);
if (matches > 0) { if (matches > 0) {
for (uint i = 0; i < ARRAY_SIZE(command_names); i++) { for (uint i = 0; i < ARRAY_SIZE(option_names); i++) {
if (strcmp(command, command_names[i]) == 0) { if (strcasecmp(option_buf, option_names[i]) == 0) {
return (OracleCommand)i; return static_cast<enum CompileCommand>(i);
} }
} }
} }
return UnknownCommand; jio_snprintf(errorbuf, bufsize, "Unrecognized option '%s'", option_buf);
return CompileCommand::Unknown;
}
void print_tip() { // CMH Update info
tty->cr();
tty->print_cr("Usage: '-XX:CompileCommand=<option>,<method pattern>' - to set boolean option to true");
tty->print_cr("Usage: '-XX:CompileCommand=<option>,<method pattern>,<value>'");
tty->print_cr("Use: '-XX:CompileCommand=help' for more information and to list all option.");
tty->cr();
}
void print_option(enum CompileCommand option, const char* name, enum OptionType type) {
if (type != OptionType::Unknown) {
tty->print_cr(" %s (%s)", name, optiontype2name(type));
}
}
void print_commands() {
tty->cr();
tty->print_cr("All available options:");
#define enum_of_options(option, name, ctype) print_option(CompileCommand::option, name, OptionType::ctype);
COMPILECOMMAND_OPTIONS(enum_of_options)
#undef enum_of_options
tty->cr();
} }
static void usage() { static void usage() {
tty->cr(); tty->cr();
tty->print_cr("The CompileCommand option enables the user of the JVM to control specific"); 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("behavior of the dynamic compilers.");
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->cr();
tty->print_cr(" break,<pattern> - debug breakpoint in compiler and in generated code"); tty->print_cr("Compile commands has this general form:");
tty->print_cr(" print,<pattern> - print assembly"); tty->print_cr("-XX:CompileCommand=<option><method pattern><value>");
tty->print_cr(" exclude,<pattern> - don't compile or inline"); tty->print_cr(" Sets <option> to the specified value for methods matching <method pattern>");
tty->print_cr(" inline,<pattern> - always inline"); tty->print_cr(" All options are typed");
tty->print_cr(" dontinline,<pattern> - don't inline");
tty->print_cr(" compileonly,<pattern> - compile only");
tty->print_cr(" log,<pattern> - log compilation");
tty->print_cr(" option,<pattern>,<option type>,<option name>,<value>");
tty->print_cr(" - set value of custom option");
tty->print_cr(" option,<pattern>,<bool option name>");
tty->print_cr(" - shorthand for setting boolean flag");
tty->print_cr(" quiet - silence the compile command output");
tty->print_cr(" help - print this text");
tty->cr(); tty->cr();
tty->print_cr("The preferred format for the method matching pattern is:"); tty->print_cr("-XX:CompileCommand=<option><method pattern>");
tty->print_cr(" Sets <option> to true for methods matching <method pattern>");
tty->print_cr(" Only applies to boolean options.");
tty->cr();
tty->print_cr("-XX:CompileCommand=quiet");
tty->print_cr(" Silence the compile command output");
tty->cr();
tty->print_cr("-XX:CompileCommand=help");
tty->print_cr(" Prints this help text");
tty->cr();
print_commands();
tty->cr();
tty->print_cr("Method patterns has the format:");
tty->print_cr(" package/Class.method()"); tty->print_cr(" package/Class.method()");
tty->cr(); tty->cr();
tty->print_cr("For backward compatibility this form is also allowed:"); tty->print_cr("For backward compatibility this form is also allowed:");
@ -428,7 +483,7 @@ static void usage() {
tty->print_cr(" package/Class.method ()"); tty->print_cr(" package/Class.method ()");
tty->cr(); tty->cr();
tty->print_cr("The class and method identifier can be used together with leading or"); tty->print_cr("The class and method identifier can be used together with leading or");
tty->print_cr("trailing *'s for a small amount of wildcarding:"); tty->print_cr("trailing *'s for wildcard matching:");
tty->print_cr(" *ackage/Clas*.*etho*()"); tty->print_cr(" *ackage/Clas*.*etho*()");
tty->cr(); tty->cr();
tty->print_cr("It is possible to use more than one CompileCommand on the command line:"); tty->print_cr("It is possible to use more than one CompileCommand on the command line:");
@ -447,59 +502,68 @@ static void usage() {
tty->cr(); tty->cr();
}; };
// Scan next flag and value in line, return MethodMatcher object on success, NULL on failure. int skip_whitespace(char* &line) {
// On failure, error_msg contains description for the first error. // Skip any leading spaces
// For future extensions: set error_msg on first error. int whitespace_read = 0;
static void scan_flag_and_value(const char* type, const char* line, int& total_bytes_read, sscanf(line, "%*[ \t]%n", &whitespace_read);
TypedMethodOptionMatcher* matcher, line += whitespace_read;
char* errorbuf, const int buf_size) { return whitespace_read;
total_bytes_read = 0; }
void skip_comma(char* &line) {
// Skip any leading spaces
if (*line == ',') {
line++;
}
}
static void scan_value(enum OptionType type, char* line, int& total_bytes_read,
TypedMethodOptionMatcher* matcher, enum CompileCommand option, char* errorbuf, const int buf_size) {
int bytes_read = 0; int bytes_read = 0;
char flag[256]; const char* ccname = option2name(option);
const char* type_str = optiontype2name(type);
// Read flag name. int skipped = skip_whitespace(line);
if (sscanf(line, "%*[ \t]%255[a-zA-Z0-9]%n", flag, &bytes_read) == 1) { total_bytes_read += skipped;
line += bytes_read; if (type == OptionType::Intx) {
total_bytes_read += bytes_read;
// Read value.
if (strcmp(type, "intx") == 0) {
intx value; intx value;
if (sscanf(line, "%*[ \t]" INTX_FORMAT "%n", &value, &bytes_read) == 1) { if (sscanf(line, "" INTX_FORMAT "%n", &value, &bytes_read) == 1) {
total_bytes_read += bytes_read; total_bytes_read += bytes_read;
add_option_string(matcher, flag, value); line += bytes_read;
register_command(matcher, option, value);
return; return;
} else { } else {
jio_snprintf(errorbuf, buf_size, " Value cannot be read for flag %s of type %s ", flag, type); jio_snprintf(errorbuf, buf_size, "Value cannot be read for option '%s' of type '%s'", ccname, type_str);
} }
} else if (strcmp(type, "uintx") == 0) { } else if (type == OptionType::Uintx) {
uintx value; uintx value;
if (sscanf(line, "%*[ \t]" UINTX_FORMAT "%n", &value, &bytes_read) == 1) { if (sscanf(line, "" UINTX_FORMAT "%n", &value, &bytes_read) == 1) {
total_bytes_read += bytes_read; total_bytes_read += bytes_read;
add_option_string(matcher, flag, value); line += bytes_read;
register_command(matcher, option, value);
return; return;
} else { } else {
jio_snprintf(errorbuf, buf_size, " Value cannot be read for flag %s of type %s", flag, type); jio_snprintf(errorbuf, buf_size, "Value cannot be read for option '%s' of type '%s'", ccname, type_str);
} }
} else if (strcmp(type, "ccstr") == 0) { } else if (type == OptionType::Ccstr) {
ResourceMark rm; ResourceMark rm;
char* value = NEW_RESOURCE_ARRAY(char, strlen(line) + 1); char* value = NEW_RESOURCE_ARRAY(char, strlen(line) + 1);
if (sscanf(line, "%*[ \t]%255[_a-zA-Z0-9]%n", value, &bytes_read) == 1) { if (sscanf(line, "%255[_a-zA-Z0-9]%n", value, &bytes_read) == 1) {
total_bytes_read += bytes_read; total_bytes_read += bytes_read;
add_option_string(matcher, flag, (ccstr)value); line += bytes_read;
register_command(matcher, option, (ccstr) value);
return; return;
} else { } else {
jio_snprintf(errorbuf, buf_size, " Value cannot be read for flag %s of type %s", flag, type); jio_snprintf(errorbuf, buf_size, "Value cannot be read for option '%s' of type '%s'", ccname, type_str);
} }
} else if (strcmp(type, "ccstrlist") == 0) { } else if (type == OptionType::Ccstrlist) {
// Accumulates several strings into one. The internal type is ccstr. // Accumulates several strings into one. The internal type is ccstr.
ResourceMark rm; ResourceMark rm;
char* value = NEW_RESOURCE_ARRAY(char, strlen(line) + 1); char* value = NEW_RESOURCE_ARRAY(char, strlen(line) + 1);
char* next_value = value; char* next_value = value;
if (sscanf(line, "%*[ \t]%255[_a-zA-Z0-9+\\-]%n", next_value, &bytes_read) == 1) { if (sscanf(line, "%255[_a-zA-Z0-9+\\-]%n", next_value, &bytes_read) == 1) {
total_bytes_read += bytes_read; total_bytes_read += bytes_read;
line += bytes_read; line += bytes_read;
next_value += bytes_read; next_value += bytes_read + 1;
char* end_value = next_value - 1; char* end_value = next_value - 1;
while (sscanf(line, "%*[ \t]%255[_a-zA-Z0-9+\\-]%n", next_value, &bytes_read) == 1) { while (sscanf(line, "%*[ \t]%255[_a-zA-Z0-9+\\-]%n", next_value, &bytes_read) == 1) {
total_bytes_read += bytes_read; total_bytes_read += bytes_read;
@ -508,184 +572,236 @@ static void scan_flag_and_value(const char* type, const char* line, int& total_b
next_value += bytes_read; next_value += bytes_read;
end_value = next_value-1; end_value = next_value-1;
} }
add_option_string(matcher, flag, (ccstr)value); register_command(matcher, option, (ccstr) value);
return; return;
} else { } else {
jio_snprintf(errorbuf, buf_size, " Value cannot be read for flag %s of type %s", flag, type); jio_snprintf(errorbuf, buf_size, "Value cannot be read for option '%s' of type '%s'", ccname, type_str);
} }
} else if (strcmp(type, "bool") == 0) { } else if (type == OptionType::Bool) {
char value[256]; char value[256];
if (sscanf(line, "%*[ \t]%255[a-zA-Z]%n", value, &bytes_read) == 1) { if (*line == '\0') {
if (strcmp(value, "true") == 0) { // Short version of a CompileCommand sets a boolean Option to true
total_bytes_read += bytes_read; // -XXCompileCommand=<Option>,<method pattern>
add_option_string(matcher, flag, true); register_command(matcher, option, true);
return; return;
} else if (strcmp(value, "false") == 0) { }
if (sscanf(line, "%255[a-zA-Z]%n", value, &bytes_read) == 1) {
if (strcasecmp(value, "true") == 0) {
total_bytes_read += bytes_read; total_bytes_read += bytes_read;
add_option_string(matcher, flag, false); line += bytes_read;
register_command(matcher, option, true);
return;
} else if (strcasecmp(value, "false") == 0) {
total_bytes_read += bytes_read;
line += bytes_read;
register_command(matcher, option, false);
return; return;
} else { } else {
jio_snprintf(errorbuf, buf_size, " Value cannot be read for flag %s of type %s", flag, type); jio_snprintf(errorbuf, buf_size, "Value cannot be read for option '%s' of type '%s'", ccname, type_str);
} }
} else { } else {
jio_snprintf(errorbuf, buf_size, " Value cannot be read for flag %s of type %s", flag, type); jio_snprintf(errorbuf, buf_size, "Value cannot be read for option '%s' of type '%s'", ccname, type_str);
} }
} else if (strcmp(type, "double") == 0) { } else if (type == OptionType::Double) {
char buffer[2][256]; char buffer[2][256];
// Decimal separator '.' has been replaced with ' ' or '/' earlier, // Decimal separator '.' has been replaced with ' ' or '/' earlier,
// so read integer and fraction part of double value separately. // so read integer and fraction part of double value separately.
if (sscanf(line, "%*[ \t]%255[0-9]%*[ /\t]%255[0-9]%n", buffer[0], buffer[1], &bytes_read) == 2) { if (sscanf(line, "%255[0-9]%*[ /\t]%255[0-9]%n", buffer[0], buffer[1], &bytes_read) == 2) {
char value[512] = ""; char value[512] = "";
jio_snprintf(value, sizeof(value), "%s.%s", buffer[0], buffer[1]); jio_snprintf(value, sizeof(value), "%s.%s", buffer[0], buffer[1]);
total_bytes_read += bytes_read; total_bytes_read += bytes_read;
add_option_string(matcher, flag, atof(value)); line += bytes_read;
register_command(matcher, option, atof(value));
return; return;
} else { } else {
jio_snprintf(errorbuf, buf_size, " Value cannot be read for flag %s of type %s", flag, type); jio_snprintf(errorbuf, buf_size, "Value cannot be read for option '%s' of type '%s'", ccname, type_str);
} }
} else { } else {
jio_snprintf(errorbuf, buf_size, " Type %s not supported ", type); jio_snprintf(errorbuf, buf_size, "Type '%s' not supported ", type_str);
} }
}
// Scan next option 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 void scan_option_and_value(enum OptionType type, char* line, int& total_bytes_read,
TypedMethodOptionMatcher* matcher,
char* errorbuf, const int buf_size) {
total_bytes_read = 0;
int bytes_read = 0;
char option_buf[256];
// Read option name.
if (sscanf(line, "%*[ \t]%255[a-zA-Z0-9]%n", option_buf, &bytes_read) == 1) {
line += bytes_read;
total_bytes_read += bytes_read;
int bytes_read2 = 0;
total_bytes_read += skip_whitespace(line);
enum CompileCommand option = parse_option_name(option_buf, &bytes_read2, errorbuf, buf_size);
if (option == CompileCommand::Unknown) {
assert(*errorbuf != '\0', "error must have been set");
return;
}
enum OptionType optiontype = option2type(option);
if (option2type(option) != type) {
const char* optiontype_name = optiontype2name(optiontype);
const char* type_name = optiontype2name(type);
jio_snprintf(errorbuf, buf_size, "Option '%s' with type '%s' doesn't match supplied type '%s'", option_buf, optiontype_name, type_name);
return;
}
scan_value(type, line, total_bytes_read, matcher, option, errorbuf, buf_size);
} else { } else {
jio_snprintf(errorbuf, buf_size, " Flag name for type %s should be alphanumeric ", type); const char* type_str = optiontype2name(type);
jio_snprintf(errorbuf, buf_size, "Option name for type '%s' should be alphanumeric ", type_str);
} }
return; return;
} }
int skip_whitespace(char* line) { void CompilerOracle::print_parse_error(char* error_msg, char* original_line) {
// Skip any leading spaces assert(*error_msg != '\0', "Must have error_message");
int whitespace_read = 0;
sscanf(line, "%*[ \t]%n", &whitespace_read);
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; ttyLocker ttyl;
tty->print_cr("CompileCommand: An error occurred during parsing"); tty->print_cr("CompileCommand: An error occurred during parsing");
tty->print_cr("Line: %s", original_line);
tty->print_cr("Error: %s", error_msg); tty->print_cr("Error: %s", error_msg);
CompilerOracle::print_tip(); tty->print_cr("Line: '%s'", original_line);
print_tip();
} }
enum OptionType parse_option_type(const char* type_str) {
for (uint i = 0; i < ARRAY_SIZE(optiontype_names); i++) {
if (strcasecmp(type_str, optiontype_names[i]) == 0) {
return static_cast<enum OptionType>(i);
}
}
return OptionType::Unknown;
}
class LineCopy : StackObj {
const char* _copy;
public:
LineCopy(char* line) {
_copy = os::strdup(line, mtInternal);
}
~LineCopy() {
os::free((void*)_copy);
}
char* get() {
return (char*)_copy;
}
};
void CompilerOracle::parse_from_line(char* line) { void CompilerOracle::parse_from_line(char* line) {
if (line[0] == '\0') return; if (line[0] == '\0') return;
if (line[0] == '#') return; if (line[0] == '#') return;
char* original_line = line; LineCopy original(line);
int bytes_read; int bytes_read;
OracleCommand command = parse_command_name(line, &bytes_read); char error_buf[1024] = {0};
enum CompileCommand option = parse_option_name(line, &bytes_read, error_buf, sizeof(error_buf));
line += bytes_read; line += bytes_read;
ResourceMark rm; ResourceMark rm;
if (command == UnknownCommand) { if (option == CompileCommand::Unknown) {
ttyLocker ttyl; print_parse_error(error_buf, original.get());
tty->print_cr("CompileCommand: unrecognized command");
tty->print_cr(" \"%s\"", original_line);
CompilerOracle::print_tip();
return; return;
} }
if (command == QuietCommand) { if (option == CompileCommand::Quiet) {
_quiet = true; _quiet = true;
return; return;
} }
if (command == HelpCommand) { if (option == CompileCommand::Help) {
usage(); usage();
return; return;
} }
const char* error_msg = NULL; if (option == CompileCommand::Option) {
if (command == OptionCommand) {
// Look for trailing options. // Look for trailing options.
// //
// Two types of trailing options are // Two types of trailing options are
// supported: // supported:
// //
// (1) CompileCommand=option,Klass::method,flag // (1) CompileCommand=option,Klass::method,option
// (2) CompileCommand=option,Klass::method,type,flag,value // (2) CompileCommand=option,Klass::method,type,option,value
// //
// Type (1) is used to enable a boolean flag for a method. // Type (1) is used to enable a boolean option for a method.
// //
// Type (2) is used to support options with a value. Values can have the // Type (2) is used to support options with a value. Values can have the
// the following types: intx, uintx, bool, ccstr, ccstrlist, and double. // 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) char option_type[256]; // stores option for Type (1) and type of Type (2)
line++; // skip the ',' skip_comma(line);
TypedMethodOptionMatcher* archetype = TypedMethodOptionMatcher::parse_method_pattern(line, error_msg); TypedMethodOptionMatcher* archetype = TypedMethodOptionMatcher::parse_method_pattern(line, error_buf, sizeof(error_buf));
if (archetype == NULL) { if (archetype == NULL) {
assert(error_msg != NULL, "Must have error_message"); print_parse_error(error_buf, original.get());
print_parse_error(error_msg, original_line);
return; return;
} }
line += skip_whitespace(line); skip_whitespace(line);
// This is unnecessarily complex. Should retire multi-option lines and skip while loop // 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) { while (sscanf(line, "%255[a-zA-Z0-9]%n", option_type, &bytes_read) == 1) {
line += bytes_read; line += bytes_read;
// typed_matcher is used as a blueprint for each option, deleted at the end // typed_matcher is used as a blueprint for each option, deleted at the end
TypedMethodOptionMatcher* typed_matcher = archetype->clone(); TypedMethodOptionMatcher* typed_matcher = archetype->clone();
if (strcmp(option, "intx") == 0 enum OptionType type = parse_option_type(option_type);
|| strcmp(option, "uintx") == 0 if (type != OptionType::Unknown) {
|| strcmp(option, "bool") == 0 // Type (2) option: parse option name and value.
|| strcmp(option, "ccstr") == 0 scan_option_and_value(type, line, bytes_read, typed_matcher, error_buf, sizeof(error_buf));
|| strcmp(option, "ccstrlist") == 0 if (*error_buf != '\0') {
|| strcmp(option, "double") == 0 print_parse_error(error_buf, original.get());
) {
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; return;
} }
line += bytes_read; line += bytes_read;
} else { } else {
// Type (1) option // Type (1) option - option_type contains the option name -> bool value = true is implied
add_option_string(typed_matcher, option, true); int bytes_read;
} enum CompileCommand option = parse_option_name(option_type, &bytes_read, error_buf, sizeof(error_buf));
if (typed_matcher != NULL && !_quiet) { if (option == CompileCommand::Unknown) {
// Print out the last match added print_parse_error(error_buf, original.get());
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");
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; return;
} }
register_command(typed_matcher, option, true);
add_predicate(command, matcher); }
if (!_quiet) { assert(typed_matcher != NULL, "sanity");
ttyLocker ttyl; assert(*error_buf == '\0', "No error here");
tty->print("CompileCommand: %s ", command_names[command]); skip_whitespace(line);
matcher->print(tty); } // while(
tty->cr(); delete archetype;
} else { // not an OptionCommand
// Command has the following form:
// CompileCommand=<option>,<method pattern><value>
// CompileCommand=<option>,<method pattern> (implies option is bool and value is true)
assert(*error_buf == '\0', "Don't call here with error_buf already set");
enum OptionType type = option2type(option);
int bytes_read = 0;
skip_comma(line);
TypedMethodOptionMatcher* matcher = TypedMethodOptionMatcher::parse_method_pattern(line, error_buf, sizeof(error_buf));
if (matcher == NULL) {
print_parse_error(error_buf, original.get());
return;
}
skip_whitespace(line);
if (*line == '\0') {
// if this is a bool option this implies true
if (option2type(option) == OptionType::Bool) {
register_command(matcher, option, true);
return;
} else {
jio_snprintf(error_buf, sizeof(error_buf), " Option '%s' is not followed by a value", option2name(option));
print_parse_error(error_buf, original.get());
return;
} }
} }
scan_value(type, line, bytes_read, matcher, option, error_buf, sizeof(error_buf));
if (*error_buf != '\0') {
print_parse_error(error_buf, original.get());
return;
}
assert(matcher != NULL, "consistency");
} }
void CompilerOracle::print_tip() {
tty->cr();
tty->print_cr("Usage: '-XX:CompileCommand=command,\"package/Class.method()\"'");
tty->print_cr("Use: '-XX:CompileCommand=help' for more information.");
tty->cr();
} }
static const char* default_cc_file = ".hotspot_compiler"; static const char* default_cc_file = ".hotspot_compiler";
@ -760,7 +876,7 @@ void compilerOracle_init() {
default_cc_file, default_cc_file); default_cc_file, default_cc_file);
} }
} }
if (lists[PrintCommand] != NULL) { if (has_command(CompileCommand::Print)) {
if (PrintAssembly) { if (PrintAssembly) {
warning("CompileCommand and/or %s file contains 'print' commands, but PrintAssembly is also enabled", default_cc_file); warning("CompileCommand and/or %s file contains 'print' commands, but PrintAssembly is also enabled", default_cc_file);
} else if (FLAG_IS_DEFAULT(DebugNonSafepoints)) { } else if (FLAG_IS_DEFAULT(DebugNonSafepoints)) {
@ -770,7 +886,6 @@ void compilerOracle_init() {
} }
} }
void CompilerOracle::parse_compile_only(char* line) { void CompilerOracle::parse_compile_only(char* line) {
int i; int i;
char name[1024]; char name[1024];
@ -841,12 +956,12 @@ void CompilerOracle::parse_compile_only(char * line) {
Symbol* m_name = SymbolTable::new_symbol(methodName); Symbol* m_name = SymbolTable::new_symbol(methodName);
Symbol* signature = NULL; Symbol* signature = NULL;
BasicMatcher* bm = new BasicMatcher(); TypedMethodOptionMatcher* tom = new TypedMethodOptionMatcher();
bm->init(c_name, c_match, m_name, m_match, signature); tom->init_matcher(c_name, c_match, m_name, m_match, signature);
add_predicate(CompileOnlyCommand, bm); register_command(tom, CompileCommand::CompileOnly, true);
if (PrintVMOptions) { if (PrintVMOptions) {
tty->print("CompileOnly: compileonly "); tty->print("CompileOnly: compileonly ");
lists[CompileOnlyCommand]->print_all(tty); tom->print();
} }
className = NULL; className = NULL;
@ -856,3 +971,9 @@ void CompilerOracle::parse_compile_only(char * line) {
line = *line == '\0' ? line : line + 1; line = *line == '\0' ? line : line + 1;
} }
} }
enum CompileCommand CompilerOracle::string_to_option(const char* name) {
int bytes_read = 0;
char errorbuf[1024] = {0};
return parse_option_name(name, &bytes_read, errorbuf, sizeof(errorbuf));
}

View file

@ -30,17 +30,91 @@
class methodHandle; class methodHandle;
// CompilerOracle is an interface for turning on and off compilation // CompilerOracle is an interface for turning on and off compilation
// for some methods // for some methods
// OPTION_TYPES: type, name
#define OPTION_TYPES(type) \
type(Intx, "intx") \
type(Uintx, "uintx") \
type(Bool, "bool") \
type(Ccstr, "ccstr") \
type(Ccstrlist, "ccstrlist") \
type(Double, "double")
// COMPILECOMMAND_OPTIONS: option, name, variant, type
#define COMPILECOMMAND_OPTIONS(option) \
option(Help, "help", Unknown) \
option(Quiet, "quiet", Unknown) \
option(Log, "log", Bool) \
option(Print, "print", Bool) \
option(Inline, "inline", Bool) \
option(DontInline, "dontinline", Bool) \
option(CompileOnly, "compileonly", Bool)\
option(Exclude, "exclude", Bool) \
option(Break, "break", Bool) \
option(BreakAtExecute, "BreakAtExecute", Bool) \
option(BreakAtCompile, "BreakAtCompile", Bool) \
option(PrintAssembly, "PrintAssembly", Bool) \
option(PrintInlining, "PrintInlining", Bool) \
option(PrintIntrinsics, "PrintIntrinsics", Bool) \
option(PrintNMethods, "PrintNMethods", Bool) \
option(PrintOptoAssembly, "PrintOptoAssembly", Bool) \
option(PrintDebugInfo, "PrintDebugInfo", Bool) \
option(PrintRelocations, "PrintRelocations", Bool) \
option(PrintDependencies, "PrintDependencies", Bool) \
option(BackgroundCompilation, "BackgroundCompilation", Bool) \
option(RepeatCompilation, "RepeatCompilation", Intx) \
option(ReplayInline, "ReplayInline", Bool) \
option(DumpReplay, "DumpReplay", Bool) \
option(DumpInline, "DumpInline", Bool) \
option(CompileThresholdScaling, "CompileThresholdScaling", Double) \
option(ControlIntrinsic, "ControlIntrinsic", Ccstrlist) \
option(DisableIntrinsic, "DisableIntrinsic", Ccstrlist) \
option(NoRTMLockEliding, "NoRTMLockEliding", Bool) \
option(UseRTMLockEliding, "UseRTMLockEliding", Bool) \
option(BlockLayoutByFrequency, "BlockLayoutByFrequency", Bool) \
option(TraceOptoPipelining, "TraceOptoPipelining", Bool) \
option(TraceOptoOutput, "TraceOptoOutput", Bool) \
option(TraceSpilling, "TraceSpilling", Bool) \
option(PrintIdeal, "PrintIdeal", Bool) \
option(IGVPrintLevel, "IGVPrintLevel", Intx) \
option(Vectorize, "Vectorize", Bool) \
option(VectorizeDebug, "VectorizeDebug", Uintx) \
option(CloneMapDebug, "CloneMapDebug", Bool) \
option(MaxNodeLimit, "MaxNodeLimit", Intx) \
NOT_PRODUCT(option(TestOptionInt, "TestOptionInt", Intx)) \
NOT_PRODUCT(option(TestOptionUint, "TestOptionUint", Uintx)) \
NOT_PRODUCT(option(TestOptionBool, "TestOptionBool", Bool)) \
NOT_PRODUCT(option(TestOptionBool2, "TestOptionBool2", Bool)) \
NOT_PRODUCT(option(TestOptionStr, "TestOptionStr", Ccstr)) \
NOT_PRODUCT(option(TestOptionList, "TestOptionList", Ccstrlist)) \
NOT_PRODUCT(option(TestOptionDouble, "TestOptionDouble", Double)) \
option(Option, "option", Unknown) \
option(Unknown, "unknown", Unknown)
enum class CompileCommand {
#define enum_of_options(option, name, ctype) option,
COMPILECOMMAND_OPTIONS(enum_of_options)
#undef enum_of_options
Count
};
enum class OptionType {
#define enum_of_types(type, name) type,
OPTION_TYPES(enum_of_types)
#undef enum_of_types
Unknown
};
class CompilerOracle : AllStatic { class CompilerOracle : AllStatic {
private: private:
static bool _quiet; static bool _quiet;
static void print_tip(); static void print_parse_error(char* error_msg, char* original_line);
static void print_parse_error(const char*& error_msg, char* original_line); static void print_command(enum CompileCommand option, const char* name, enum OptionType type);
public: public:
// True if the command file has been specified or is implicit // True if the command file has been specified or is implicit
static bool has_command_file(); static bool has_command_file();
@ -49,7 +123,7 @@ class CompilerOracle : AllStatic {
// Tells whether we to exclude compilation of method // Tells whether we to exclude compilation of method
static bool should_exclude(const methodHandle& method); static bool should_exclude(const methodHandle& method);
static bool should_exclude_quietly() { return _quiet; } static bool be_quiet() { return _quiet; }
// Tells whether we want to inline this method // Tells whether we want to inline this method
static bool should_inline(const methodHandle& method); static bool should_inline(const methodHandle& method);
@ -66,25 +140,28 @@ class CompilerOracle : AllStatic {
// Tells whether to break when compiling method // Tells whether to break when compiling method
static bool should_break_at(const methodHandle& method); static bool should_break_at(const methodHandle& method);
// Check to see if this method has option set for it // Tells whether there are any methods to print for print_method_statistics()
static bool has_option_string(const methodHandle& method, const char * option); static bool should_print_methods();
// A wrapper for checking bool options
static bool has_option(const methodHandle& method, enum CompileCommand option);
// Check if method has option and value set. If yes, overwrite value and return true, // Check if method has option and value set. If yes, overwrite value and return true,
// otherwise leave value unchanged and return false. // otherwise leave value unchanged and return false.
template<typename T> template<typename T>
static bool has_option_value(const methodHandle& method, const char* option, T& value); static bool has_option_value(const methodHandle& method, enum CompileCommand option, T& value, bool verfiy_type = false);
// Fast check if there is any option available that compile control needs to know about
static bool has_any_option();
// Reads from string instead of file // Reads from string instead of file
static void parse_from_string(const char* command_string, void (*parser)(char*)); static void parse_from_string(const char* option_string, void (*parser)(char*));
static void parse_from_line(char* line); static void parse_from_line(char* line);
static void parse_compile_only(char* line); static void parse_compile_only(char* line);
// Tells whether there are any methods to print for print_method_statistics() // Fast check if there is any option set that compile control needs to know about
static bool should_print_methods(); static bool has_any_command_set();
// convert a string to a proper compilecommand option - used from whitebox.
// returns CompileCommand::Unknown on names not matching an option.
static enum CompileCommand string_to_option(const char* name);
}; };
#endif // SHARE_COMPILER_COMPILERORACLE_HPP #endif // SHARE_COMPILER_COMPILERORACLE_HPP

View file

@ -259,6 +259,10 @@ void MethodMatcher::parse_method_pattern(char*& line, const char*& error_msg, Me
} }
skip_leading_spaces(line, &total_bytes_read); skip_leading_spaces(line, &total_bytes_read);
if (*line == '\0') {
error_msg = "Method pattern missing from command";
return;
}
if (2 == sscanf(line, "%255" RANGESLASH "%*[ ]" "%255" RANGE0 "%n", class_name, method_name, &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); c_match = check_mode(class_name, error_msg);
@ -352,7 +356,7 @@ void MethodMatcher::print_base(outputStream* st) {
} }
} }
BasicMatcher* BasicMatcher::parse_method_pattern(char* line, const char*& error_msg) { BasicMatcher* BasicMatcher::parse_method_pattern(char* line, const char*& error_msg, bool expect_trailing_chars) {
assert(error_msg == NULL, "Don't call here with error_msg already set"); assert(error_msg == NULL, "Don't call here with error_msg already set");
BasicMatcher *bm = new BasicMatcher(); BasicMatcher *bm = new BasicMatcher();
MethodMatcher::parse_method_pattern(line, error_msg, bm); MethodMatcher::parse_method_pattern(line, error_msg, bm);
@ -360,7 +364,7 @@ BasicMatcher* BasicMatcher::parse_method_pattern(char* line, const char*& error_
delete bm; delete bm;
return NULL; return NULL;
} }
if (!expect_trailing_chars) {
// check for bad trailing characters // check for bad trailing characters
int bytes_read = 0; int bytes_read = 0;
sscanf(line, "%*[ \t]%n", &bytes_read); sscanf(line, "%*[ \t]%n", &bytes_read);
@ -369,6 +373,7 @@ BasicMatcher* BasicMatcher::parse_method_pattern(char* line, const char*& error_
delete bm; delete bm;
return NULL; return NULL;
} }
}
return bm; return bm;
} }
@ -426,7 +431,6 @@ InlineMatcher* InlineMatcher::parse_inline_pattern(char* str, const char*& error
} }
str++; str++;
int bytes_read = 0;
assert(error_msg == NULL, "error_msg must not be set yet"); assert(error_msg == NULL, "error_msg must not be set yet");
InlineMatcher* im = InlineMatcher::parse_method_pattern(str, error_msg); InlineMatcher* im = InlineMatcher::parse_method_pattern(str, error_msg);
if (im == NULL) { if (im == NULL) {

View file

@ -81,7 +81,7 @@ public:
_next(next) { _next(next) {
} }
static BasicMatcher* parse_method_pattern(char* line, const char*& error_msg); static BasicMatcher* parse_method_pattern(char* line, const char*& error_msg, bool expect_trailing_chars);
bool match(const methodHandle& method); bool match(const methodHandle& method);
void set_next(BasicMatcher* next) { _next = next; } void set_next(BasicMatcher* next) { _next = next; }
BasicMatcher* next() { return _next; } BasicMatcher* next() { return _next; }

View file

@ -47,7 +47,7 @@
bool TieredThresholdPolicy::call_predicate_helper(const methodHandle& method, CompLevel cur_level, int i, int b, double scale) { bool TieredThresholdPolicy::call_predicate_helper(const methodHandle& method, CompLevel cur_level, int i, int b, double scale) {
double threshold_scaling; double threshold_scaling;
if (CompilerOracle::has_option_value(method, "CompileThresholdScaling", threshold_scaling)) { if (CompilerOracle::has_option_value(method, CompileCommand::CompileThresholdScaling, threshold_scaling)) {
scale *= threshold_scaling; scale *= threshold_scaling;
} }
switch(cur_level) { switch(cur_level) {
@ -78,7 +78,7 @@ bool TieredThresholdPolicy::call_predicate_helper(const methodHandle& method, Co
bool TieredThresholdPolicy::loop_predicate_helper(const methodHandle& method, CompLevel cur_level, int i, int b, double scale) { bool TieredThresholdPolicy::loop_predicate_helper(const methodHandle& method, CompLevel cur_level, int i, int b, double scale) {
double threshold_scaling; double threshold_scaling;
if (CompilerOracle::has_option_value(method, "CompileThresholdScaling", threshold_scaling)) { if (CompilerOracle::has_option_value(method, CompileCommand::CompileThresholdScaling, threshold_scaling)) {
scale *= threshold_scaling; scale *= threshold_scaling;
} }
switch(cur_level) { switch(cur_level) {

View file

@ -94,7 +94,7 @@ class MethodCounters : public Metadata {
// Set per-method thresholds. // Set per-method thresholds.
double scale = 1.0; double scale = 1.0;
CompilerOracle::has_option_value(mh, "CompileThresholdScaling", scale); CompilerOracle::has_option_value(mh, CompileCommand::CompileThresholdScaling, scale);
int compile_threshold = CompilerConfig::scaled_compile_threshold(CompileThreshold, scale); int compile_threshold = CompilerConfig::scaled_compile_threshold(CompileThreshold, scale);
_interpreter_invocation_limit = compile_threshold << InvocationCounter::count_shift; _interpreter_invocation_limit = compile_threshold << InvocationCounter::count_shift;

View file

@ -1289,7 +1289,7 @@ void MethodData::init() {
// Set per-method invoke- and backedge mask. // Set per-method invoke- and backedge mask.
double scale = 1.0; double scale = 1.0;
methodHandle mh(Thread::current(), _method); methodHandle mh(Thread::current(), _method);
CompilerOracle::has_option_value(mh, "CompileThresholdScaling", scale); CompilerOracle::has_option_value(mh, CompileCommand::CompileThresholdScaling, scale);
_invoke_mask = right_n_bits(CompilerConfig::scaled_freq_log(Tier0InvokeNotifyFreqLog, scale)) << InvocationCounter::count_shift; _invoke_mask = right_n_bits(CompilerConfig::scaled_freq_log(Tier0InvokeNotifyFreqLog, scale)) << InvocationCounter::count_shift;
_backedge_mask = right_n_bits(CompilerConfig::scaled_freq_log(Tier0BackedgeNotifyFreqLog, scale)) << InvocationCounter::count_shift; _backedge_mask = right_n_bits(CompilerConfig::scaled_freq_log(Tier0BackedgeNotifyFreqLog, scale)) << InvocationCounter::count_shift;
@ -1306,8 +1306,8 @@ void MethodData::init() {
#if INCLUDE_RTM_OPT #if INCLUDE_RTM_OPT
_rtm_state = NoRTM; // No RTM lock eliding by default _rtm_state = NoRTM; // No RTM lock eliding by default
if (UseRTMLocking && if (UseRTMLocking &&
!CompilerOracle::has_option_string(mh, "NoRTMLockEliding")) { !CompilerOracle::has_option(mh, CompileCommand::NoRTMLockEliding)) {
if (CompilerOracle::has_option_string(mh, "UseRTMLockEliding") || !UseRTMDeopt) { if (CompilerOracle::has_option(mh, CompileCommand::UseRTMLockEliding) || !UseRTMDeopt) {
// Generate RTM lock eliding code without abort ratio calculation code. // Generate RTM lock eliding code without abort ratio calculation code.
_rtm_state = UseRTM; _rtm_state = UseRTM;
} else if (UseRTMDeopt) { } else if (UseRTMDeopt) {

View file

@ -953,10 +953,10 @@ void Compile::Init(int aliaslevel) {
#if INCLUDE_RTM_OPT #if INCLUDE_RTM_OPT
if (UseRTMLocking && has_method() && (method()->method_data_or_null() != NULL)) { if (UseRTMLocking && has_method() && (method()->method_data_or_null() != NULL)) {
int rtm_state = method()->method_data()->rtm_state(); int rtm_state = method()->method_data()->rtm_state();
if (method_has_option("NoRTMLockEliding") || ((rtm_state & NoRTM) != 0)) { if (method_has_option(CompileCommand::NoRTMLockEliding) || ((rtm_state & NoRTM) != 0)) {
// Don't generate RTM lock eliding code. // Don't generate RTM lock eliding code.
set_rtm_state(NoRTM); set_rtm_state(NoRTM);
} else if (method_has_option("UseRTMLockEliding") || ((rtm_state & UseRTM) != 0) || !UseRTMDeopt) { } else if (method_has_option(CompileCommand::UseRTMLockEliding) || ((rtm_state & UseRTM) != 0) || !UseRTMDeopt) {
// Generate RTM lock eliding code without abort ratio calculation code. // Generate RTM lock eliding code without abort ratio calculation code.
set_rtm_state(UseRTM); set_rtm_state(UseRTM);
} else if (UseRTMDeopt) { } else if (UseRTMDeopt) {

View file

@ -594,7 +594,7 @@ class Compile : public Phase {
void set_clinit_barrier_on_entry(bool z) { _clinit_barrier_on_entry = z; } void set_clinit_barrier_on_entry(bool z) { _clinit_barrier_on_entry = z; }
// check the CompilerOracle for special behaviours for this compile // check the CompilerOracle for special behaviours for this compile
bool method_has_option(const char * option) { bool method_has_option(enum CompileCommand option) {
return method() != NULL && method()->has_option(option); return method() != NULL && method()->has_option(option);
} }

View file

@ -1056,7 +1056,7 @@ WB_ENTRY(jint, WB_MatchesMethod(JNIEnv* env, jobject o, jobject method, jstring
const char* error_msg = NULL; const char* error_msg = NULL;
BasicMatcher* m = BasicMatcher::parse_method_pattern(method_str, error_msg); BasicMatcher* m = BasicMatcher::parse_method_pattern(method_str, error_msg, false);
if (m == NULL) { if (m == NULL) {
assert(error_msg != NULL, "Must have error_msg"); assert(error_msg != NULL, "Must have error_msg");
tty->print_cr("Got error: %s", error_msg); tty->print_cr("Got error: %s", error_msg);
@ -1810,9 +1810,12 @@ static bool GetMethodOption(JavaThread* thread, JNIEnv* env, jobject method, jst
ThreadToNativeFromVM ttnfv(thread); ThreadToNativeFromVM ttnfv(thread);
const char* flag_name = env->GetStringUTFChars(name, NULL); const char* flag_name = env->GetStringUTFChars(name, NULL);
CHECK_JNI_EXCEPTION_(env, false); CHECK_JNI_EXCEPTION_(env, false);
bool result = CompilerOracle::has_option_value(mh, flag_name, *value); enum CompileCommand option = CompilerOracle::string_to_option(flag_name);
env->ReleaseStringUTFChars(name, flag_name); env->ReleaseStringUTFChars(name, flag_name);
return result; if (option == CompileCommand::Unknown) {
return false;
}
return CompilerOracle::has_option_value(mh, option, *value, true /* verify type*/);
} }
WB_ENTRY(jobject, WB_GetMethodBooleaneOption(JNIEnv* env, jobject wb, jobject method, jstring name)) WB_ENTRY(jobject, WB_GetMethodBooleaneOption(JNIEnv* env, jobject wb, jobject method, jstring name))

View file

@ -28,6 +28,7 @@
* @library /test/lib * @library /test/lib
* @modules java.base/jdk.internal.misc * @modules java.base/jdk.internal.misc
* java.management * java.management
* @requires vm.debug == true
* @run driver compiler.oracle.CheckCompileCommandOption * @run driver compiler.oracle.CheckCompileCommandOption
*/ */
@ -43,12 +44,12 @@ public class CheckCompileCommandOption {
// Currently, two types of trailing options can be used with // Currently, two types of trailing options can be used with
// -XX:CompileCommand=option // -XX:CompileCommand=option
// //
// (1) CompileCommand=option,Klass::method,flag // (1) CompileCommand=option,Klass::method,option
// (2) CompileCommand=option,Klass::method,type,flag,value // (2) CompileCommand=option,Klass::method,type,option,value
// //
// Type (1) is used to enable a boolean flag for a method. // Type (1) is used to enable a boolean option for a method.
// //
// Type (2) is used to support flags with a value. Values can // Type (2) is used to support options with a value. Values can
// have the the following types: intx, uintx, bool, ccstr, // have the the following types: intx, uintx, bool, ccstr,
// ccstrlist, and double. // ccstrlist, and double.
@ -65,85 +66,145 @@ public class CheckCompileCommandOption {
private static final String[][] FILE_EXPECTED_OUTPUT = { private static final String[][] FILE_EXPECTED_OUTPUT = {
{ {
"CompileCommand: option com/oracle/Test.test bool MyBoolOption1 = true", "com/oracle/Test.test1 bool TestOptionBool = true",
"CompileCommand: option com/oracle/Test.test bool MyBoolOption2 = true", "com/oracle/Test.test2 bool TestOptionBool = true",
"CompileCommand: option com/oracle/Test.test bool MyBoolOption3 = true", "com/oracle/Test.test3 bool TestOptionBool = true",
"CompileCommand: option com/oracle/Test.test bool MyBoolOption5 = true", "com/oracle/Test.test4 bool TestOptionBool = true",
"CompileCommand: option com/oracle/Test.test bool MyBoolOption6 = true", "com/oracle/Test.test4 bool TestOptionBool2 = true",
"CompileCommand: option com/oracle/Test.test bool MyBoolOption7 = true", "com/oracle/Test.test5 bool TestOptionBool = true",
"CompileCommand: option com/oracle/Test.test bool MyBoolOption8 = true", "com/oracle/Test.test5 bool TestOptionBool2 = true",
"CompileCommand: option com/oracle/Test.test(I) bool MyBoolOption9 = true", "com/oracle/Test.test6(I) bool TestOptionBool = true",
"CompileCommand: option com/oracle/Test.test(I) bool MyBoolOption10 = true", "com/oracle/Test.test7(I) bool TestOptionBool = true",
"CompileCommand: option com/oracle/Test.test(I) bool MyBoolOption11 = true", "com/oracle/Test.test8(I) bool TestOptionBool = true",
"CompileCommand: option com/oracle/Test.test(I) bool MyBoolOption13 = true", "com/oracle/Test.test9(I) bool TestOptionBool = true",
"CompileCommand: option com/oracle/Test.test(I) bool MyBoolOption14 = true", "com/oracle/Test.test9(I) bool TestOptionBool2 = true",
"CompileCommand: option com/oracle/Test.test(I) bool MyBoolOption15 = true", "com/oracle/Test.test10(I) bool TestOptionBool = true",
"CompileCommand: option com/oracle/Test.test(I) bool MyBoolOption16 = true" "com/oracle/Test.test10(I) bool TestOptionBool2 = true"
}, },
{ {
"CompileCommand: option Test.test const char* MyListOption = '_foo _bar'", "Test.test const char* TestOptionList = '_foo _bar'",
"CompileCommand: option Test.test const char* MyStrOption = '_foo'", "Test.test const char* TestOptionStr = '_foo'",
"CompileCommand: option Test.test bool MyBoolOption = false", "Test.test bool TestOptionBool = false",
"CompileCommand: option Test.test intx MyIntxOption = -1", "Test.test intx TestOptionInt = -1",
"CompileCommand: option Test.test uintx MyUintxOption = 1", "Test.test uintx TestOptionUint = 1",
"CompileCommand: option Test.test bool MyFlag = true", "Test.test bool TestOptionBool2 = true",
"CompileCommand: option Test.test double MyDoubleOption = 1.123000" "Test.test double TestOptionDouble = 1.123000"
} }
}; };
private static final String[][] TYPE_1_ARGUMENTS = { private static final String[][] TYPE_1_ARGUMENTS = {
{ {
"-XX:CompileCommand=option,com/oracle/Test.test,MyBoolOption1", "-XX:CompileCommand=option,com/oracle/Test.test,TestOptionBool",
"-XX:CompileCommand=option,com/oracle/Test,test,MyBoolOption2", "-XX:CompileCommand=option,com/oracle/Test,test,TestOptionBool2",
"-XX:CompileCommand=option,com.oracle.Test::test,MyBoolOption3", "-XX:CompileCommand=option,com/oracle/Test.test2,TestOptionBool2,TestOptionBool",
"-XX:CompileCommand=option,com/oracle/Test.test,MyBoolOption5,MyBoolOption6",
"-XX:CompileCommand=option,com/oracle/Test,test,MyBoolOption7,MyBoolOption8",
"-version" "-version"
} }
}; };
private static final String[][] TYPE_1_EXPECTED_OUTPUTS = { private static final String[][] TYPE_1_EXPECTED_OUTPUTS = {
{ {
"CompileCommand: option com/oracle/Test.test bool MyBoolOption1 = true", "com/oracle/Test.test bool TestOptionBool = true",
"CompileCommand: option com/oracle/Test.test bool MyBoolOption2 = true", "com/oracle/Test.test bool TestOptionBool2 = true",
"CompileCommand: option com/oracle/Test.test bool MyBoolOption3 = true", "com/oracle/Test.test2 bool TestOptionBool = true",
"CompileCommand: option com/oracle/Test.test bool MyBoolOption5 = true", "com/oracle/Test.test2 bool TestOptionBool2 = true",
"CompileCommand: option com/oracle/Test.test bool MyBoolOption6 = true",
"CompileCommand: option com/oracle/Test.test bool MyBoolOption7 = true",
"CompileCommand: option com/oracle/Test.test bool MyBoolOption8 = true"
} }
}; };
private static final String[][] TYPE_2_ARGUMENTS = { private static final String[][] TYPE_2_ARGUMENTS = {
{ {
"-XX:CompileCommand=option,Test::test,ccstrlist,MyListOption,_foo,_bar", "-XX:CompileCommand=option,Test::test,ccstrlist,TestOptionList,_foo,_bar",
"-XX:CompileCommand=option,Test::test,ccstr,MyStrOption,_foo", "-XX:CompileCommand=option,Test::test,ccstr,TestOptionStr,_foo",
"-XX:CompileCommand=option,Test::test,bool,MyBoolOption,false", "-XX:CompileCommand=option,Test::test,bool,TestOptionBool,false",
"-XX:CompileCommand=option,Test::test,intx,MyIntxOption,-1", "-XX:CompileCommand=option,Test::test,intx,TestOptionInt,-1",
"-XX:CompileCommand=option,Test::test,uintx,MyUintxOption,1", "-XX:CompileCommand=option,Test::test,uintx,TestOptionUint,1",
"-XX:CompileCommand=option,Test::test,MyFlag", "-XX:CompileCommand=option,Test::test,TestOptionBool2",
"-XX:CompileCommand=option,Test::test,double,MyDoubleOption1,1.123", "-XX:CompileCommand=option,Test::test,double,TestOptionDouble,1.123",
"-XX:CompileCommand=option,Test.test,double,MyDoubleOption2,1.123", "-XX:CompileCommand=option,Test.test2,double,TestOptionDouble,1.123",
"-XX:CompileCommand=option,Test::test,bool,MyBoolOptionX,false,intx,MyIntxOptionX,-1,uintx,MyUintxOptionX,1,MyFlagX,double,MyDoubleOptionX,1.123",
"-version" "-version"
} }
}; };
private static final String[][] TYPE_2_EXPECTED_OUTPUTS = { private static final String[][] TYPE_2_EXPECTED_OUTPUTS = {
{ {
"CompileCommand: option Test.test const char* MyListOption = '_foo _bar'", "Test.test const char* TestOptionList = '_foo _bar'",
"CompileCommand: option Test.test const char* MyStrOption = '_foo'", "Test.test const char* TestOptionStr = '_foo'",
"CompileCommand: option Test.test bool MyBoolOption = false", "Test.test bool TestOptionBool = false",
"CompileCommand: option Test.test intx MyIntxOption = -1", "Test.test intx TestOptionInt = -1",
"CompileCommand: option Test.test uintx MyUintxOption = 1", "Test.test uintx TestOptionUint = 1",
"CompileCommand: option Test.test bool MyFlag = true", "Test.test bool TestOptionBool2 = true",
"CompileCommand: option Test.test double MyDoubleOption1 = 1.123000", "Test.test double TestOptionDouble = 1.123000",
"CompileCommand: option Test.test double MyDoubleOption2 = 1.123000", "Test.test2 double TestOptionDouble = 1.123000"
"CompileCommand: option Test.test bool MyBoolOptionX = false", }
"CompileCommand: option Test.test intx MyIntxOptionX = -1", };
"CompileCommand: option Test.test uintx MyUintxOptionX = 1",
"CompileCommand: option Test.test bool MyFlagX = true", private static final String[][] TYPE_3_ARGUMENTS = {
"CompileCommand: option Test.test double MyDoubleOptionX = 1.123000", {
"-XX:CompileCommand=option,Test::test,bool,TestOptionBool,false,intx,TestOptionInt,-1,uintx,TestOptionUint,1,TestOptionBool2,double,TestOptionDouble,1.123",
"-version"
}
};
private static final String[][] TYPE_3_EXPECTED_OUTPUTS = {
{
"Test.test bool TestOptionBool = false",
"Test.test intx TestOptionInt = -1",
"Test.test uintx TestOptionUint = 1",
"Test.test bool TestOptionBool2 = true",
"Test.test double TestOptionDouble = 1.123000"
}
};
private static final String[][] TYPE_4_ARGUMENTS = {
{
"-XX:CompileCommand=TestOptionList,Test::test,_foo,_bar",
"-XX:CompileCommand=TestOptionStr,Test::test,_foo",
"-XX:CompileCommand=TestOptionBool,Test::test,false",
"-XX:CompileCommand=TestOptionInt,Test::test,-1",
"-XX:CompileCommand=TestOptionUint,Test::test,1",
"-XX:CompileCommand=TestOptionBool2,Test::test",
"-XX:CompileCommand=TestOptionDouble,Test::test,1.123",
"-XX:CompileCommand=TestOptionDouble,Test.test2,1.123",
"-version"
}
};
private static final String[][] TYPE_4_EXPECTED_OUTPUTS = {
{
"CompileCommand: TestOptionList Test.test const char* TestOptionList = '_foo _bar'",
"CompileCommand: TestOptionStr Test.test const char* TestOptionStr = '_foo'",
"CompileCommand: TestOptionBool Test.test bool TestOptionBool = false",
"CompileCommand: TestOptionInt Test.test intx TestOptionInt = -1",
"CompileCommand: TestOptionUint Test.test uintx TestOptionUint = 1",
"CompileCommand: TestOptionBool2 Test.test bool TestOptionBool2 = true",
"CompileCommand: TestOptionDouble Test.test double TestOptionDouble = 1.123000",
"CompileCommand: TestOptionDouble Test.test2 double TestOptionDouble = 1.123000"
}
};
private static final String[][] TYPE_4_INVALID_ARGUMENTS = {
{
"-XX:CompileCommand=InvalidOption,Test::test,_foo,_bar",
"-XX:CompileCommand=TestOptionInt,Test::test,_foo",
"-XX:CompileCommand=TestOptionBool,Test::test,1",
"-XX:CompileCommand=TestOptionDouble,Test::test,-1",
"-XX:CompileCommand=TestOptionUint,Test::test",
"-XX:CompileCommand=TestOptionBool2,Test::test,falsee",
"-XX:CompileCommand=TestOptionDouble,Test::test,true",
"-XX:CompileCommand=TestOptionDouble,Test.test2,1.f",
"-version"
}
};
private static final String[][] TYPE_4_INVALID_OUTPUTS = {
{
"Unrecognized option 'InvalidOption'",
"Value cannot be read for option 'TestOptionInt' of type 'intx'",
"Value cannot be read for option 'TestOptionBool' of type 'bool'",
"Value cannot be read for option 'TestOptionDouble' of type 'double'",
"Option 'TestOptionUint' is not followed by a value",
"Value cannot be read for option 'TestOptionBool2' of type 'bool'",
"Value cannot be read for option 'TestOptionDouble' of type 'double'",
"Value cannot be read for option 'TestOptionDouble' of type 'double'"
} }
}; };
@ -211,6 +272,23 @@ public class CheckCompileCommandOption {
out.shouldHaveExitValue(0); out.shouldHaveExitValue(0);
} }
private static void verifyInvalidOption(String[] arguments, String[] expected_outputs) throws Exception {
ProcessBuilder pb;
OutputAnalyzer out;
pb = ProcessTools.createJavaProcessBuilder(arguments);
out = new OutputAnalyzer(pb.start());
for (String expected_output : expected_outputs) {
out.shouldContain(expected_output);
}
out.shouldContain("CompileCommand: An error occurred during parsing");
out.shouldHaveExitValue(0);
}
public static void main(String[] args) throws Exception { public static void main(String[] args) throws Exception {
if (TYPE_1_ARGUMENTS.length != TYPE_1_EXPECTED_OUTPUTS.length) { if (TYPE_1_ARGUMENTS.length != TYPE_1_EXPECTED_OUTPUTS.length) {
@ -221,6 +299,14 @@ public class CheckCompileCommandOption {
throw new RuntimeException("Test is set up incorrectly: length of arguments and expected outputs for type (2) options does not match."); throw new RuntimeException("Test is set up incorrectly: length of arguments and expected outputs for type (2) options does not match.");
} }
if (TYPE_3_ARGUMENTS.length != TYPE_3_EXPECTED_OUTPUTS.length) {
throw new RuntimeException("Test is set up incorrectly: length of arguments and expected outputs for type (3) options does not match.");
}
if (TYPE_4_ARGUMENTS.length != TYPE_4_EXPECTED_OUTPUTS.length) {
throw new RuntimeException("Test is set up incorrectly: length of arguments and expected outputs for type (4) options does not match.");
}
// Check if type (1) options are parsed correctly // Check if type (1) options are parsed correctly
for (int i = 0; i < TYPE_1_ARGUMENTS.length; i++) { for (int i = 0; i < TYPE_1_ARGUMENTS.length; i++) {
verifyValidOption(TYPE_1_ARGUMENTS[i], TYPE_1_EXPECTED_OUTPUTS[i]); verifyValidOption(TYPE_1_ARGUMENTS[i], TYPE_1_EXPECTED_OUTPUTS[i]);
@ -231,12 +317,28 @@ public class CheckCompileCommandOption {
verifyValidOption(TYPE_2_ARGUMENTS[i], TYPE_2_EXPECTED_OUTPUTS[i]); verifyValidOption(TYPE_2_ARGUMENTS[i], TYPE_2_EXPECTED_OUTPUTS[i]);
} }
// Check if type (3) options are parsed correctly
for (int i = 0; i < TYPE_3_ARGUMENTS.length; i++) {
verifyValidOption(TYPE_3_ARGUMENTS[i], TYPE_3_EXPECTED_OUTPUTS[i]);
}
// Check if type (4) options are parsed correctly
for (int i = 0; i < TYPE_4_ARGUMENTS.length; i++) {
verifyValidOption(TYPE_4_ARGUMENTS[i], TYPE_4_EXPECTED_OUTPUTS[i]);
}
// Check if error is reported for invalid type (2) options // Check if error is reported for invalid type (2) options
// (flags with type information specified) // (flags with type information specified)
for (String[] arguments: TYPE_2_INVALID_ARGUMENTS) { for (String[] arguments: TYPE_2_INVALID_ARGUMENTS) {
verifyInvalidOption(arguments); verifyInvalidOption(arguments);
} }
// Check if error is reported for invalid type (2) options
// (flags with type information specified)
for (int i = 0; i < TYPE_4_INVALID_ARGUMENTS.length; i++) {
verifyInvalidOption(TYPE_4_INVALID_ARGUMENTS[i], TYPE_4_INVALID_OUTPUTS[i]);
}
// Check if commands in command file are parsed correctly // Check if commands in command file are parsed correctly
for (int i = 0; i < FILE_ARGUMENTS.length; i++) { for (int i = 0; i < FILE_ARGUMENTS.length; i++) {
verifyValidOption(FILE_ARGUMENTS[i], FILE_EXPECTED_OUTPUT[i]); verifyValidOption(FILE_ARGUMENTS[i], FILE_EXPECTED_OUTPUT[i]);

View file

@ -27,17 +27,30 @@
* @library /test/lib * @library /test/lib
* @modules java.base/jdk.internal.misc * @modules java.base/jdk.internal.misc
* @build sun.hotspot.WhiteBox * @build sun.hotspot.WhiteBox
* @requires vm.debug == true
* @run driver ClassFileInstaller sun.hotspot.WhiteBox * @run driver ClassFileInstaller sun.hotspot.WhiteBox
* @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI
* -XX:CompileCommand=option,compiler.oracle.GetMethodOptionTest::test,ccstrlist,MyListOption,_foo,_bar * -XX:CompileCommand=option,compiler.oracle.GetMethodOptionTest::test,ccstrlist,TestOptionList,_foo,_bar
* -XX:CompileCommand=option,compiler.oracle.GetMethodOptionTest::test,ccstr,MyStrOption,_foo * -XX:CompileCommand=option,compiler.oracle.GetMethodOptionTest::test,ccstr,TestOptionStr,_foo
* -XX:CompileCommand=option,compiler.oracle.GetMethodOptionTest::test,bool,MyBoolOption,false * -XX:CompileCommand=option,compiler.oracle.GetMethodOptionTest::test,bool,TestOptionBool,false
* -XX:CompileCommand=option,compiler.oracle.GetMethodOptionTest::test,intx,MyIntxOption,-1 * -XX:CompileCommand=option,compiler.oracle.GetMethodOptionTest::test,intx,TestOptionInt,-1
* -XX:CompileCommand=option,compiler.oracle.GetMethodOptionTest::test,uintx,MyUintxOption,1 * -XX:CompileCommand=option,compiler.oracle.GetMethodOptionTest::test,uintx,TestOptionUint,1
* -XX:CompileCommand=option,compiler.oracle.GetMethodOptionTest::test,MyFlag * -XX:CompileCommand=option,compiler.oracle.GetMethodOptionTest::test,TestOptionBool2
* -XX:CompileCommand=option,compiler.oracle.GetMethodOptionTest::test,double,MyDoubleOption1,1.123 * -XX:CompileCommand=option,compiler.oracle.GetMethodOptionTest::test,double,TestOptionDouble,1.123
* -XX:CompileCommand=option,compiler.oracle.GetMethodOptionTest::test,double,MyDoubleOption2,1.123 * compiler.oracle.GetMethodOptionTest
* -XX:CompileCommand=option,compiler.oracle.GetMethodOptionTest::test,bool,MyBoolOptionX,false,intx,MyIntxOptionX,-1,uintx,MyUintxOptionX,1,MyFlagX,double,MyDoubleOptionX,1.123 *
* @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI
* -XX:CompileCommand=option,compiler.oracle.GetMethodOptionTest::test,bool,TestOptionBool,false,intx,TestOptionInt,-1,uintx,TestOptionUint,1,bool,TestOptionBool2,true,ccstr,TestOptionStr,_foo,double,TestOptionDouble,1.123,ccstrlist,TestOptionList,_foo,_bar
* compiler.oracle.GetMethodOptionTest
*
* @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI
* -XX:CompileCommand=TestOptionList,compiler.oracle.GetMethodOptionTest::test,_foo,_bar
* -XX:CompileCommand=TestOptionStr,compiler.oracle.GetMethodOptionTest::test,_foo
* -XX:CompileCommand=TestOptionBool,compiler.oracle.GetMethodOptionTest::test,false
-XX:CompileCommand=TestOptionBool2,compiler.oracle.GetMethodOptionTest::test
* -XX:CompileCommand=TestOptionInt,compiler.oracle.GetMethodOptionTest::test,-1
* -XX:CompileCommand=TestOptionUint,compiler.oracle.GetMethodOptionTest::test,1
* -XX:CompileCommand=TestOptionDouble,compiler.oracle.GetMethodOptionTest::test,1.123
* compiler.oracle.GetMethodOptionTest * compiler.oracle.GetMethodOptionTest
*/ */
@ -72,19 +85,13 @@ public class GetMethodOptionTest {
private static void test2() { } private static void test2() { }
private static enum TestCase { private static enum TestCase {
MyListOption("_foo _bar", WB::getMethodStringOption), TestOptionBool(false, WB::getMethodBooleanOption),
MyStrOption("_foo", WB::getMethodStringOption), TestOptionStr("_foo", WB::getMethodStringOption),
MyBoolOption(false, WB::getMethodBooleanOption), TestOptionInt(-1L, WB::getMethodIntxOption),
MyIntxOption(-1L, WB::getMethodIntxOption), TestOptionUint(1L, WB::getMethodUintxOption),
MyUintxOption(1L, WB::getMethodUintxOption), TestOptionBool2(true, WB::getMethodBooleanOption),
MyFlag(true, WB::getMethodBooleanOption), TestOptionDouble(1.123d, WB::getMethodDoubleOption),
MyDoubleOption1(1.123d, WB::getMethodDoubleOption), TestOptionList("_foo _bar", WB::getMethodStringOption);
MyDoubleOption2(1.123d, WB::getMethodDoubleOption),
MyBoolOptionX(false, WB::getMethodBooleanOption),
MyIntxOptionX(-1L, WB::getMethodIntxOption),
MyUintxOptionX(1L, WB::getMethodUintxOption),
MyFlagX(true, WB::getMethodBooleanOption),
MyDoubleOptionX(1.123d, WB::getMethodDoubleOption);
public final Object value; public final Object value;
public final BiFunction<Executable, String, Object> getter; public final BiFunction<Executable, String, Object> getter;

View file

@ -1,10 +1,10 @@
option,com/oracle/Test.test,MyBoolOption1 option,com/oracle/Test.test1,TestOptionBool
option,com/oracle/Test,test,MyBoolOption2 option,com/oracle/Test,test2,TestOptionBool
option,com.oracle.Test::test,MyBoolOption3 option,com.oracle.Test::test3,TestOptionBool
option,com/oracle/Test.test,MyBoolOption5,MyBoolOption6 option,com/oracle/Test.test4,TestOptionBool,TestOptionBool2
option,com/oracle/Test,test,MyBoolOption7,MyBoolOption8 option,com/oracle/Test,test5,TestOptionBool,TestOptionBool2
option,com/oracle/Test.test(I),MyBoolOption9 option,com/oracle/Test.test6(I),TestOptionBool
option,com/oracle/Test,test,(I),MyBoolOption10 option,com/oracle/Test,test7,(I),TestOptionBool
option,com.oracle.Test::test(I),MyBoolOption11 option,com.oracle.Test::test8(I),TestOptionBool
option,com/oracle/Test.test(I),MyBoolOption13,MyBoolOption14 option,com/oracle/Test.test9(I),TestOptionBool,TestOptionBool2
option,com/oracle/Test,test(I),MyBoolOption15,MyBoolOption16 option,com/oracle/Test,test10(I),TestOptionBool,TestOptionBool2

View file

@ -1,7 +1,7 @@
option,Test::test,ccstrlist,MyListOption,_foo,_bar option,Test::test,ccstrlist,TestOptionList,_foo,_bar
option,Test::test,ccstr,MyStrOption,_foo option,Test::test,ccstr,TestOptionStr,_foo
option,Test::test,bool,MyBoolOption,false option,Test::test,bool,TestOptionBool,false
option,Test::test,intx,MyIntxOption,-1 option,Test::test,intx,TestOptionInt,-1
option,Test::test,uintx,MyUintxOption,1 option,Test::test,uintx,TestOptionUint,1
option,Test::test,MyFlag option,Test::test,TestOptionBool2
option,Test::test,double,MyDoubleOption,1.123 option,Test::test,double,TestOptionDouble,1.123

View file

@ -48,7 +48,8 @@ public class CompilerConfigFileWarning {
pb = ProcessTools.createJavaProcessBuilder("-XX:CompileCommandFile=hs_comp.txt", "-version"); pb = ProcessTools.createJavaProcessBuilder("-XX:CompileCommandFile=hs_comp.txt", "-version");
output = new OutputAnalyzer(pb.start()); output = new OutputAnalyzer(pb.start());
output.shouldContain("CompileCommand: unrecognized command"); output.shouldContain("An error occurred during parsing");
output.shouldContain("Unrecognized option 'aaa'");
output.shouldContain("aaa, aaa"); output.shouldContain("aaa, aaa");
// Skip on debug builds since we'll always read the file there // Skip on debug builds since we'll always read the file there