8137167: JEP165: Compiler Control: Implementation task

Compiler Control JEP

Reviewed-by: roland, twisti, zmajo, simonis
This commit is contained in:
Nils Eliasson 2015-10-20 18:07:28 +02:00
parent 857b7eb968
commit 5a5faf94bf
66 changed files with 3965 additions and 307 deletions

View File

@ -34,6 +34,7 @@
#include "c1/c1_ValueStack.hpp"
#include "code/debugInfoRec.hpp"
#include "compiler/compileLog.hpp"
#include "compiler/compilerDirectives.hpp"
#include "runtime/sharedRuntime.hpp"
typedef enum {
@ -418,9 +419,9 @@ void Compilation::install_code(int frame_size) {
exception_handler_table(),
implicit_exception_table(),
compiler(),
_env->comp_level(),
has_unsafe_access(),
SharedRuntime::is_wide_vector(max_vector_size())
SharedRuntime::is_wide_vector(max_vector_size()),
directive()
);
}
@ -445,7 +446,7 @@ void Compilation::compile_method() {
dependency_recorder()->assert_evol_method(method());
}
if (method()->break_at_execute()) {
if (directive()->BreakAtCompileOption) {
BREAKPOINT;
}
@ -534,9 +535,10 @@ void Compilation::generate_exception_handler_table() {
Compilation::Compilation(AbstractCompiler* compiler, ciEnv* env, ciMethod* method,
int osr_bci, BufferBlob* buffer_blob)
int osr_bci, BufferBlob* buffer_blob, DirectiveSet* directive)
: _compiler(compiler)
, _env(env)
, _directive(directive)
, _log(env->log())
, _method(method)
, _osr_bci(osr_bci)
@ -587,7 +589,6 @@ Compilation::~Compilation() {
_env->set_compiler_data(NULL);
}
void Compilation::add_exception_handlers_for_pco(int pco, XHandlers* exception_handlers) {
#ifndef PRODUCT
if (PrintExceptionHandlers && Verbose) {

View File

@ -67,6 +67,7 @@ class Compilation: public StackObj {
int _next_id;
int _next_block_id;
AbstractCompiler* _compiler;
DirectiveSet* _directive;
ciEnv* _env;
CompileLog* _log;
ciMethod* _method;
@ -118,7 +119,7 @@ class Compilation: public StackObj {
public:
// creation
Compilation(AbstractCompiler* compiler, ciEnv* env, ciMethod* method,
int osr_bci, BufferBlob* buffer_blob);
int osr_bci, BufferBlob* buffer_blob, DirectiveSet* directive);
~Compilation();
@ -128,6 +129,7 @@ class Compilation: public StackObj {
// accessors
ciEnv* env() const { return _env; }
DirectiveSet* directive() const { return _directive; }
CompileLog* log() const { return _log; }
AbstractCompiler* compiler() const { return _compiler; }
bool has_exception_handlers() const { return _has_exception_handlers; }

View File

@ -238,7 +238,7 @@ bool Compiler::is_intrinsic_supported(methodHandle method) {
return true;
}
void Compiler::compile_method(ciEnv* env, ciMethod* method, int entry_bci) {
void Compiler::compile_method(ciEnv* env, ciMethod* method, int entry_bci, DirectiveSet* directive) {
BufferBlob* buffer_blob = CompilerThread::current()->get_buffer_blob();
assert(buffer_blob != NULL, "Must exist");
// invoke compilation
@ -247,7 +247,7 @@ void Compiler::compile_method(ciEnv* env, ciMethod* method, int entry_bci) {
// of Compilation to occur before we release the any
// competing compiler thread
ResourceMark rm;
Compilation c(this, env, method, entry_bci, buffer_blob);
Compilation c(this, env, method, entry_bci, buffer_blob, directive);
}
}

View File

@ -26,6 +26,7 @@
#define SHARE_VM_C1_C1_COMPILER_HPP
#include "compiler/abstractCompiler.hpp"
#include "compiler/compilerDirectives.hpp"
// There is one instance of the Compiler per CompilerThread.
@ -50,7 +51,7 @@ class Compiler: public AbstractCompiler {
virtual void initialize();
// Compilation entry point for methods
virtual void compile_method(ciEnv* env, ciMethod* target, int entry_bci);
virtual void compile_method(ciEnv* env, ciMethod* target, int entry_bci, DirectiveSet* directive);
// Print compilation timers and statistics
virtual void print_timers();

View File

@ -3365,7 +3365,7 @@ const char* GraphBuilder::check_can_parse(ciMethod* callee) const {
// negative filter: should callee NOT be inlined? returns NULL, ok to inline, or rejection msg
const char* GraphBuilder::should_not_inline(ciMethod* callee) const {
if ( callee->should_not_inline()) return "disallowed by CompileCommand";
if ( compilation()->directive()->should_not_inline(callee)) return "disallowed by CompileCommand";
if ( callee->dont_inline()) return "don't inline by annotation";
return NULL;
}
@ -3494,8 +3494,7 @@ bool GraphBuilder::try_inline_intrinsics(ciMethod* callee) {
{
VM_ENTRY_MARK;
methodHandle mh(THREAD, callee->get_Method());
methodHandle ct(THREAD, method()->get_Method());
is_available = _compilation->compiler()->is_intrinsic_available(mh, ct);
is_available = _compilation->compiler()->is_intrinsic_available(mh, _compilation->directive());
}
if (!is_available) {
@ -3690,13 +3689,14 @@ bool GraphBuilder::try_inline_full(ciMethod* callee, bool holder_known, Bytecode
}
// now perform tests that are based on flag settings
if (callee->force_inline() || callee->should_inline()) {
bool inlinee_by_directive = compilation()->directive()->should_inline(callee);
if (callee->force_inline() || inlinee_by_directive) {
if (inline_level() > MaxForceInlineLevel ) INLINE_BAILOUT("MaxForceInlineLevel");
if (recursive_inline_level(callee) > MaxRecursiveInlineLevel) INLINE_BAILOUT("recursive inlining too deep");
const char* msg = "";
if (callee->force_inline()) msg = "force inline by annotation";
if (callee->should_inline()) msg = "force inline by CompileCommand";
if (inlinee_by_directive) msg = "force inline by CompileCommand";
print_inlining(callee, msg);
} else {
// use heuristic controls on inlining
@ -4207,7 +4207,8 @@ void GraphBuilder::print_inlining(ciMethod* callee, const char* msg, bool succes
event.commit();
}
#endif // INCLUDE_TRACE
if (!PrintInlining && !compilation()->method()->has_option("PrintInlining")) {
if (!compilation()->directive()->PrintInliningOption) {
return;
}
CompileTask::print_inlining_tty(callee, scope()->level(), bci(), msg);

View File

@ -38,7 +38,8 @@
#include "code/scopeDesc.hpp"
#include "compiler/compileBroker.hpp"
#include "compiler/compileLog.hpp"
#include "compiler/compilerOracle.hpp"
#include "compiler/compilerDirectives.hpp"
#include "compiler/disassembler.hpp"
#include "gc/shared/collectedHeap.inline.hpp"
#include "interpreter/linkResolver.hpp"
#include "memory/allocation.inline.hpp"
@ -956,9 +957,9 @@ void ciEnv::register_method(ciMethod* target,
ExceptionHandlerTable* handler_table,
ImplicitExceptionTable* inc_table,
AbstractCompiler* compiler,
int comp_level,
bool has_unsafe_access,
bool has_wide_vectors,
DirectiveSet* directives,
RTMState rtm_state) {
VM_ENTRY_MARK;
nmethod* nm = NULL;
@ -1034,11 +1035,20 @@ void ciEnv::register_method(ciMethod* target,
debug_info(), dependencies(), code_buffer,
frame_words, oop_map_set,
handler_table, inc_table,
compiler, comp_level);
compiler, task()->comp_level());
// Free codeBlobs
code_buffer->free_blob();
if (nm != NULL) {
bool printnmethods = directives->PrintAssemblyOption || directives->PrintNMethodsOption;
if (printnmethods || PrintDebugInfo || PrintRelocations || PrintDependencies || PrintExceptionHandlers) {
nm->print_nmethod(printnmethods);
}
if (directives->PrintAssemblyOption) {
Disassembler::decode(nm);
}
nm->set_has_unsafe_access(has_unsafe_access);
nm->set_has_wide_vectors(has_wide_vectors);
#if INCLUDE_RTM_OPT
@ -1069,7 +1079,7 @@ void ciEnv::register_method(ciMethod* target,
char *method_name = method->name_and_sig_as_C_string();
ttyLocker ttyl;
tty->print_cr("Installing method (%d) %s ",
comp_level,
task()->comp_level(),
method_name);
}
// Allow the code to be executed
@ -1080,7 +1090,7 @@ void ciEnv::register_method(ciMethod* target,
char *method_name = method->name_and_sig_as_C_string();
ttyLocker ttyl;
tty->print_cr("Installing osr method (%d) %s @ %d",
comp_level,
task()->comp_level(),
method_name,
entry_bci);
}

View File

@ -32,9 +32,11 @@
#include "code/dependencies.hpp"
#include "code/exceptionHandlerTable.hpp"
#include "compiler/oopMap.hpp"
#include "compiler/compilerDirectives.hpp"
#include "runtime/thread.hpp"
class CompileTask;
class DirectiveSet;
// ciEnv
//
@ -352,6 +354,7 @@ public:
// The compiler task which has created this env.
// May be useful to find out compile_id, comp_level, etc.
CompileTask* task() { return _task; }
// Handy forwards to the task:
int comp_level(); // task()->comp_level()
uint compile_id(); // task()->compile_id()
@ -367,9 +370,9 @@ public:
ExceptionHandlerTable* handler_table,
ImplicitExceptionTable* inc_table,
AbstractCompiler* compiler,
int comp_level,
bool has_unsafe_access,
bool has_wide_vectors,
DirectiveSet* directives,
RTMState rtm_state = NoRTM);

View File

@ -35,7 +35,6 @@
#include "ci/ciUtilities.hpp"
#include "classfile/systemDictionary.hpp"
#include "compiler/abstractCompiler.hpp"
#include "compiler/compilerOracle.hpp"
#include "compiler/methodLiveness.hpp"
#include "interpreter/interpreter.hpp"
#include "interpreter/linkResolver.hpp"
@ -1043,51 +1042,6 @@ MethodCounters* ciMethod::ensure_method_counters() {
return method_counters;
}
// ------------------------------------------------------------------
// ciMethod::should_inline
//
// Should this method be inlined during compilation?
bool ciMethod::should_inline() {
check_is_loaded();
VM_ENTRY_MARK;
methodHandle mh(THREAD, get_Method());
return CompilerOracle::should_inline(mh);
}
// ------------------------------------------------------------------
// ciMethod::should_not_inline
//
// Should this method be disallowed from inlining during compilation?
bool ciMethod::should_not_inline() {
check_is_loaded();
VM_ENTRY_MARK;
methodHandle mh(THREAD, get_Method());
return CompilerOracle::should_not_inline(mh);
}
// ------------------------------------------------------------------
// ciMethod::should_print_assembly
//
// Should the compiler print the generated code for this method?
bool ciMethod::should_print_assembly() {
check_is_loaded();
VM_ENTRY_MARK;
methodHandle mh(THREAD, get_Method());
return CompilerOracle::should_print(mh);
}
// ------------------------------------------------------------------
// ciMethod::break_at_execute
//
// Should the compiler insert a breakpoint into the generated code
// method?
bool ciMethod::break_at_execute() {
check_is_loaded();
VM_ENTRY_MARK;
methodHandle mh(THREAD, get_Method());
return CompilerOracle::should_break_at(mh);
}
// ------------------------------------------------------------------
// ciMethod::has_option
//
@ -1101,20 +1055,12 @@ bool ciMethod::has_option(const char* option) {
// ------------------------------------------------------------------
// ciMethod::has_option_value
//
template<typename T>
bool ciMethod::has_option_value(const char* option, T& value) {
bool ciMethod::has_option_value(const char* option, double& value) {
check_is_loaded();
VM_ENTRY_MARK;
methodHandle mh(THREAD, get_Method());
return CompilerOracle::has_option_value(mh, option, value);
}
// Explicit instantiation for all OptionTypes supported.
template bool ciMethod::has_option_value<intx>(const char* option, intx& value);
template bool ciMethod::has_option_value<uintx>(const char* option, uintx& value);
template bool ciMethod::has_option_value<bool>(const char* option, bool& value);
template bool ciMethod::has_option_value<ccstr>(const char* option, ccstr& value);
template bool ciMethod::has_option_value<double>(const char* option, double& value);
// ------------------------------------------------------------------
// ciMethod::can_be_compiled
//

View File

@ -104,8 +104,6 @@ class ciMethod : public ciMetadata {
void load_code();
void check_is_loaded() const { assert(is_loaded(), "not loaded"); }
bool ensure_method_data(methodHandle h_m);
void code_at_put(int bci, Bytecodes::Code code) {
@ -120,6 +118,8 @@ class ciMethod : public ciMetadata {
void assert_call_type_ok(int bci);
public:
void check_is_loaded() const { assert(is_loaded(), "not loaded"); }
// Basic method information.
ciFlags flags() const { check_is_loaded(); return _flags; }
ciSymbol* name() const { return _name; }
@ -265,14 +265,8 @@ class ciMethod : public ciMetadata {
// Find the proper vtable index to invoke this method.
int resolve_vtable_index(ciKlass* caller, ciKlass* receiver);
// Compilation directives
bool should_inline();
bool should_not_inline();
bool should_print_assembly();
bool break_at_execute();
bool has_option(const char *option);
template<typename T>
bool has_option_value(const char* option, T& value);
bool has_option_value(const char* option, double& value);
bool can_be_compiled();
bool can_be_osr_compiled(int entry_bci);
void set_not_compilable(const char* reason = NULL);

View File

@ -417,36 +417,10 @@ int vmIntrinsics::predicates_needed(vmIntrinsics::ID id) {
}
}
bool vmIntrinsics::is_disabled_by_flags(methodHandle method, methodHandle compilation_context) {
bool vmIntrinsics::is_disabled_by_flags(methodHandle method) {
vmIntrinsics::ID id = method->intrinsic_id();
assert(id != vmIntrinsics::_none, "must be a VM intrinsic");
// Check if the intrinsic corresponding to 'method' has been disabled on
// the command line by using the DisableIntrinsic flag (either globally
// or on a per-method level, see src/share/vm/compiler/abstractCompiler.hpp
// for details).
// Usually, the compilation context is the caller of the method 'method'.
// The only case when for a non-recursive method 'method' the compilation context
// is not the caller of the 'method' (but it is the method itself) is
// java.lang.ref.Referene::get.
// For java.lang.ref.Reference::get, the intrinsic version is used
// instead of the compiled version so that the value in the referent
// field can be registered by the G1 pre-barrier code. The intrinsified
// version of Reference::get also adds a memory barrier to prevent
// commoning reads from the referent field across safepoint since GC
// can change the referent field's value. See Compile::Compile()
// in src/share/vm/opto/compile.cpp or
// GraphBuilder::GraphBuilder() in src/share/vm/c1/c1_GraphBuilder.cpp
// for more details.
ccstr disable_intr = NULL;
if ((DisableIntrinsic[0] != '\0' && strstr(DisableIntrinsic, vmIntrinsics::name_at(id)) != NULL) ||
(!compilation_context.is_null() &&
CompilerOracle::has_option_value(compilation_context, "DisableIntrinsic", disable_intr) &&
strstr(disable_intr, vmIntrinsics::name_at(id)) != NULL)
) {
return true;
}
// -XX:-InlineNatives disables nearly all intrinsics except the ones listed in
// the following switch statement.
if (!InlineNatives) {

View File

@ -1402,7 +1402,7 @@ public:
// Returns true if a compiler intrinsic is disabled by command-line flags
// and false otherwise.
static bool is_disabled_by_flags(methodHandle method, methodHandle compilation_context);
static bool is_disabled_by_flags(methodHandle method);
};
#endif // SHARE_VM_CLASSFILE_VMSYMBOLS_HPP

View File

@ -32,7 +32,7 @@
#include "compiler/abstractCompiler.hpp"
#include "compiler/compileBroker.hpp"
#include "compiler/compileLog.hpp"
#include "compiler/compilerOracle.hpp"
#include "compiler/compilerDirectives.hpp"
#include "compiler/disassembler.hpp"
#include "interpreter/bytecode.hpp"
#include "oops/methodData.hpp"
@ -582,9 +582,6 @@ nmethod* nmethod::new_native_nmethod(methodHandle method,
basic_lock_owner_sp_offset,
basic_lock_sp_offset, oop_maps);
NOT_PRODUCT(if (nm != NULL) native_nmethod_stats.note_native_nmethod(nm));
if ((PrintAssembly || CompilerOracle::should_print(method)) && nm != NULL) {
Disassembler::decode(nm);
}
}
// verify nmethod
debug_only(if (nm) nm->verify();) // might block
@ -666,9 +663,6 @@ nmethod* nmethod::new_nmethod(methodHandle method,
}
}
NOT_PRODUCT(if (nm != NULL) note_java_nmethod(nm));
if (PrintAssembly || CompilerOracle::has_option_string(method, "PrintAssembly")) {
Disassembler::decode(nm);
}
}
}
// Do verification and logging outside CodeCache_lock.
@ -908,13 +902,6 @@ nmethod::nmethod(
_method->is_static() == (entry_point() == _verified_entry_point),
" entry points must be same for static methods and vice versa");
}
bool printnmethods = PrintNMethods || PrintNMethodsAtLevel == _comp_level
|| CompilerOracle::should_print(_method)
|| CompilerOracle::has_option_string(_method, "PrintNMethods");
if (printnmethods || PrintDebugInfo || PrintRelocations || PrintDependencies || PrintExceptionHandlers) {
print_nmethod(printnmethods);
}
}
// Print a short set of xml attributes to identify this nmethod. The

View File

@ -26,6 +26,7 @@
#define SHARE_VM_COMPILER_ABSTRACTCOMPILER_HPP
#include "ci/compilerInterface.hpp"
#include "compiler/compilerDirectives.hpp"
typedef void (*initializer)(void);
@ -114,36 +115,33 @@ class AbstractCompiler : public CHeapObj<mtCompiler> {
// Determine if the current compiler provides an intrinsic
// for method 'method'. An intrinsic is available if:
// - the intrinsic is enabled (by using the appropriate command-line flag) and
// - the intrinsic is enabled (by using the appropriate command-line flag,
// the command-line compile ommand, or a compiler directive)
// - the platform on which the VM is running supports the intrinsic
// (i.e., the platform provides the instructions necessary for the compiler
// to generate the intrinsic code).
//
// The second parameter, 'compilation_context', is needed to implement functionality
// related to the DisableIntrinsic command-line flag. The DisableIntrinsic flag can
// be used to prohibit the compilers to use an intrinsic. There are three ways to
// disable an intrinsic using the DisableIntrinsic flag:
// The directive provides the compilation context and includes pre-evaluated values
// dependent on VM flags, compile commands, and compiler directives.
//
// (1) -XX:DisableIntrinsic=_hashCode,_getClass
// Disables intrinsification of _hashCode and _getClass globally
// (i.e., the intrinsified version the methods will not be used at all).
// (2) -XX:CompileCommand=option,aClass::aMethod,ccstr,DisableIntrinsic,_hashCode
// Disables intrinsification of _hashCode if it is called from
// aClass::aMethod (but not for any other call site of _hashCode)
// (3) -XX:CompileCommand=option,java.lang.ref.Reference::get,ccstr,DisableIntrinsic,_Reference_get
// Some methods are not compiled by C2. Instead, the C2 compiler
// returns directly the intrinsified version of these methods.
// The command above forces C2 to compile _Reference_get, but
// allows using the intrinsified version of _Reference_get at all
// other call sites.
//
// From the modes above, (1) disable intrinsics globally, (2) and (3)
// disable intrinsics on a per-method basis. In cases (2) and (3) the
// compilation context is aClass::aMethod and java.lang.ref.Reference::get,
// respectively.
virtual bool is_intrinsic_available(methodHandle method, methodHandle compilation_context) {
// Usually, the compilation context is the caller of the method 'method'.
// The only case when for a non-recursive method 'method' the compilation context
// is not the caller of the 'method' (but it is the method itself) is
// java.lang.ref.Referene::get.
// For java.lang.ref.Reference::get, the intrinsic version is used
// instead of the compiled version so that the value in the referent
// field can be registered by the G1 pre-barrier code. The intrinsified
// version of Reference::get also adds a memory barrier to prevent
// commoning reads from the referent field across safepoint since GC
// can change the referent field's value. See Compile::Compile()
// in src/share/vm/opto/compile.cpp or
// GraphBuilder::GraphBuilder() in src/share/vm/c1/c1_GraphBuilder.cpp
// for more details.
virtual bool is_intrinsic_available(methodHandle method, DirectiveSet* directive) {
return is_intrinsic_supported(method) &&
!vmIntrinsics::is_disabled_by_flags(method, compilation_context);
!directive->is_intrinsic_disabled(method) &&
!vmIntrinsics::is_disabled_by_flags(method);
}
// Determines if an intrinsic is supported by the compiler, that is,
@ -176,7 +174,7 @@ class AbstractCompiler : public CHeapObj<mtCompiler> {
void set_state (int state);
void set_shut_down () { set_state(shut_down); }
// Compilation entry point for methods
virtual void compile_method(ciEnv* env, ciMethod* target, int entry_bci) {
virtual void compile_method(ciEnv* env, ciMethod* target, int entry_bci, DirectiveSet* directive) {
ShouldNotReachHere();
}

View File

@ -29,6 +29,7 @@
#include "compiler/compileBroker.hpp"
#include "compiler/compileLog.hpp"
#include "compiler/compilerOracle.hpp"
#include "compiler/directivesParser.hpp"
#include "interpreter/linkResolver.hpp"
#include "memory/allocation.inline.hpp"
#include "oops/methodData.hpp"
@ -202,10 +203,22 @@ class CompilationLog : public StringEventLog {
static CompilationLog* _compilation_log = NULL;
void compileBroker_init() {
bool compileBroker_init() {
if (LogEvents) {
_compilation_log = new CompilationLog();
}
// init directives stack, adding default directive
DirectivesStack::init();
if (DirectivesParser::has_file()) {
return DirectivesParser::parse_from_flag();
} else if (PrintCompilerDirectives) {
// Print default directive even when no other was added
DirectivesStack::print(tty);
}
return true;
}
CompileTaskWrapper::CompileTaskWrapper(CompileTask* task) {
@ -1180,11 +1193,15 @@ bool CompileBroker::compilation_is_prohibited(methodHandle method, int osr_bci,
return true;
}
// Breaking the abstraction - directives are only used inside a compilation otherwise.
DirectiveSet* directive = DirectivesStack::getMatchingDirective(method, comp);
bool excluded = directive->ExcludeOption;
DirectivesStack::release(directive);
// The method may be explicitly excluded by the user.
bool quietly;
double scale;
if (CompilerOracle::should_exclude(method, quietly)
|| (CompilerOracle::has_option_value(method, "CompileThresholdScaling", scale) && scale == 0)) {
if (excluded || (CompilerOracle::has_option_value(method, "CompileThresholdScaling", scale) && scale == 0)) {
bool quietly = CompilerOracle::should_exclude_quietly();
if (!quietly) {
// This does not happen quietly...
ResourceMark rm;
@ -1194,7 +1211,7 @@ bool CompileBroker::compilation_is_prohibited(methodHandle method, int osr_bci,
method->print_short_name(tty);
tty->cr();
}
method->set_not_compilable(CompLevel_all, !quietly, "excluded by CompileCommand");
method->set_not_compilable(comp_level, !quietly, "excluded by CompileCommand");
}
return false;
@ -1357,7 +1374,6 @@ bool CompileBroker::init_compiler_runtime() {
ThreadInVMfromNative tv(thread);
ResetNoHandleMark rnhm;
if (!comp->is_shark()) {
// Perform per-thread and global initializations
comp->initialize();
@ -1629,6 +1645,10 @@ void CompileBroker::post_compile(CompilerThread* thread, CompileTask* task, Even
}
}
int DirectivesStack::_depth = 0;
CompilerDirectives* DirectivesStack::_top = NULL;
CompilerDirectives* DirectivesStack::_bottom = NULL;
// ------------------------------------------------------------------
// CompileBroker::invoke_compiler_on_method
//
@ -1655,16 +1675,20 @@ void CompileBroker::invoke_compiler_on_method(CompileTask* task) {
bool should_log = (thread->log() != NULL);
bool should_break = false;
int task_level = task->comp_level();
// Look up matching directives
DirectiveSet* directive = DirectivesStack::getMatchingDirective(task->method(), compiler(task_level));
should_break = directive->BreakAtExecuteOption || task->check_break_at_flags();
if (should_log && !directive->LogOption) {
should_log = false;
}
{
// create the handle inside it's own block so it can't
// accidentally be referenced once the thread transitions to
// native. The NoHandleMark before the transition should catch
// any cases where this occurs in the future.
methodHandle method(thread, task->method());
should_break = check_break_at(method, compile_id, is_osr);
if (should_log && !CompilerOracle::should_log(method)) {
should_log = false;
}
assert(!method->is_native(), "no longer compile natives");
// Save information about this method in case of failure.
@ -1732,7 +1756,7 @@ void CompileBroker::invoke_compiler_on_method(CompileTask* task) {
locker.wait(Mutex::_no_safepoint_check_flag);
}
}
comp->compile_method(&ci_env, target, osr_bci);
comp->compile_method(&ci_env, target, osr_bci, directive);
}
if (!ci_env.failing() && task->code() == NULL) {
@ -1762,6 +1786,7 @@ void CompileBroker::invoke_compiler_on_method(CompileTask* task) {
post_compile(thread, task, event, !ci_env.failing(), &ci_env);
}
DirectivesStack::release(directive);
pop_jni_handle_block();
methodHandle method(thread, task->method());
@ -1947,21 +1972,6 @@ void CompileBroker::pop_jni_handle_block() {
JNIHandleBlock::release_block(compile_handles, thread); // may block
}
// ------------------------------------------------------------------
// CompileBroker::check_break_at
//
// Should the compilation break at the current compilation.
bool CompileBroker::check_break_at(methodHandle method, int compile_id, bool is_osr) {
if (CICountOSR && is_osr && (compile_id == CIBreakAtOSR)) {
return true;
} else if( CompilerOracle::should_break_at(method) ) { // break when compiling
return true;
} else {
return (compile_id == CIBreakAt);
}
}
// ------------------------------------------------------------------
// CompileBroker::collect_statistics
//
@ -2232,3 +2242,4 @@ void CompileBroker::print_compiler_threads_on(outputStream* st) {
st->cr();
#endif
}

View File

@ -28,8 +28,10 @@
#include "ci/compilerInterface.hpp"
#include "compiler/abstractCompiler.hpp"
#include "compiler/compileTask.hpp"
#include "compiler/compilerDirectives.hpp"
#include "runtime/perfData.hpp"
#include "trace/tracing.hpp"
#include "utilities/stack.hpp"
class nmethod;
class nmethodLocker;
@ -129,13 +131,12 @@ public:
~CompileTaskWrapper();
};
// Compilation
//
// The broker for all compilation requests.
class CompileBroker: AllStatic {
friend class Threads;
friend class CompileTaskWrapper;
friend class CompileTaskWrapper;
public:
enum {
@ -238,7 +239,6 @@ class CompileBroker: AllStatic {
static void set_last_compile(CompilerThread *thread, methodHandle method, bool is_osr, int comp_level);
static void push_jni_handle_block();
static void pop_jni_handle_block();
static bool check_break_at(methodHandle method, int compile_id, bool is_osr);
static void collect_statistics(CompilerThread* thread, elapsedTimer time, CompileTask* task);
static void compile_method_base(methodHandle method,
@ -253,7 +253,11 @@ class CompileBroker: AllStatic {
static bool init_compiler_runtime();
static void shutdown_compiler_runtime(AbstractCompiler* comp, CompilerThread* thread);
public:
public:
static DirectivesStack* dirstack();
static void set_dirstack(DirectivesStack* stack);
enum {
// The entry bci used for non-OSR compilations.
standard_entry_bci = InvocationEntryBci
@ -267,6 +271,7 @@ class CompileBroker: AllStatic {
static bool compilation_is_in_queue(methodHandle method);
static void print_compile_queues(outputStream* st);
static void print_directives(outputStream* st);
static int queue_size(int comp_level) {
CompileQueue *q = compile_queue(comp_level);
return q != NULL ? q->size() : 0;

View File

@ -26,6 +26,7 @@
#include "compiler/compileTask.hpp"
#include "compiler/compileLog.hpp"
#include "compiler/compileBroker.hpp"
#include "compiler/compilerDirectives.hpp"
CompileTask* CompileTask::_task_free_list = NULL;
#ifdef ASSERT
@ -371,6 +372,19 @@ void CompileTask::log_task_done(CompileLog* log) {
log->mark_file_end();
}
// ------------------------------------------------------------------
// CompileTask::check_break_at_flags
bool CompileTask::check_break_at_flags() {
int compile_id = this->_compile_id;
bool is_osr = (_osr_bci != CompileBroker::standard_entry_bci);
if (CICountOSR && is_osr && (compile_id == CIBreakAtOSR)) {
return true;
} else {
return (compile_id == CIBreakAt);
}
}
// ------------------------------------------------------------------
// CompileTask::print_inlining
void CompileTask::print_inlining_inner(outputStream* st, ciMethod* method, int inline_level, int bci, const char* msg) {

View File

@ -0,0 +1,502 @@
/*
* Copyright (c) 1998, 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
#include "precompiled.hpp"
#include "ci/ciMethod.hpp"
#include "ci/ciUtilities.hpp"
#include "compiler/abstractCompiler.hpp"
#include "compiler/compilerDirectives.hpp"
#include "compiler/compilerOracle.hpp"
CompilerDirectives::CompilerDirectives() :_match(NULL), _next(NULL), _ref_count(0) {
_c1_store = new DirectiveSet(this);
_c2_store = new DirectiveSet(this);
};
CompilerDirectives::~CompilerDirectives() {
if (_c1_store != NULL) {
delete _c1_store;
}
if (_c2_store != NULL) {
delete _c2_store;
}
// remove all linked method matchers
BasicMatcher* tmp = _match;
while (tmp != NULL) {
BasicMatcher* next = tmp->next();
delete tmp;
tmp = next;
}
}
void CompilerDirectives::print(outputStream* st) {
assert(DirectivesStack_lock->owned_by_self(), "");
if (_match != NULL) {
st->cr();
st->print("Directive:");
if (is_default_directive()) {
st->print_cr(" (default)");
} else {
st->cr();
}
st->print(" matching: ");
_match->print(st);
BasicMatcher* tmp = _match->next();
while (tmp != NULL) {
st->print(", ");
tmp->print(st);
tmp = tmp->next();
}
st->cr();
} else {
assert(0, "There should always be a match");
}
if (_c1_store != NULL) {
st->print_cr(" c1 directives:");
_c1_store->print(st);
}
if (_c2_store != NULL) {
st->cr();
st->print_cr(" c2 directives:");
_c2_store->print(st);
}
//---
}
void CompilerDirectives::finalize() {
if (_c1_store != NULL) {
_c1_store->finalize();
}
if (_c2_store != NULL) {
_c2_store->finalize();
}
}
void DirectiveSet::finalize() {
// if any flag has been modified - set directive as enabled
// unless it already has been explicitly set.
if (!_modified[EnableIndex]) {
if (_inlinematchers != NULL) {
EnableOption = true;
return;
}
int i;
for (i = 0; i < number_of_flags; i++) {
if (_modified[i]) {
EnableOption = true;
return;
}
}
}
}
CompilerDirectives* CompilerDirectives::next() {
return _next;
}
bool CompilerDirectives::match(methodHandle method) {
if (is_default_directive()) {
return true;
}
if (method == NULL) {
return false;
}
if (_match->match(method)) {
return true;
}
return false;
}
bool CompilerDirectives::add_match(char* str, const char*& error_msg) {
BasicMatcher* bm = BasicMatcher::parse_method_pattern(str, error_msg);
if (bm == NULL) {
assert(error_msg != NULL, "Must have error message");
return false;
} else {
bm->set_next(_match);
_match = bm;
return true;
}
}
void CompilerDirectives::inc_refcount() {
assert(DirectivesStack_lock->owned_by_self(), "");
_ref_count++;
}
void CompilerDirectives::dec_refcount() {
assert(DirectivesStack_lock->owned_by_self(), "");
_ref_count--;
}
int CompilerDirectives::refcount() {
assert(DirectivesStack_lock->owned_by_self(), "");
return _ref_count;
}
DirectiveSet* CompilerDirectives::get_for(AbstractCompiler *comp) {
assert(DirectivesStack_lock->owned_by_self(), "");
inc_refcount(); // The compiling thread is responsible to decrement this when finished.
if (comp == NULL) { // Xint
return _c1_store;
} else if (comp->is_c2()) {
return _c2_store;
} else if (comp->is_c1()) {
return _c1_store;
} else if (comp->is_shark()) {
return NULL;
} else if (comp->is_jvmci()) {
return NULL;
}
ShouldNotReachHere();
return NULL;
}
DirectiveSet::DirectiveSet(CompilerDirectives* d) :_inlinematchers(NULL), _directive(d) {
#define init_defaults_definition(name, type, dvalue, compiler) this->name##Option = dvalue;
compilerdirectives_common_flags(init_defaults_definition)
compilerdirectives_c2_flags(init_defaults_definition)
compilerdirectives_c1_flags(init_defaults_definition)
memset(_modified, 0, sizeof _modified);
}
DirectiveSet::~DirectiveSet() {
// remove all linked methodmatchers
InlineMatcher* tmp = _inlinematchers;
while (tmp != NULL) {
InlineMatcher* next = tmp->next();
delete tmp;
tmp = next;
}
// Free if modified, otherwise it just points to the global vm flag value
// or to the Compile command option
if (_modified[DisableIntrinsicIndex]) {
assert(this->DisableIntrinsicOption != NULL, "");
FREE_C_HEAP_ARRAY(char, (void *)this->DisableIntrinsicOption);
}
}
// Backward compatibility for CompileCommands
// Breaks the abstraction and causes lots of extra complexity
// - if some option is changed we need to copy directiveset since it no longer can be shared
// - Need to free copy after use
// - Requires a modified bit so we don't overwrite options that is set by directives
DirectiveSet* DirectiveSet::compilecommand_compatibility_init(methodHandle method) {
// 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 copy set if a flag needs to be set
if (!CompilerDirectivesIgnoreCompileCommandsOption && CompilerOracle::has_any_option()) {
DirectiveSet* set = DirectiveSet::clone(this);
bool changed = false; // Track if we actually change anything
// All CompileCommands are not equal so this gets a bit verbose
// When CompileCommands have been refactored less clutter will remain.
if (CompilerOracle::should_break_at(method)) {
if (!_modified[BreakAtCompileIndex]) {
set->BreakAtCompileOption = true;
changed = true;
}
if (!_modified[BreakAtExecuteIndex]) {
set->BreakAtExecuteOption = true;
changed = true;
}
}
if (CompilerOracle::should_log(method)) {
if (!_modified[LogIndex]) {
set->LogOption = true;
changed = true;
}
}
if (CompilerOracle::should_print(method)) {
if (!_modified[PrintAssemblyIndex]) {
set->PrintAssemblyOption = true;
changed = true;
}
}
// Exclude as in should not compile == Enabled
if (CompilerOracle::should_exclude(method)) {
if (!_modified[ExcludeIndex]) {
set->ExcludeOption = true;
changed = true;
}
}
// inline and dontinline (including exclude) are implemented in the directiveset accessors
#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->name##Option = v; changed = true;} }
compilerdirectives_common_flags(init_default_cc)
compilerdirectives_c2_flags(init_default_cc)
compilerdirectives_c1_flags(init_default_cc)
if (!changed) {
// We didn't actually update anything, discard.
delete set;
} else {
// We are returning a (parentless) copy. The originals parent don't need to account for this.
DirectivesStack::release(this);
return set;
}
}
// Nothing changed
return this;
}
CompilerDirectives* DirectiveSet::directive() {
assert(_directive != NULL, "Must have been initialized");
return _directive;
}
bool DirectiveSet::matches_inline(methodHandle method, int inline_action) {
if (_inlinematchers != NULL) {
if (_inlinematchers->match(method, InlineMatcher::force_inline)) {
return true;
}
}
return false;
}
bool DirectiveSet::should_inline(ciMethod* inlinee) {
inlinee->check_is_loaded();
VM_ENTRY_MARK;
methodHandle mh(THREAD, inlinee->get_Method());
if (matches_inline(mh, InlineMatcher::force_inline)) {
return true;
}
if (!CompilerDirectivesIgnoreCompileCommandsOption && CompilerOracle::should_inline(mh)) {
return true;
}
return false;
}
bool DirectiveSet::should_not_inline(ciMethod* inlinee) {
inlinee->check_is_loaded();
VM_ENTRY_MARK;
methodHandle mh(THREAD, inlinee->get_Method());
if (matches_inline(mh, InlineMatcher::dont_inline)) {
return true;
}
if (!CompilerDirectivesIgnoreCompileCommandsOption && CompilerOracle::should_not_inline(mh)) {
return true;
}
return false;
}
bool DirectiveSet::parse_and_add_inline(char* str, const char*& error_msg) {
InlineMatcher* m = InlineMatcher::parse_inline_pattern(str, error_msg);
if (m != NULL) {
// add matcher last in chain - the order is significant
append_inline(m);
return true;
} else {
assert(error_msg != NULL, "Error message must be set");
return false;
}
}
void DirectiveSet::append_inline(InlineMatcher* m) {
if (_inlinematchers == NULL) {
_inlinematchers = m;
return;
}
InlineMatcher* tmp = _inlinematchers;
while (tmp->next() != NULL) {
tmp = tmp->next();
}
tmp->set_next(m);
}
void DirectiveSet::print_inline(outputStream* st) {
if (_inlinematchers == NULL) {
st->print_cr(" inline: -");
} else {
st->print(" inline: ");
_inlinematchers->print(st);
InlineMatcher* tmp = _inlinematchers->next();
while (tmp != NULL) {
st->print(", ");
tmp->print(st);
tmp = tmp->next();
}
st->cr();
}
}
bool DirectiveSet::is_intrinsic_disabled(methodHandle method) {
vmIntrinsics::ID id = method->intrinsic_id();
assert(id != vmIntrinsics::_none, "must be a VM intrinsic");
ccstr disable_intr = DisableIntrinsicOption;
return ((disable_intr != '\0') && strstr(disable_intr, vmIntrinsics::name_at(id)) != NULL);
}
DirectiveSet* DirectiveSet::clone(DirectiveSet const* src) {
DirectiveSet* set = new DirectiveSet(NULL);
memcpy(set->_modified, src->_modified, sizeof(src->_modified));
InlineMatcher* tmp = src->_inlinematchers;
while (tmp != NULL) {
set->append_inline(tmp->clone());
tmp = tmp->next();
}
#define copy_members_definition(name, type, dvalue, cc_flag) set->name##Option = src->name##Option;
compilerdirectives_common_flags(copy_members_definition)
compilerdirectives_c2_flags(copy_members_definition)
compilerdirectives_c1_flags(copy_members_definition)
// Must duplicate ccstr option if it was modified, otherwise it is global.
if (src->_modified[DisableIntrinsicIndex]) {
assert(src->DisableIntrinsicOption != NULL, "");
size_t len = strlen(src->DisableIntrinsicOption) + 1;
char* s = NEW_C_HEAP_ARRAY(char, len, mtCompiler);
strncpy(s, src->DisableIntrinsicOption, len);
assert(s[len-1] == '\0', "");
set->DisableIntrinsicOption = s;
}
return set;
}
// Create a new dirstack and push a default directive
void DirectivesStack::init() {
CompilerDirectives* _default_directives = new CompilerDirectives();
char str[] = "*.*";
const char* error_msg = NULL;
_default_directives->add_match(str, error_msg);
#ifdef COMPILER1
_default_directives->_c1_store->EnableOption = true;
#endif
#ifdef COMPILER2
_default_directives->_c2_store->EnableOption = true;
#endif
assert(error_msg == NULL, "Must succeed.");
push(_default_directives);
}
DirectiveSet* DirectivesStack::getDefaultDirective(AbstractCompiler* comp) {
MutexLockerEx locker(DirectivesStack_lock, Mutex::_no_safepoint_check_flag);
assert(_bottom != NULL, "Must never be empty");
return _bottom->get_for(comp);
}
void DirectivesStack::push(CompilerDirectives* directive) {
MutexLockerEx locker(DirectivesStack_lock, Mutex::_no_safepoint_check_flag);
directive->inc_refcount();
if (_top == NULL) {
assert(_bottom == NULL, "There can only be one default directive");
_bottom = directive; // default directive, can never be removed.
}
directive->set_next(_top);
_top = directive;
_depth++;
}
void DirectivesStack::pop() {
MutexLockerEx locker(DirectivesStack_lock, Mutex::_no_safepoint_check_flag);
pop_inner();
}
void DirectivesStack::pop_inner() {
assert(DirectivesStack_lock->owned_by_self(), "");
if (_top->next() == NULL) {
return; // Do nothing - don't allow an empty stack
}
CompilerDirectives* tmp = _top;
_top = _top->next();
_depth--;
DirectivesStack::release(tmp);
}
void DirectivesStack::clear() {
// holding the lock during the whole operation ensuring consistent result
MutexLockerEx locker(DirectivesStack_lock, Mutex::_no_safepoint_check_flag);
while (_top->next() != NULL) {
pop_inner();
}
}
void DirectivesStack::print(outputStream* st) {
MutexLockerEx locker(DirectivesStack_lock, Mutex::_no_safepoint_check_flag);
CompilerDirectives* tmp = _top;
while (tmp != NULL) {
tmp->print(st);
tmp = tmp->next();
st->cr();
}
}
void DirectivesStack::release(DirectiveSet* set) {
MutexLockerEx locker(DirectivesStack_lock, Mutex::_no_safepoint_check_flag);
if (set->is_exclusive_copy()) {
// Old CompilecCmmands forced us to create an exclusive copy
delete set;
} else {
assert(set->directive() != NULL, "");
release(set->directive());
}
}
void DirectivesStack::release(CompilerDirectives* dir) {
assert(DirectivesStack_lock->owned_by_self(), "");
dir->dec_refcount();
if (dir->refcount() == 0) {
delete dir;
}
}
DirectiveSet* DirectivesStack::getMatchingDirective(methodHandle method, AbstractCompiler *comp) {
assert(_depth > 0, "Must never be empty");
CompilerDirectives* dir = _top;
assert(dir != NULL, "Must be initialized");
DirectiveSet* match = NULL;
{
MutexLockerEx locker(DirectivesStack_lock, Mutex::_no_safepoint_check_flag);
while (dir != NULL) {
if (dir->is_default_directive() || dir->match(method)) {
match = dir->get_for(comp);
if (match->EnableOption) {
// The directiveSet for this compile is also enabled -> success
break;
}
}
dir = dir->next();
}
}
guarantee(match != NULL, "There should always be a default directive that matches");
// Check for legacy compile commands update, without DirectivesStack_lock
return match->compilecommand_compatibility_init(method);
}

View File

@ -0,0 +1,186 @@
/*
* Copyright (c) 1998, 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
#ifndef SHARE_VM_COMPILER_COMPILERDIRECTIVES_HPP
#define SHARE_VM_COMPILER_COMPILERDIRECTIVES_HPP
#include "ci/ciMetadata.hpp"
#include "ci/ciMethod.hpp"
#include "ci/ciUtilities.hpp"
#include "compiler/methodMatcher.hpp"
#include "compiler/compilerOracle.hpp"
#include "oops/oop.inline.hpp"
#include "utilities/exceptions.hpp"
// Directives flag name, type, default value, compile command name
#define compilerdirectives_common_flags(cflags) \
cflags(Enable, bool, false, X) \
cflags(Exclude, bool, false, X) \
cflags(BreakAtExecute, bool, false, X) \
cflags(BreakAtCompile, bool, false, X) \
cflags(Log, bool, false, X) \
cflags(PrintAssembly, bool, PrintAssembly, PrintAssembly) \
cflags(PrintInlining, bool, PrintInlining, PrintInlining) \
cflags(PrintNMethods, bool, PrintNMethods, PrintNMethods) \
cflags(ReplayInline, bool, false, ReplayInline) \
cflags(DumpReplay, bool, false, DumpReplay) \
cflags(DumpInline, bool, false, DumpInline) \
cflags(CompilerDirectivesIgnoreCompileCommands, bool, CompilerDirectivesIgnoreCompileCommands, X) \
cflags(DisableIntrinsic, ccstr, DisableIntrinsic, DisableIntrinsic)
#ifdef COMPILER1
#define compilerdirectives_c1_flags(cflags)
#else
#define compilerdirectives_c1_flags(cflags)
#endif
#ifdef COMPILER2
#define compilerdirectives_c2_flags(cflags) \
cflags(BlockLayoutByFrequency, bool, BlockLayoutByFrequency, BlockLayoutByFrequency) \
cflags(PrintOptoAssembly, bool, PrintOptoAssembly, PrintOptoAssembly) \
cflags(PrintIntrinsics, bool, PrintIntrinsics, PrintIntrinsics) \
cflags(TraceOptoPipelining, bool, false, TraceOptoPipelining) \
cflags(TraceOptoOutput, bool, false, TraceOptoOutput) \
cflags(TraceSpilling, bool, TraceSpilling, TraceSpilling) \
cflags(Vectorize, bool, false, Vectorize) \
cflags(VectorizeDebug, bool, false, VectorizeDebug) \
cflags(CloneMapDebug, bool, false, CloneMapDebug) \
cflags(DoReserveCopyInSuperWordDebug, bool, false, DoReserveCopyInSuperWordDebug) \
cflags(IGVPrintLevel, intx, PrintIdealGraphLevel, IGVPrintLevel) \
cflags(MaxNodeLimit, intx, MaxNodeLimit, MaxNodeLimit)
#else
#define compilerdirectives_c2_flags(cflags)
#endif
class CompilerDirectives;
class DirectiveSet;
class DirectivesStack : AllStatic {
private:
static CompilerDirectives* _top;
static CompilerDirectives* _bottom;
static int _depth;
static void pop_inner(); // no lock version of pop
public:
static void init();
static DirectiveSet* getMatchingDirective(methodHandle mh, AbstractCompiler* comp);
static DirectiveSet* getDefaultDirective(AbstractCompiler* comp);
static void push(CompilerDirectives* directive);
static void pop();
static void clear();
static void print(outputStream* st);
static void release(DirectiveSet* set);
static void release(CompilerDirectives* dir);
};
class DirectiveSet : public CHeapObj<mtCompiler> {
private:
InlineMatcher* _inlinematchers;
CompilerDirectives* _directive;
public:
DirectiveSet(CompilerDirectives* directive);
~DirectiveSet();
CompilerDirectives* directive();
bool parse_and_add_inline(char* str, const char*& error_msg);
void append_inline(InlineMatcher* m);
bool should_inline(ciMethod* inlinee);
bool should_not_inline(ciMethod* inlinee);
void print_inline(outputStream* st);
DirectiveSet* compilecommand_compatibility_init(methodHandle method);
bool is_exclusive_copy() { return _directive == NULL; }
bool matches_inline(methodHandle method, int inline_action);
static DirectiveSet* clone(DirectiveSet const* src);
bool is_intrinsic_disabled(methodHandle method);
void finalize();
typedef enum {
#define enum_of_flags(name, type, dvalue, cc_flag) name##Index,
compilerdirectives_common_flags(enum_of_flags)
compilerdirectives_c2_flags(enum_of_flags)
compilerdirectives_c1_flags(enum_of_flags)
number_of_flags
} flags;
bool _modified[number_of_flags];
#define flag_store_definition(name, type, dvalue, cc_flag) type name##Option;
compilerdirectives_common_flags(flag_store_definition)
compilerdirectives_c2_flags(flag_store_definition)
compilerdirectives_c1_flags(flag_store_definition)
// Casting to get the same function signature for all setters. Used from parser.
#define set_function_definition(name, type, dvalue, cc_flag) void set_##name(void* value) { type val = *(type*)value; name##Option = val; _modified[name##Index] = 1; }
compilerdirectives_common_flags(set_function_definition)
compilerdirectives_c2_flags(set_function_definition)
compilerdirectives_c1_flags(set_function_definition)
void print_intx(outputStream* st, ccstr n, intx v, bool mod) { if (mod) { st->print("%s:" INTX_FORMAT " ", n, v); } }
void print_bool(outputStream* st, ccstr n, bool v, bool mod) { if (mod) { st->print("%s:%s ", n, v ? "true" : "false"); } }
void print_double(outputStream* st, ccstr n, double v, bool mod) { if (mod) { st->print("%s:%f ", n, v); } }
void print_ccstr(outputStream* st, ccstr n, ccstr v, bool mod) { if (mod) { st->print("%s:%s ", n, v); } }
void print(outputStream* st) {
print_inline(st);
st->print(" ");
#define print_function_definition(name, type, dvalue, cc_flag) print_##type(st, #name, this->name##Option, true);//(bool)_modified[name##Index]);
compilerdirectives_common_flags(print_function_definition)
compilerdirectives_c2_flags(print_function_definition)
compilerdirectives_c1_flags(print_function_definition)
st->cr();
}
};
class CompilerDirectives : public CHeapObj<mtCompiler> {
private:
CompilerDirectives* _next;
BasicMatcher* _match;
int _ref_count;
public:
CompilerDirectives();
~CompilerDirectives();
CompilerDirectives* next();
void set_next(CompilerDirectives* next) {_next = next; }
bool match(methodHandle method);
BasicMatcher* match() { return _match; }
bool add_match(char* str, const char*& error_msg);
DirectiveSet* get_for(AbstractCompiler *comp);
void print(outputStream* st);
bool is_default_directive() { return _next == NULL; }
void finalize();
void inc_refcount();
void dec_refcount();
int refcount();
DirectiveSet* _c1_store;
DirectiveSet* _c2_store;
};
#endif // SHARE_VM_COMPILER_COMPILERDIRECTIVES_HPP

View File

@ -106,6 +106,7 @@ class TypedMethodOptionMatcher;
static BasicMatcher* lists[OracleCommandCount] = { 0, };
static TypedMethodOptionMatcher* option_list = NULL;
static bool any_set = false;
class TypedMethodOptionMatcher : public MethodMatcher {
private:
@ -292,6 +293,7 @@ static void add_option_string(TypedMethodOptionMatcher* matcher,
matcher->init(option, get_type_for<T>(), option_list);
matcher->set_value<T>(value);
option_list = matcher;
any_set = true;
return;
}
@ -308,7 +310,9 @@ static void add_predicate(OracleCommand command, BasicMatcher* bm) {
}
bm->set_next(lists[command]);
lists[command] = bm;
if ((command != DontInlineCommand) && (command != InlineCommand)) {
any_set = true;
}
return;
}
@ -324,6 +328,10 @@ bool CompilerOracle::has_option_value(methodHandle method, const char* option, T
return false;
}
bool CompilerOracle::has_any_option() {
return any_set;
}
// Explicit instantiation for all OptionTypes supported.
template bool CompilerOracle::has_option_value<intx>(methodHandle method, const char* option, intx& value);
template bool CompilerOracle::has_option_value<uintx>(methodHandle method, const char* option, uintx& value);
@ -337,15 +345,10 @@ bool CompilerOracle::has_option_string(methodHandle method, const char* option)
return value;
}
bool CompilerOracle::should_exclude(methodHandle method, bool& quietly) {
quietly = true;
if (lists[ExcludeCommand] != NULL) {
if (lists[ExcludeCommand]->match(method)) {
quietly = _quiet;
return true;
}
bool CompilerOracle::should_exclude(methodHandle method) {
if (check_predicate(ExcludeCommand, method)) {
return true;
}
if (lists[CompileOnlyCommand] != NULL) {
return !lists[CompileOnlyCommand]->match(method);
}
@ -356,8 +359,6 @@ bool CompilerOracle::should_inline(methodHandle method) {
return (check_predicate(InlineCommand, method));
}
// Check both DontInlineCommand and ExcludeCommand here
// - consistent behavior for all compilers
bool CompilerOracle::should_not_inline(methodHandle method) {
return check_predicate(DontInlineCommand, method) || check_predicate(ExcludeCommand, method);
}

View File

@ -46,7 +46,8 @@ class CompilerOracle : AllStatic {
static void parse_from_file();
// Tells whether we to exclude compilation of method
static bool should_exclude(methodHandle method, bool& quietly);
static bool should_exclude(methodHandle method);
static bool should_exclude_quietly() { return _quiet; }
// Tells whether we want to inline this method
static bool should_inline(methodHandle method);
@ -71,6 +72,9 @@ class CompilerOracle : AllStatic {
template<typename T>
static bool has_option_value(methodHandle method, const char* option, T& value);
// 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
static void parse_from_string(const char* command_string, void (*parser)(char*));

View File

@ -0,0 +1,726 @@
/*
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
#include "precompiled.hpp"
#include "compiler/compileBroker.hpp"
#include "compiler/directivesParser.hpp"
#include "memory/allocation.inline.hpp"
#include "runtime/os.hpp"
#include <string.h>
void DirectivesParser::push_tmp(CompilerDirectives* dir) {
dir->set_next(_tmp_top);
_tmp_top = dir;
}
CompilerDirectives* DirectivesParser::pop_tmp() {
if (_tmp_top == NULL) {
return NULL;
}
CompilerDirectives* tmp = _tmp_top;
_tmp_top = _tmp_top->next();
tmp->set_next(NULL);
return tmp;
}
bool DirectivesParser::parse_string(const char* text, outputStream* st) {
DirectivesParser cd(text, st);
if (cd.valid()) {
return cd.install_directives();
}
st->flush();
st->print_cr("Parsing of compiler directives failed");
return false;
}
bool DirectivesParser::has_file() {
return CompilerDirectivesFile != NULL;
}
bool DirectivesParser::parse_from_flag() {
return parse_from_file(CompilerDirectivesFile, tty);
}
bool DirectivesParser::parse_from_file(const char* filename, outputStream* st) {
assert(filename != NULL, "Test before calling this");
if (!parse_from_file_inner(filename, st)) {
st->print_cr("Could not load file: %s", filename);
return false;
}
return true;
}
bool DirectivesParser::parse_from_file_inner(const char* filename, outputStream* stream) {
struct stat st;
ResourceMark rm;
if (os::stat(filename, &st) == 0) {
// found file, open it
int file_handle = os::open(filename, 0, 0);
if (file_handle != -1) {
// read contents into resource array
char* buffer = NEW_RESOURCE_ARRAY(char, st.st_size+1);
size_t num_read = os::read(file_handle, (char*) buffer, st.st_size);
buffer[num_read] = '\0';
// close file
os::close(file_handle);
return parse_string(buffer, stream);
}
}
return false;
}
bool DirectivesParser::install_directives() {
// Pop from internal temporary stack and push to compileBroker.
CompilerDirectives* tmp = pop_tmp();
int i = 0;
while (tmp != NULL) {
i++;
DirectivesStack::push(tmp);
tmp = pop_tmp();
}
if (i == 0) {
_st->print_cr("No directives in file");
return false;
} else {
_st->print_cr("%i compiler directives added", i);
if (PrintCompilerDirectives) {
// Print entire directives stack after new has been pushed.
DirectivesStack::print(_st);
}
return true;
}
}
DirectivesParser::DirectivesParser(const char* text, outputStream* st)
: JSON(text, false, st), depth(0), current_directive(NULL), current_directiveset(NULL), _tmp_top(NULL) {
#ifndef PRODUCT
memset(stack, 0, MAX_DEPTH * sizeof(stack[0]));
#endif
parse();
}
DirectivesParser::~DirectivesParser() {
}
const DirectivesParser::key DirectivesParser::keys[] = {
// name, keytype, allow_array, allowed_mask, set_function
{ "c1", type_c1, 0, mask(type_directives), NULL, UnknownFlagType },
{ "c2", type_c2, 0, mask(type_directives), NULL, UnknownFlagType },
{ "match", type_match, 1, mask(type_directives), NULL, UnknownFlagType },
{ "inline", type_inline, 1, mask(type_directives) | mask(type_c1) | mask(type_c2), NULL, UnknownFlagType },
{ "enable", type_enable, 1, mask(type_directives) | mask(type_c1) | mask(type_c2), NULL, UnknownFlagType },
{ "preset", type_preset, 0, mask(type_c1) | mask(type_c2), NULL, UnknownFlagType },
// Global flags
#define common_flag_key(name, type, dvalue, compiler) \
{ #name, type_flag, 0, mask(type_directives) | mask(type_c1) | mask(type_c2), &DirectiveSet::set_##name, type##Flag},
compilerdirectives_common_flags(common_flag_key)
compilerdirectives_c2_flags(common_flag_key)
compilerdirectives_c1_flags(common_flag_key)
#undef common_flag_key
};
const DirectivesParser::key DirectivesParser::dir_array_key = {
"top level directives array", type_dir_array, 0, 1 // Lowest bit means allow at top level
};
const DirectivesParser::key DirectivesParser::dir_key = {
"top level directive", type_directives, 0, mask(type_dir_array) | 1 // Lowest bit means allow at top level
};
const DirectivesParser::key DirectivesParser::value_array_key = {
"value array", type_value_array, 0, UINT_MAX // Allow all, checked by allow_array on other keys, not by allowed_mask from this key
};
const DirectivesParser::key* DirectivesParser::lookup_key(const char* str, size_t len) {
for (size_t i = 0; i < (sizeof(keys) / sizeof(keys[0])); i++) {
if (strncasecmp(keys[i].name, str, len) == 0) {
return &keys[i];
}
}
return NULL;
}
uint DirectivesParser::mask(keytype kt) {
return 1 << (kt + 1);
}
bool DirectivesParser::push_key(const char* str, size_t len) {
bool result = true;
const key* k = lookup_key(str, len);
if (k == NULL) {
// os::strdup
char* s = NEW_C_HEAP_ARRAY(char, len + 1, mtCompiler);
strncpy(s, str, len);
s[len] = '\0';
error(KEY_ERROR, "No such key: '%s'.", s);
FREE_C_HEAP_ARRAY(char, s);
return false;
}
return push_key(k);
}
bool DirectivesParser::push_key(const key* k) {
assert(k->allowedmask != 0, "not allowed anywhere?");
// Exceeding the stack should not be possible with a valid compiler directive,
// and an invalid should abort before this happens
assert(depth < MAX_DEPTH, "exceeded stack depth");
if (depth >= MAX_DEPTH) {
error(INTERNAL_ERROR, "Stack depth exceeded.");
return false;
}
assert(stack[depth] == NULL, "element not nulled, something is wrong");
if (depth == 0 && !(k->allowedmask & 1)) {
error(KEY_ERROR, "Key '%s' not allowed at top level.", k->name);
return false;
}
if (depth > 0) {
const key* prev = stack[depth - 1];
if (!(k->allowedmask & mask(prev->type))) {
error(KEY_ERROR, "Key '%s' not allowed after '%s' key.", k->name, prev->name);
return false;
}
}
stack[depth] = k;
depth++;
return true;
}
const DirectivesParser::key* DirectivesParser::current_key() {
assert(depth > 0, "getting key from empty stack");
if (depth == 0) {
return NULL;
}
return stack[depth - 1];
}
const DirectivesParser::key* DirectivesParser::pop_key() {
assert(depth > 0, "popping empty stack");
if (depth == 0) {
error(INTERNAL_ERROR, "Popping empty stack.");
return NULL;
}
depth--;
const key* k = stack[depth];
#ifndef PRODUCT
stack[depth] = NULL;
#endif
return k;
}
bool DirectivesParser::set_option_flag(JSON_TYPE t, JSON_VAL* v, const key* option_key, DirectiveSet* set) {
void (DirectiveSet::*test)(void *args);
test = option_key->set;
switch (t) {
case JSON_TRUE:
if (option_key->flag_type != boolFlag) {
error(VALUE_ERROR, "Cannot use bool value for an %s flag", flag_type_names[option_key->flag_type]);
return false;
} else {
bool val = true;
(set->*test)((void *)&val);
}
break;
case JSON_FALSE:
if (option_key->flag_type != boolFlag) {
error(VALUE_ERROR, "Cannot use bool value for an %s flag", flag_type_names[option_key->flag_type]);
return false;
} else {
bool val = false;
(set->*test)((void *)&val);
}
break;
case JSON_NUMBER_INT:
if (option_key->flag_type != intxFlag) {
if (option_key->flag_type == doubleFlag) {
double dval = (double)v->int_value;
(set->*test)((void *)&dval);
break;
}
error(VALUE_ERROR, "Cannot use int value for an %s flag", flag_type_names[option_key->flag_type]);
return false;
} else {
intx ival = v->int_value;
(set->*test)((void *)&ival);
}
break;
case JSON_NUMBER_FLOAT:
if (option_key->flag_type != doubleFlag) {
error(VALUE_ERROR, "Cannot use double value for an %s flag", flag_type_names[option_key->flag_type]);
return false;
} else {
double dval = v->double_value;
(set->*test)((void *)&dval);
}
break;
case JSON_STRING:
if (option_key->flag_type != ccstrFlag) {
error(VALUE_ERROR, "Cannot use string value for a %s flag", flag_type_names[option_key->flag_type]);
return false;
} else {
char* s = NEW_C_HEAP_ARRAY(char, v->str.length+1, mtCompiler);
strncpy(s, v->str.start, v->str.length + 1);
s[v->str.length] = '\0';
(set->*test)((void *)&s);
}
break;
default:
assert(0, "Should not reach here.");
}
return true;
}
bool DirectivesParser::set_option(JSON_TYPE t, JSON_VAL* v) {
const key* option_key = pop_key();
const key* enclosing_key = current_key();
if (option_key->type == value_array_key.type) {
// Multi value array, we are really setting the value
// for the key one step further up.
option_key = pop_key();
enclosing_key = current_key();
// Repush option_key and multi value marker, since
// we need to keep them until all multi values are set.
push_key(option_key);
push_key(&value_array_key);
}
switch (option_key->type) {
case type_flag:
{
if (current_directiveset == NULL) {
assert(depth == 2, "Must not have active directive set");
if (!set_option_flag(t, v, option_key, current_directive->_c1_store)) {
return false;
}
if(!set_option_flag(t, v, option_key, current_directive->_c2_store)) {
return false;
}
} else {
assert(depth > 2, "Must have active current directive set");
if (!set_option_flag(t, v, option_key, current_directiveset)) {
return false;
}
}
break;
}
case type_match:
if (t != JSON_STRING) {
error(VALUE_ERROR, "Key of type %s needs a value of type string", option_key->name);
return false;
}
if (enclosing_key->type != type_directives) {
error(SYNTAX_ERROR, "Match keyword can only exist inside a directive");
return false;
}
{
char* s = NEW_C_HEAP_ARRAY(char, v->str.length + 1, mtCompiler);
strncpy(s, v->str.start, v->str.length);
s[v->str.length] = '\0';
const char* error_msg = NULL;
if (!current_directive->add_match(s, error_msg)) {
assert (error_msg != NULL, "Must have valid error message");
error(VALUE_ERROR, "Method pattern error: %s", error_msg);
}
FREE_C_HEAP_ARRAY(char, s);
}
break;
case type_inline:
if (t != JSON_STRING) {
error(VALUE_ERROR, "Key of type %s needs a value of type string", option_key->name);
return false;
}
{
//char* s = strndup(v->str.start, v->str.length);
char* s = NEW_C_HEAP_ARRAY(char, v->str.length + 1, mtCompiler);
strncpy(s, v->str.start, v->str.length);
s[v->str.length] = '\0';
const char* error_msg = NULL;
if (current_directiveset == NULL) {
if (!current_directive->_c1_store->parse_and_add_inline(s, error_msg)) {
assert (error_msg != NULL, "Must have valid error message");
error(VALUE_ERROR, "Method pattern error: %s", error_msg);
}
if (!current_directive->_c2_store->parse_and_add_inline(s, error_msg)) {
assert (error_msg != NULL, "Must have valid error message");
error(VALUE_ERROR, "Method pattern error: %s", error_msg);
}
} else {
if (!current_directiveset->parse_and_add_inline(s, error_msg)) {
assert (error_msg != NULL, "Must have valid error message");
error(VALUE_ERROR, "Method pattern error: %s", error_msg);
}
}
FREE_C_HEAP_ARRAY(char, s);
}
break;
case type_c1:
current_directiveset = current_directive->_c1_store;
if (t != JSON_TRUE && t != JSON_FALSE) {
error(VALUE_ERROR, "Key of type %s needs a true or false value", option_key->name);
return false;
}
break;
case type_c2:
current_directiveset = current_directive->_c2_store;
if (t != JSON_TRUE && t != JSON_FALSE) {
error(VALUE_ERROR, "Key of type %s needs a true or false value", option_key->name);
return false;
}
break;
case type_enable:
switch (enclosing_key->type) {
case type_c1:
case type_c2:
{
if (t != JSON_TRUE && t != JSON_FALSE) {
error(VALUE_ERROR, "Key of type %s enclosed in a %s key needs a true or false value", option_key->name, enclosing_key->name);
return false;
}
int val = (t == JSON_TRUE);
current_directiveset->set_Enable(&val);
break;
}
case type_directives:
error(VALUE_ERROR, "Enable keyword not available for generic directive");
return false;
default:
error(INTERNAL_ERROR, "Unexpected enclosing type for key %s: %s", option_key->name, enclosing_key->name);
ShouldNotReachHere();
return false;
}
break;
default:
break;
}
return true;
}
bool DirectivesParser::callback(JSON_TYPE t, JSON_VAL* v, uint rlimit) {
const key* k;
if (depth == 0) {
switch (t) {
case JSON_ARRAY_BEGIN:
return push_key(&dir_array_key);
case JSON_OBJECT_BEGIN:
// push synthetic dir_array
push_key(&dir_array_key);
assert(depth == 1, "Make sure the stack are aligned with the directives");
break;
default:
error(SYNTAX_ERROR, "DirectivesParser can only start with an array containing directive objects, or one single directive.");
return false;
}
}
if (depth == 1) {
switch (t) {
case JSON_OBJECT_BEGIN:
// Parsing a new directive.
current_directive = new CompilerDirectives();
return push_key(&dir_key);
case JSON_ARRAY_END:
k = pop_key();
if (k->type != type_dir_array) {
error(SYNTAX_ERROR, "Expected end of directives array");
return false;
}
return true;
default:
error(SYNTAX_ERROR, "DirectivesParser can only start with an array containing directive objects, or one single directive.");
return false;
}
} else {
switch (t) {
case JSON_OBJECT_BEGIN:
k = current_key();
switch (k->type) {
case type_c1:
current_directiveset = current_directive->_c1_store;
return true;
case type_c2:
current_directiveset = current_directive->_c2_store;
return true;
case type_dir_array:
return push_key(&dir_key);
default:
error(SYNTAX_ERROR, "The key '%s' does not allow an object to follow.", k->name);
return false;
}
return false;
case JSON_OBJECT_END:
k = pop_key();
switch (k->type) {
case type_c1:
case type_c2:
// This is how we now if options apply to a single or both directive sets
current_directiveset = NULL;
break;
case type_directives:
// Check, finish and push to stack!
if (current_directive->match() == NULL) {
error(INTERNAL_ERROR, "Directive missing required match.");
return false;
}
current_directive->finalize();
push_tmp(current_directive);
current_directive = NULL;
break;
default:
error(INTERNAL_ERROR, "Object end with wrong key type on stack: %s.", k->name);
ShouldNotReachHere();
return false;
}
return true;
case JSON_ARRAY_BEGIN:
k = current_key();
if (!(k->allow_array_value)) {
if (k->type == type_dir_array) {
error(SYNTAX_ERROR, "Array not allowed inside top level array, expected directive object.");
} else {
error(VALUE_ERROR, "The key '%s' does not allow an array of values.", k->name);
}
return false;
}
return push_key(&value_array_key);
case JSON_ARRAY_END:
k = pop_key(); // Pop multi value marker
assert(k->type == value_array_key.type, "array end for level != 0 should terminate multi value");
k = pop_key(); // Pop key for option that was set
return true;
case JSON_KEY:
return push_key(v->str.start, v->str.length);
case JSON_STRING:
case JSON_NUMBER_INT:
case JSON_NUMBER_FLOAT:
case JSON_TRUE:
case JSON_FALSE:
case JSON_NULL:
return set_option(t, v);
default:
error(INTERNAL_ERROR, "Unknown JSON type: %d.", t);
ShouldNotReachHere();
return false;
}
}
}
#ifndef PRODUCT
void DirectivesParser::test(const char* text, bool should_pass) {
DirectivesParser cd(text, tty);
if (should_pass) {
assert(cd.valid() == true, "failed on a valid DirectivesParser string");
if (VerboseInternalVMTests) {
tty->print("-- DirectivesParser test passed as expected --\n");
}
} else {
assert(cd.valid() == false, "succeeded on an invalid DirectivesParser string");
if (VerboseInternalVMTests) {
tty->print("-- DirectivesParser test failed as expected --\n");
}
}
}
bool DirectivesParser::test() {
DirectivesParser::test("{}", false);
DirectivesParser::test("[]", true);
DirectivesParser::test("[{}]", false);
DirectivesParser::test("[{},{}]", false);
DirectivesParser::test("{},{}", false);
DirectivesParser::test(
"[" "\n"
" {" "\n"
" match: \"foo/bar.*\"," "\n"
" inline : \"+java/util.*\"," "\n"
" PrintAssembly: true," "\n"
" BreakAtExecute: true," "\n"
" }" "\n"
"]" "\n", true);
DirectivesParser::test(
"[" "\n"
" [" "\n"
" {" "\n"
" match: \"foo/bar.*\"," "\n"
" inline : \"+java/util.*\"," "\n"
" PrintAssembly: true," "\n"
" BreakAtExecute: true," "\n"
" }" "\n"
" ]" "\n"
"]" "\n", false);
/*DirectivesParser::test(
"[" "\n"
" {" "\n"
" match: \"foo/bar.*\"," "\n"
" c1: {"
" PrintIntrinsics: false," "\n"
" }" "\n"
" }" "\n"
"]" "\n", false);*/
DirectivesParser::test(
"[" "\n"
" {" "\n"
" match: \"foo/bar.*\"," "\n"
" c2: {" "\n"
" PrintInlining: false," "\n"
" }" "\n"
" }" "\n"
"]" "\n", true);
DirectivesParser::test(
"[" "\n"
" {" "\n"
" match: \"foo/bar.*\"," "\n"
" PrintInlining: [" "\n"
" true," "\n"
" false" "\n"
" ]," "\n"
" }" "\n"
"]" "\n", false);
DirectivesParser::test(
"[" "\n"
" {"
" // pattern to match against class+method+signature" "\n"
" // leading and trailing wildcard (*) allowed" "\n"
" match: \"foo/bar.*\"," "\n"
"" "\n"
" // override defaults for specified compiler" "\n"
" // we may differentiate between levels too. TBD." "\n"
" c1: {" "\n"
" //override c1 presets " "\n"
" DumpReplay: false," "\n"
" BreakAtCompile: true," "\n"
" }," "\n"
"" "\n"
" c2: {" "\n"
" // control inlining of method" "\n"
" // + force inline, - dont inline" "\n"
" inline : \"+java/util.*\"," "\n"
" PrintInlining: true," "\n"
" }," "\n"
"" "\n"
" // directives outside a specific preset applies to all compilers" "\n"
" inline : [ \"+java/util.*\", \"-com/sun.*\"]," "\n"
" BreakAtExecute: true," "\n"
" Log: true," "\n"
" }," "\n"
" {" "\n"
" // matching several patterns require an array" "\n"
" match: [\"baz.*\",\"frob.*\"]," "\n"
"" "\n"
" // applies to all compilers" "\n"
" // + force inline, - dont inline" "\n"
" inline : [ \"+java/util.*\", \"-com/sun.*\" ]," "\n"
" PrintInlining: true," "\n"
"" "\n"
" // force matching compiles to be blocking/syncronous" "\n"
" PrintNMethods: true" "\n"
" }," "\n"
"]" "\n", true);
// Test max stack depth
DirectivesParser::test(
"[" "\n" // depth 1: type_dir_array
" {" "\n" // depth 2: type_directives
" match: \"*.*\"," // match required
" c1:" "\n" // depth 3: type_c1
" {" "\n"
" inline:" "\n" // depth 4: type_inline
" [" "\n" // depth 5: type_value_array
" \"foo\"," "\n"
" \"bar\"," "\n"
" ]" "\n" // depth 3: pop type_value_array and type_inline keys
" }" "\n" // depth 2: pop type_c1 key
" }" "\n" // depth 1: pop type_directives key
"]" "\n", true); // depth 0: pop type_dir_array key
// Test max stack depth
DirectivesParser::test(
"[{c1:{c1:{c1:{c1:{c1:{c1:{c1:{}}}}}}}}]", false);
DirectivesParser::test(
"[" "\n"
" {" "\n"
" c1: true," "\n"
" c2: true," "\n"
" match: true," "\n"
" inline: true," "\n"
" enable: true," "\n"
" c1: {" "\n"
" preset: true," "\n"
" }" "\n"
" }" "\n"
"]" "\n", false);
return true;
}
#endif

View File

@ -0,0 +1,139 @@
/*
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
#ifndef SHARE_VM_COMPILER_DIRECTIVESPARSER_HPP
#define SHARE_VM_COMPILER_DIRECTIVESPARSER_HPP
#include "utilities/json.hpp"
#include "compiler/compilerDirectives.hpp"
enum FlagType {
boolFlag,
intxFlag,
doubleFlag,
ccstrFlag,
UnknownFlagType
};
static const char* flag_type_names[] = {
"bool",
"int",
"double",
"string",
"unknown"
};
class DirectivesParser : public JSON {
public:
static bool has_file();
static bool parse_from_flag();
static bool parse_from_file(const char* filename, outputStream* st);
static bool parse_string(const char* string, outputStream* st);
bool install_directives();
private:
DirectivesParser(const char* text, outputStream* st);
~DirectivesParser();
bool callback(JSON_TYPE t, JSON_VAL* v, uint level);
static bool parse_from_file_inner(const char* filename, outputStream* st);
// types of "keys". i.e recognized <key>:<value> pairs in our JSON syntax
typedef enum {
type_c1,
type_c2,
type_enable,
type_preset,
type_match,
type_inline,
// After here, there is no correlation between
// keytype and keys array
//type_strategy,
type_flag,
//type_dir,
// Synthetic.
type_dir_array,
type_directives,
type_value_array
} keytype;
// name, type, dtd info and maybe a setter
// this is how we map key-values
typedef struct {
const char *name;
keytype type;
uint allow_array_value : 1;
uint allowedmask;
void (DirectiveSet::*set)(void* arg);
FlagType flag_type;
} key;
// Array with valid keys for the directive file
static const key keys[];
// Marker for outermost moosewings/array
static const key dir_array_key;
// Marker for a directives set (these are "implicit" objects, as in not named)
static const key dir_key;
// Marker for a multi value
static const key value_array_key;
// A compiler directive shouldn't be able to use more than 5 stack slots.
// Example of max stack usage:
// depth 1: type_dir_array [
// depth 2: type_directives {
// depth 3: type_c1 c1: {
// depth 4: type_inline inline:
// depth 5: type_value_array [ ...
static const uint MAX_DEPTH = 5;
const key* stack[MAX_DEPTH];
uint depth;
bool push_key(const char* str, size_t len);
bool push_key(const key* k);
const key* current_key();
const key* pop_key();
static const key* lookup_key(const char* s, size_t len);
bool set_option(JSON_TYPE t, JSON_VAL* v);
bool set_option_flag(JSON_TYPE t, JSON_VAL* v, const key* option_key, DirectiveSet* set);
CompilerDirectives* current_directive;
DirectiveSet* current_directiveset;
void push_tmp(CompilerDirectives* dir);
CompilerDirectives* pop_tmp();
CompilerDirectives* _tmp_top; // temporary storage for dirs while parsing
static uint mask(keytype kt);
#ifndef PRODUCT
static void test(const char* json, bool valid);
public:
static bool test();
#endif
};
#endif // SHARE_VM_COMPILER_DIRECTIVESPARSER_HPP

View File

@ -342,6 +342,107 @@ void MethodMatcher::print_base(outputStream* st) {
}
}
BasicMatcher* BasicMatcher::parse_method_pattern(char* line, const char*& error_msg) {
assert(error_msg == NULL, "Don't call here with error_msg already set");
BasicMatcher* bm = new BasicMatcher();
MethodMatcher::parse_method_pattern(line, error_msg, bm);
if (error_msg != NULL) {
delete bm;
return NULL;
}
// check for bad trailing characters
int bytes_read = 0;
sscanf(line, "%*[ \t]%n", &bytes_read);
if (line[bytes_read] != '\0') {
error_msg = "Unrecognized trailing text after method pattern";
delete bm;
return NULL;
}
return bm;
}
bool BasicMatcher::match(methodHandle method) {
for (BasicMatcher* current = this; current != NULL; current = current->next()) {
if (current->matches(method)) {
return true;
}
}
return false;
}
void InlineMatcher::print(outputStream* st) {
if (_inline_action == InlineMatcher::force_inline) {
st->print("+");
} else {
st->print("-");
}
print_base(st);
}
InlineMatcher* InlineMatcher::parse_method_pattern(char* line, const char*& error_msg) {
assert(error_msg == NULL, "Dont call here with error_msg already set");
InlineMatcher* im = new InlineMatcher();
MethodMatcher::parse_method_pattern(line, error_msg, im);
if (error_msg != NULL) {
delete im;
return NULL;
}
return im;
}
bool InlineMatcher::match(methodHandle method, int inline_action) {
for (InlineMatcher* current = this; current != NULL; current = current->next()) {
if (current->matches(method)) {
return (current->_inline_action == inline_action);
}
}
return false;
}
InlineMatcher* InlineMatcher::parse_inline_pattern(char* str, const char*& error_msg) {
// check first token is +/-
InlineType _inline_action;
switch (str[0]) {
case '-':
_inline_action = InlineMatcher::dont_inline;
break;
case '+':
_inline_action = InlineMatcher::force_inline;
break;
default:
error_msg = "Missing leading inline type (+/-)";
return NULL;
}
str++;
int bytes_read = 0;
assert(error_msg== NULL, "error_msg must not be set yet");
InlineMatcher* im = InlineMatcher::parse_method_pattern(str, error_msg);
if (im == NULL) {
assert(error_msg != NULL, "Must have error message");
return NULL;
}
im->set_action(_inline_action);
return im;
}
InlineMatcher* InlineMatcher::clone() {
InlineMatcher* m = new InlineMatcher();
m->_class_mode = _class_mode;
m->_method_mode = _method_mode;
m->_inline_action = _inline_action;
m->_class_name = _class_name;
if(_class_name != NULL) {
_class_name->increment_refcount();
}
m->_method_name = _method_name;
if (_method_name != NULL) {
_method_name->increment_refcount();
}
m->_signature = _signature;
if (_signature != NULL) {
_signature->increment_refcount();
}
return m;
}

View File

@ -81,35 +81,8 @@ public:
_next(next) {
}
static BasicMatcher* parse_method_pattern(char* line, const char*& error_msg) {
assert(error_msg == NULL, "Dont call here with error_msg already set");
BasicMatcher* bm = new BasicMatcher();
MethodMatcher::parse_method_pattern(line, error_msg, bm);
if (error_msg != NULL) {
delete bm;
return NULL;
}
// check for bad trailing characters
int bytes_read = 0;
sscanf(line, "%*[ \t]%n", &bytes_read);
if (line[bytes_read] != '\0') {
error_msg = "Unrecognized trailing text after method pattern";
delete bm;
return NULL;
}
return bm;
}
bool match(methodHandle method) {
for (BasicMatcher* current = this; current != NULL; current = current->next()) {
if (current->matches(method)) {
return true;
}
}
return false;
}
static BasicMatcher* parse_method_pattern(char* line, const char*& error_msg);
bool match(methodHandle method);
void set_next(BasicMatcher* next) { _next = next; }
BasicMatcher* next() { return _next; }
@ -122,5 +95,33 @@ public:
}
};
class InlineMatcher : public MethodMatcher {
public:
enum InlineType {
unknown_inline,
dont_inline,
force_inline
};
private:
InlineType _inline_action;
InlineMatcher * _next;
InlineMatcher() : MethodMatcher(),
_inline_action(unknown_inline), _next(NULL) {
}
public:
static InlineMatcher* parse_method_pattern(char* line, const char*& error_msg);
bool match(methodHandle method, int inline_action);
void print(outputStream* st);
void set_next(InlineMatcher* next) { _next = next; }
InlineMatcher* next() { return _next; }
void set_action(InlineType inline_action) { _inline_action = inline_action; }
int inline_action() { return _inline_action; }
static InlineMatcher* parse_inline_pattern(char* line, const char*& error_msg);
InlineMatcher* clone();
};
#endif // SHARE_VM_COMPILER_METHODMATCHER_HPP

View File

@ -145,7 +145,7 @@ void JVMCICompiler::compile_method(methodHandle method, int entry_bci, JVMCIEnv*
// Compilation entry point for methods
void JVMCICompiler::compile_method(ciEnv* env, ciMethod* target, int entry_bci) {
void JVMCICompiler::compile_method(ciEnv* env, ciMethod* target, int entry_bci, DirectiveSet* directive) {
ShouldNotReachHere();
}

View File

@ -69,7 +69,7 @@ public:
void bootstrap();
// Compilation entry point for methods
virtual void compile_method(ciEnv* env, ciMethod* target, int entry_bci);
virtual void compile_method(ciEnv* env, ciMethod* target, int entry_bci, DirectiveSet* directive);
void compile_method(methodHandle target, int entry_bci, JVMCIEnv* env);

View File

@ -25,6 +25,7 @@
#include "precompiled.hpp"
#include "libadt/vectset.hpp"
#include "memory/allocation.inline.hpp"
#include "compiler/compilerDirectives.hpp"
#include "opto/block.hpp"
#include "opto/cfgnode.hpp"
#include "opto/chaitin.hpp"
@ -365,7 +366,7 @@ PhaseCFG::PhaseCFG(Arena* arena, RootNode* root, Matcher& matcher)
, _node_to_block_mapping(arena)
, _node_latency(NULL)
#ifndef PRODUCT
, _trace_opto_pipelining(TraceOptoPipelining || C->method_has_option("TraceOptoPipelining"))
, _trace_opto_pipelining(C->directive()->TraceOptoPipeliningOption)
#endif
#ifdef ASSERT
, _raw_oops(arena)

View File

@ -368,7 +368,6 @@ public:
class PhaseCFG : public Phase {
friend class VMStructs;
private:
// Root of whole program
RootNode* _root;

View File

@ -108,7 +108,7 @@ bool InlineTree::should_inline(ciMethod* callee_method, ciMethod* caller_method,
int caller_bci, ciCallProfile& profile,
WarmCallInfo* wci_result) {
// Allows targeted inlining
if (callee_method->should_inline()) {
if (C->directive()->should_inline(callee_method)) {
*wci_result = *(WarmCallInfo::always_hot());
if (C->print_inlining() && Verbose) {
CompileTask::print_inline_indent(inline_level());
@ -222,12 +222,12 @@ bool InlineTree::should_not_inline(ciMethod *callee_method,
}
// ignore heuristic controls on inlining
if (callee_method->should_inline()) {
if (C->directive()->should_inline(callee_method)) {
set_msg("force inline by CompileCommand");
return false;
}
if (callee_method->should_not_inline()) {
if (C->directive()->should_not_inline(callee_method)) {
set_msg("disallowed by CompileCommand");
return true;
}

View File

@ -154,7 +154,7 @@
notproduct(bool, PrintOptoStatistics, false, \
"Print New compiler statistics") \
\
notproduct(bool, PrintOptoAssembly, false, \
diagnostic(bool, PrintOptoAssembly, false, \
"Print New compiler assembly output") \
\
develop_pd(bool, OptoPeephole, \
@ -632,7 +632,7 @@
develop(bool, PrintDominators, false, \
"Print out dominator trees for GVN") \
\
notproduct(bool, TraceSpilling, false, \
diagnostic(bool, TraceSpilling, false, \
"Trace spilling") \
\
diagnostic(bool, TraceTypeProfile, false, \

View File

@ -94,15 +94,16 @@ void C2Compiler::initialize() {
}
}
void C2Compiler::compile_method(ciEnv* env, ciMethod* target, int entry_bci) {
void C2Compiler::compile_method(ciEnv* env, ciMethod* target, int entry_bci, DirectiveSet* directive) {
assert(is_initialized(), "Compiler thread must be initialized");
bool subsume_loads = SubsumeLoads;
bool do_escape_analysis = DoEscapeAnalysis && !env->should_retain_local_variables();
bool eliminate_boxing = EliminateAutoBox;
while (!env->failing()) {
// Attempt to compile while subsuming loads into machine instructions.
Compile C(env, this, target, entry_bci, subsume_loads, do_escape_analysis, eliminate_boxing);
Compile C(env, this, target, entry_bci, subsume_loads, do_escape_analysis, eliminate_boxing, directive);
// Check result and retry if appropriate.
if (C.failure_reason() != NULL) {

View File

@ -41,7 +41,8 @@ public:
// Compilation entry point for methods
void compile_method(ciEnv* env,
ciMethod* target,
int entry_bci);
int entry_bci,
DirectiveSet* directive);
// sentinel value used to trigger backtracking in compile_method().
static const char* retry_no_subsuming_loads();

View File

@ -211,7 +211,7 @@ PhaseChaitin::PhaseChaitin(uint unique, PhaseCFG &cfg, Matcher &matcher, bool sc
, _scratch_int_pressure(0, INTPRESSURE)
, _scratch_float_pressure(0, FLOATPRESSURE)
#ifndef PRODUCT
, _trace_spilling(TraceSpilling || C->method_has_option("TraceSpilling"))
, _trace_spilling(C->directive()->TraceSpillingOption)
#endif
{
Compile::TracePhase tp("ctorChaitin", &timers[_t_ctorChaitin]);

View File

@ -464,7 +464,7 @@ CompileWrapper::CompileWrapper(Compile* compile) : _compile(compile) {
Type::Initialize(compile);
_compile->set_scratch_buffer_blob(NULL);
_compile->begin_method();
_compile->clone_map().set_debug(_compile->has_method() && _compile->method_has_option(_compile->clone_map().debug_option_name));
_compile->clone_map().set_debug(_compile->has_method() && _compile->directive()->CloneMapDebugOption);
}
CompileWrapper::~CompileWrapper() {
_compile->end_method();
@ -496,7 +496,7 @@ void Compile::print_compile_messages() {
tty->print_cr("** Bailout: Recompile without boxing elimination **");
tty->print_cr("*********************************************************");
}
if (env()->break_at_compile()) {
if (C->directive()->BreakAtCompileOption) {
// Open the debugger when compiling this method.
tty->print("### Breaking when compiling: ");
method()->print_short_name();
@ -617,9 +617,10 @@ debug_only( int Compile::_debug_idx = 100000; )
Compile::Compile( ciEnv* ci_env, C2Compiler* compiler, ciMethod* target, int osr_bci,
bool subsume_loads, bool do_escape_analysis, bool eliminate_boxing )
bool subsume_loads, bool do_escape_analysis, bool eliminate_boxing, DirectiveSet* directive)
: Phase(Compiler),
_env(ci_env),
_directive(directive),
_log(ci_env->log()),
_compile_id(ci_env->compile_id()),
_save_argument_registers(false),
@ -649,7 +650,7 @@ Compile::Compile( ciEnv* ci_env, C2Compiler* compiler, ciMethod* target, int osr
_dead_node_list(comp_arena()),
_dead_node_count(0),
#ifndef PRODUCT
_trace_opto_output(TraceOptoOutput || method()->has_option("TraceOptoOutput")),
_trace_opto_output(directive->TraceOptoOutputOption),
_in_dump_cnt(0),
_printer(IdealGraphPrinter::printer()),
#endif
@ -673,7 +674,11 @@ Compile::Compile( ciEnv* ci_env, C2Compiler* compiler, ciMethod* target, int osr
_interpreter_frame_size(0),
_max_node_limit(MaxNodeLimit) {
C = this;
#ifndef PRODUCT
if (_printer != NULL) {
_printer->set_compile(this);
}
#endif
CompileWrapper cw(this);
if (CITimeVerbose) {
@ -687,9 +692,9 @@ Compile::Compile( ciEnv* ci_env, C2Compiler* compiler, ciMethod* target, int osr
TraceTime t2(NULL, &_t_methodCompilation, CITime, false);
#ifndef PRODUCT
bool print_opto_assembly = PrintOptoAssembly || _method->has_option("PrintOptoAssembly");
bool print_opto_assembly = directive->PrintOptoAssemblyOption;
if (!print_opto_assembly) {
bool print_assembly = (PrintAssembly || _method->should_print_assembly());
bool print_assembly = directive->PrintAssemblyOption;
if (print_assembly && !Disassembler::can_decode()) {
tty->print_cr("PrintAssembly request changed to PrintOptoAssembly");
print_opto_assembly = true;
@ -698,12 +703,12 @@ Compile::Compile( ciEnv* ci_env, C2Compiler* compiler, ciMethod* target, int osr
set_print_assembly(print_opto_assembly);
set_parsed_irreducible_loop(false);
if (method()->has_option("ReplayInline")) {
if (directive->ReplayInlineOption) {
_replay_inline_data = ciReplay::load_inline_data(method(), entry_bci(), ci_env->comp_level());
}
#endif
set_print_inlining(PrintInlining || method()->has_option("PrintInlining") NOT_PRODUCT( || PrintOptoInlining));
set_print_intrinsics(PrintIntrinsics || method()->has_option("PrintIntrinsics"));
set_print_inlining(directive->PrintInliningOption NOT_PRODUCT( || PrintOptoInlining));
set_print_intrinsics(directive->PrintIntrinsicsOption);
set_has_irreducible_loop(true); // conservative until build_loop_tree() reset it
if (ProfileTraps RTM_OPT_ONLY( || UseRTMLocking )) {
@ -837,8 +842,8 @@ Compile::Compile( ciEnv* ci_env, C2Compiler* compiler, ciMethod* target, int osr
// Drain the list.
Finish_Warm();
#ifndef PRODUCT
if (_printer && _printer->should_print(_method)) {
_printer->print_inlining(this);
if (_printer && _printer->should_print(1)) {
_printer->print_inlining();
}
#endif
@ -871,10 +876,10 @@ Compile::Compile( ciEnv* ci_env, C2Compiler* compiler, ciMethod* target, int osr
NOT_PRODUCT( verify_barriers(); )
// Dump compilation data to replay it.
if (method()->has_option("DumpReplay")) {
if (directive->DumpReplayOption) {
env()->dump_replay_data(_compile_id);
}
if (method()->has_option("DumpInline") && (ilt() != NULL)) {
if (directive->DumpInlineOption && (ilt() != NULL)) {
env()->dump_inline_data(_compile_id);
}
@ -918,9 +923,9 @@ Compile::Compile( ciEnv* ci_env, C2Compiler* compiler, ciMethod* target, int osr
frame_size_in_words(), _oop_map_set,
&_handler_table, &_inc_table,
compiler,
env()->comp_level(),
has_unsafe_access(),
SharedRuntime::is_wide_vector(max_vector_size()),
_directive,
rtm_state()
);
@ -938,9 +943,11 @@ Compile::Compile( ciEnv* ci_env,
int is_fancy_jump,
bool pass_tls,
bool save_arg_registers,
bool return_pc )
bool return_pc,
DirectiveSet* directive)
: Phase(Compiler),
_env(ci_env),
_directive(directive),
_log(ci_env->log()),
_compile_id(0),
_save_argument_registers(save_arg_registers),
@ -1090,7 +1097,7 @@ void Compile::Init(int aliaslevel) {
Copy::zero_to_bytes(_trap_hist, sizeof(_trap_hist));
set_decompile_count(0);
set_do_freq_based_layout(BlockLayoutByFrequency || method_has_option("BlockLayoutByFrequency"));
set_do_freq_based_layout(_directive->BlockLayoutByFrequencyOption);
set_num_loop_opts(LoopOptsCount);
set_do_inlining(Inline);
set_max_inline_size(MaxInlineSize);
@ -1103,7 +1110,7 @@ void Compile::Init(int aliaslevel) {
bool do_vector = false;
if (AllowVectorizeOnDemand) {
if (has_method() && (method()->has_option("Vectorize") || method()->has_option("VectorizeDebug"))) {
if (has_method() && (_directive->VectorizeOption || _directive->VectorizeDebugOption)) {
set_do_vector_loop(true);
} else if (has_method() && method()->name() != 0 &&
method()->intrinsic_id() == vmIntrinsics::_forEachRemaining) {
@ -1118,7 +1125,8 @@ void Compile::Init(int aliaslevel) {
set_age_code(has_method() && method()->profile_aging());
set_rtm_state(NoRTM); // No RTM lock eliding by default
method_has_option_value("MaxNodeLimit", _max_node_limit);
_max_node_limit = _directive->MaxNodeLimitOption;
#if INCLUDE_RTM_OPT
if (UseRTMLocking && has_method() && (method()->method_data_or_null() != NULL)) {
int rtm_state = method()->method_data()->rtm_state();
@ -2091,7 +2099,7 @@ void Compile::Optimize() {
TracePhase tp("optimizer", &timers[_t_optimizer]);
#ifndef PRODUCT
if (env()->break_at_compile()) {
if (_directive->BreakAtCompileOption) {
BREAKPOINT;
}
@ -4357,7 +4365,6 @@ bool Compile::randomized_select(int count) {
return (os::random() & RANDOMIZED_DOMAIN_MASK) < (RANDOMIZED_DOMAIN / count);
}
const char* CloneMap::debug_option_name = "CloneMapDebug";
CloneMap& Compile::clone_map() { return _clone_map; }
void Compile::set_clone_map(Dict* d) { _clone_map._dict = d; }

View File

@ -391,6 +391,7 @@ class Compile : public Phase {
// Compilation environment.
Arena _comp_arena; // Arena with lifetime equivalent to Compile
ciEnv* _env; // CI interface
DirectiveSet* _directive; // Compiler directive
CompileLog* _log; // from CompilerThread
const char* _failure_reason; // for record_failure/failing pattern
GrowableArray<CallGenerator*>* _intrinsics; // List of intrinsics.
@ -527,6 +528,10 @@ class Compile : public Phase {
print_inlining_stream()->print("%s", ss.as_string());
}
#ifndef PRODUCT
IdealGraphPrinter* printer() { return _printer; }
#endif
void log_late_inline(CallGenerator* cg);
void log_inline_id(CallGenerator* cg);
void log_inline_failure(const char* msg);
@ -578,6 +583,7 @@ class Compile : public Phase {
// ID for this compilation. Useful for setting breakpoints in the debugger.
int compile_id() const { return _compile_id; }
DirectiveSet* directive() const { return _directive; }
// Does this compilation allow instructions to subsume loads? User
// instructions that subsume a load may result in an unschedulable
@ -671,10 +677,7 @@ class Compile : public Phase {
bool method_has_option(const char * option) {
return method() != NULL && method()->has_option(option);
}
template<typename T>
bool method_has_option_value(const char * option, T& value) {
return method() != NULL && method()->has_option_value(option, value);
}
#ifndef PRODUCT
bool trace_opto_output() const { return _trace_opto_output; }
bool parsed_irreducible_loop() const { return _parsed_irreducible_loop; }
@ -692,8 +695,8 @@ class Compile : public Phase {
void begin_method() {
#ifndef PRODUCT
if (_printer && _printer->should_print(_method)) {
_printer->begin_method(this);
if (_printer && _printer->should_print(1)) {
_printer->begin_method();
}
#endif
C->_latest_stage_start_counter.stamp();
@ -711,8 +714,8 @@ class Compile : public Phase {
#ifndef PRODUCT
if (_printer && _printer->should_print(_method)) {
_printer->print_method(this, CompilerPhaseTypeHelper::to_string(cpt), level);
if (_printer && _printer->should_print(level)) {
_printer->print_method(CompilerPhaseTypeHelper::to_string(cpt), level);
}
#endif
C->_latest_stage_start_counter.stamp();
@ -728,7 +731,7 @@ class Compile : public Phase {
event.commit();
}
#ifndef PRODUCT
if (_printer && _printer->should_print(_method)) {
if (_printer && _printer->should_print(level)) {
_printer->end_method();
}
#endif
@ -1107,7 +1110,7 @@ class Compile : public Phase {
// continuation.
Compile(ciEnv* ci_env, C2Compiler* compiler, ciMethod* target,
int entry_bci, bool subsume_loads, bool do_escape_analysis,
bool eliminate_boxing);
bool eliminate_boxing, DirectiveSet* directive);
// Second major entry point. From the TypeFunc signature, generate code
// to pass arguments from the Java calling convention to the C calling
@ -1115,7 +1118,7 @@ class Compile : public Phase {
Compile(ciEnv* ci_env, const TypeFunc *(*gen)(),
address stub_function, const char *stub_name,
int is_fancy_jump, bool pass_tls,
bool save_arg_registers, bool return_pc);
bool save_arg_registers, bool return_pc, DirectiveSet* directive);
// From the TypeFunc signature, generate code to pass arguments
// from Compiled calling convention to Interpreter's calling convention

View File

@ -292,11 +292,11 @@ void IdealGraphPrinter::print_inline_tree(InlineTree *tree) {
}
void IdealGraphPrinter::print_inlining(Compile* compile) {
void IdealGraphPrinter::print_inlining() {
// Print inline tree
if (_should_send_method) {
InlineTree *inlineTree = compile->ilt();
InlineTree *inlineTree = C->ilt();
if (inlineTree != NULL) {
print_inline_tree(inlineTree);
} else {
@ -306,9 +306,9 @@ void IdealGraphPrinter::print_inlining(Compile* compile) {
}
// Has to be called whenever a method is compiled
void IdealGraphPrinter::begin_method(Compile* compile) {
void IdealGraphPrinter::begin_method() {
ciMethod *method = compile->method();
ciMethod *method = C->method();
assert(_output, "output stream must exist!");
assert(method, "null methods are not allowed!");
assert(!_current_method, "current method must be null!");
@ -662,16 +662,14 @@ void IdealGraphPrinter::walk_nodes(Node *start, bool edges, VectorSet* temp_set)
}
}
void IdealGraphPrinter::print_method(Compile* compile, const char *name, int level, bool clear_nodes) {
print(compile, name, (Node *)compile->root(), level, clear_nodes);
void IdealGraphPrinter::print_method(const char *name, int level, bool clear_nodes) {
print(name, (Node *)C->root(), level, clear_nodes);
}
// Print current ideal graph
void IdealGraphPrinter::print(Compile* compile, const char *name, Node *node, int level, bool clear_nodes) {
void IdealGraphPrinter::print(const char *name, Node *node, int level, bool clear_nodes) {
if (!_current_method || !_should_send_method || !should_print(_current_method, level)) return;
this->C = compile;
if (!_current_method || !_should_send_method || !should_print(level)) return;
// Warning, unsafe cast?
_chaitin = (PhaseChaitin *)C->regalloc();
@ -722,10 +720,8 @@ void IdealGraphPrinter::print(Compile* compile, const char *name, Node *node, in
}
// Should method be printed?
bool IdealGraphPrinter::should_print(ciMethod* method, int level) {
intx ideal_graph_level = PrintIdealGraphLevel;
method->has_option_value("PrintIdealGraphLevel", ideal_graph_level); // update value with per-method value (if available)
return ideal_graph_level >= level;
bool IdealGraphPrinter::should_print(int level) {
return C->directive()->IGVPrintLevelOption >= level;
}
extern const char *NodeClassNames[];

View File

@ -127,13 +127,14 @@ class IdealGraphPrinter : public CHeapObj<mtCompiler> {
bool traverse_outs();
void set_traverse_outs(bool b);
void print_inlining(Compile* compile);
void begin_method(Compile* compile);
void print_inlining();
void begin_method();
void end_method();
void print_method(Compile* compile, const char *name, int level=1, bool clear_nodes = false);
void print(Compile* compile, const char *name, Node *root, int level=1, bool clear_nodes = false);
void print_method(const char *name, int level=1, bool clear_nodes = false);
void print(const char *name, Node *root, int level=1, bool clear_nodes = false);
void print_xml(const char *name);
static bool should_print(ciMethod* method, int level = 1);
bool should_print(int level);
void set_compile(Compile* compile) {C = compile; }
};
#endif

View File

@ -326,9 +326,10 @@ CallGenerator* Compile::make_vm_intrinsic(ciMethod* m, bool is_virtual) {
// methods access VM-internal data.
VM_ENTRY_MARK;
methodHandle mh(THREAD, m->get_Method());
methodHandle ct(THREAD, method()->get_Method());
is_available = compiler->is_intrinsic_supported(mh, is_virtual) &&
!vmIntrinsics::is_disabled_by_flags(mh, ct);
!C->directive()->is_intrinsic_disabled(mh) &&
!vmIntrinsics::is_disabled_by_flags(mh);
}
if (is_available) {

View File

@ -28,6 +28,7 @@
#include "code/debugInfo.hpp"
#include "code/debugInfoRec.hpp"
#include "compiler/compileBroker.hpp"
#include "compiler/compilerDirectives.hpp"
#include "compiler/oopMap.hpp"
#include "memory/allocation.inline.hpp"
#include "opto/ad.hpp"
@ -89,9 +90,8 @@ void Compile::Output() {
}
// Break before main entry point
if( (_method && _method->break_at_execute())
if( (_method && C->directive()->BreakAtExecuteOption)
#ifndef PRODUCT
||(OptoBreakpoint && is_method_compilation())
||(OptoBreakpointOSR && is_osr_compilation())

View File

@ -2378,13 +2378,13 @@ void Parse::do_one_bytecode() {
}
#ifndef PRODUCT
IdealGraphPrinter *printer = IdealGraphPrinter::printer();
if (printer && printer->should_print(_method)) {
IdealGraphPrinter *printer = C->printer();
if (printer && printer->should_print(1)) {
char buffer[256];
sprintf(buffer, "Bytecode %d: %s", bci(), Bytecodes::name(bc()));
bool old = printer->traverse_outs();
printer->set_traverse_outs(true);
printer->print_method(C, buffer, 4);
printer->print_method(buffer, 4);
printer->set_traverse_outs(old);
}
#endif

View File

@ -159,9 +159,13 @@ address OptoRuntime::generate_stub( ciEnv* env,
const char *name, int is_fancy_jump,
bool pass_tls,
bool save_argument_registers,
bool return_pc ) {
bool return_pc) {
// Matching the default directive, we currently have no method to match.
DirectiveSet* directive = DirectivesStack::getDefaultDirective(CompileBroker::compiler(CompLevel_full_optimization));
ResourceMark rm;
Compile C( env, gen, C_function, name, is_fancy_jump, pass_tls, save_argument_registers, return_pc );
Compile C( env, gen, C_function, name, is_fancy_jump, pass_tls, save_argument_registers, return_pc, directive);
DirectivesStack::release(directive);
return C.stub_entry_point();
}

View File

@ -79,11 +79,12 @@ SuperWord::SuperWord(PhaseIdealLoop* phase) :
#ifndef PRODUCT
_vector_loop_debug = 0;
if (_phase->C->method() != NULL) {
_phase->C->method()->has_option_value("VectorizeDebug", _vector_loop_debug);
_vector_loop_debug = phase->C->directive()->VectorizeDebugOption;
}
_CountedLoopReserveKit_debug = 0;
if (_phase->C->method() != NULL) {
_phase->C->method()->has_option_value("DoReserveCopyInSuperWordDebug", _CountedLoopReserveKit_debug);
_CountedLoopReserveKit_debug = phase->C->directive()->DoReserveCopyInSuperWordDebugOption;
}
#endif
}

View File

@ -3840,7 +3840,9 @@ _JNI_IMPORT_OR_EXPORT_ jint JNICALL JNI_GetDefaultJavaVMInitArgs(void *args_) {
#if INCLUDE_ALL_GCS
#include "gc/g1/heapRegionRemSet.hpp"
#endif
#include "compiler/directivesParser.hpp"
#include "memory/guardedMemory.hpp"
#include "utilities/json.hpp"
#include "utilities/ostream.hpp"
#include "utilities/quickSort.hpp"
#if INCLUDE_VM_STRUCTS
@ -3903,6 +3905,8 @@ void execute_internal_vm_tests() {
run_unit_test(ObjectMonitor::sanity_checks());
run_unit_test(Test_linked_list());
run_unit_test(TestChunkedList_test());
run_unit_test(JSONTest::test());
run_unit_test(DirectivesParser::test());
#if INCLUDE_VM_STRUCTS
run_unit_test(VMStructs::test());
#endif

View File

@ -551,14 +551,20 @@ WB_ENTRY(jboolean, WB_IsIntrinsicAvailable(JNIEnv* env, jobject o, jobject metho
method_id = reflected_method_to_jmid(thread, env, method);
CHECK_JNI_EXCEPTION_(env, JNI_FALSE);
methodHandle mh(THREAD, Method::checked_resolve_jmethod_id(method_id));
DirectiveSet* directive;
if (compilation_context != NULL) {
compilation_context_id = reflected_method_to_jmid(thread, env, compilation_context);
CHECK_JNI_EXCEPTION_(env, JNI_FALSE);
methodHandle cch(THREAD, Method::checked_resolve_jmethod_id(compilation_context_id));
return CompileBroker::compiler(compLevel)->is_intrinsic_available(mh, cch);
directive = DirectivesStack::getMatchingDirective(cch, CompileBroker::compiler((int)compLevel));
} else {
return CompileBroker::compiler(compLevel)->is_intrinsic_available(mh, NULL);
// Calling with NULL matches default directive
directive = DirectivesStack::getDefaultDirective(CompileBroker::compiler((int)compLevel));
}
bool result = CompileBroker::compiler(compLevel)->is_intrinsic_available(mh, directive);
DirectivesStack::release(directive);
return result;
WB_END
WB_ENTRY(jint, WB_GetMethodCompilationLevel(JNIEnv* env, jobject o, jobject method, jboolean is_osr))
@ -624,6 +630,47 @@ WB_ENTRY(jboolean, WB_EnqueueMethodForCompilation(JNIEnv* env, jobject o, jobjec
return (mh->queued_for_compilation() || nm != NULL);
WB_END
WB_ENTRY(jboolean, WB_ShouldPrintAssembly(JNIEnv* env, jobject o, jobject method))
jmethodID jmid = reflected_method_to_jmid(thread, env, method);
CHECK_JNI_EXCEPTION_(env, JNI_FALSE);
methodHandle mh(THREAD, Method::checked_resolve_jmethod_id(jmid));
DirectiveSet* directive = DirectivesStack::getMatchingDirective(mh, CompileBroker::compiler(CompLevel_simple));
bool result = directive->PrintAssemblyOption;
DirectivesStack::release(directive);
return result;
WB_END
WB_ENTRY(jint, WB_MatchesInline(JNIEnv* env, jobject o, jobject method, jstring pattern))
jmethodID jmid = reflected_method_to_jmid(thread, env, method);
CHECK_JNI_EXCEPTION_(env, JNI_FALSE);
methodHandle mh(THREAD, Method::checked_resolve_jmethod_id(jmid));
ResourceMark rm;
const char* error_msg = NULL;
char* method_str = java_lang_String::as_utf8_string(JNIHandles::resolve_non_null(pattern));
InlineMatcher* m = InlineMatcher::parse_inline_pattern(method_str, error_msg);
if (m == NULL) {
assert(error_msg != NULL, "Always have an error message");
tty->print_cr("Got error: %s", error_msg);
return -1; // Pattern failed
}
// Pattern works - now check if it matches
int result;
if (m->match(mh, InlineMatcher::force_inline)) {
result = 2; // Force inline match
} else if (m->match(mh, InlineMatcher::dont_inline)) {
result = 1; // Dont inline match
} else {
result = 0; // No match
}
delete m;
return result;
WB_END
WB_ENTRY(jint, WB_MatchesMethod(JNIEnv* env, jobject o, jobject method, jstring pattern))
jmethodID jmid = reflected_method_to_jmid(thread, env, method);
@ -1475,6 +1522,13 @@ static JNINativeMethod methods[] = {
{CC"matchesMethod",
CC"(Ljava/lang/reflect/Executable;Ljava/lang/String;)I",
(void*)&WB_MatchesMethod},
{CC"matchesInline",
CC"(Ljava/lang/reflect/Executable;Ljava/lang/String;)I",
(void*)&WB_MatchesInline},
{CC"shouldPrintAssembly",
CC"(Ljava/lang/reflect/Executable;)Z",
(void*)&WB_ShouldPrintAssembly},
{CC"isConstantVMFlag", CC"(Ljava/lang/String;)Z", (void*)&WB_IsConstantVMFlag},
{CC"isLockedVMFlag", CC"(Ljava/lang/String;)Z", (void*)&WB_IsLockedVMFlag},
{CC"setBooleanVMFlag", CC"(Ljava/lang/String;Z)V",(void*)&WB_SetBooleanVMFlag},

View File

@ -3650,6 +3650,9 @@ public:
product(ccstr, CompileCommandFile, NULL, \
"Read compiler commands from this file [.hotspot_compiler]") \
\
diagnostic(ccstr, CompilerDirectivesFile, NULL, \
"Read compiler directives from this file") \
\
product(ccstrlist, CompileCommand, "", \
"Prepend to .hotspot_compiler; e.g. log,java/lang/String.<init>") \
\
@ -4233,7 +4236,13 @@ public:
"(3) no orphan methods exist for class C (i.e., methods for " \
"which the VM declares an intrinsic but that are not declared "\
"in the loaded class C. " \
"Check (3) is available only in debug builds.")
"Check (3) is available only in debug builds.") \
\
diagnostic(bool, CompilerDirectivesIgnoreCompileCommands, false, \
"Disable backwards compatibility for compile commands.") \
\
diagnostic(bool, PrintCompilerDirectives, false, \
"Print compiler directives on installation.")
/*
* Macros for factoring of globals

View File

@ -71,7 +71,7 @@ void vmStructs_init();
void vtableStubs_init();
void InlineCacheBuffer_init();
void compilerOracle_init();
void compileBroker_init();
bool compileBroker_init();
// Initialization after compiler initialization
bool universe_post_init(); // must happen after compiler_init
@ -131,7 +131,9 @@ jint init_globals() {
vtableStubs_init();
InlineCacheBuffer_init();
compilerOracle_init();
compileBroker_init();
if (!compileBroker_init()) {
return JNI_EINVAL;
}
VMRegImpl::set_regName();
if (!universe_post_init()) {

View File

@ -90,6 +90,7 @@ Monitor* CompileThread_lock = NULL;
Monitor* Compilation_lock = NULL;
Mutex* CompileTaskAlloc_lock = NULL;
Mutex* CompileStatistics_lock = NULL;
Mutex* DirectivesStack_lock = NULL;
Mutex* MultiArray_lock = NULL;
Monitor* Terminator_lock = NULL;
Monitor* BeforeExit_lock = NULL;
@ -264,6 +265,7 @@ void mutex_init() {
def(CompiledIC_lock , Mutex , nonleaf+2, false, Monitor::_safepoint_check_always); // locks VtableStubs_lock, InlineCacheBuffer_lock
def(CompileTaskAlloc_lock , Mutex , nonleaf+2, true, Monitor::_safepoint_check_always);
def(CompileStatistics_lock , Mutex , nonleaf+2, false, Monitor::_safepoint_check_always);
def(DirectivesStack_lock , Mutex , special, true, Monitor::_safepoint_check_never);
def(MultiArray_lock , Mutex , nonleaf+2, false, Monitor::_safepoint_check_always); // locks SymbolTable_lock
def(JvmtiThreadState_lock , Mutex , nonleaf+2, false, Monitor::_safepoint_check_always); // Used by JvmtiThreadState/JvmtiEventController

View File

@ -93,6 +93,7 @@ extern Monitor* CompileThread_lock; // a lock held by compile threa
extern Monitor* Compilation_lock; // a lock used to pause compilation
extern Mutex* CompileTaskAlloc_lock; // a lock held when CompileTasks are allocated
extern Mutex* CompileStatistics_lock; // a lock held when updating compilation statistics
extern Mutex* DirectivesStack_lock; // a lock held when mutating the dirstack and ref counting directives
extern Mutex* MultiArray_lock; // a lock used to guard allocation of multi-dim arrays
extern Monitor* Terminator_lock; // a lock used to guard termination of the vm
extern Monitor* BeforeExit_lock; // a lock used to guard cleanups and shutdown hooks

View File

@ -2696,6 +2696,12 @@ void AdapterHandlerLibrary::create_native_wrapper(methodHandle method) {
if (nm != NULL) {
method->set_code(method, nm);
DirectiveSet* directive = DirectivesStack::getDefaultDirective(CompileBroker::compiler(CompLevel_simple));
if (directive->PrintAssemblyOption) {
Disassembler::decode(nm, tty);
}
DirectivesStack::release(directive);
}
}
} // Unlock AdapterHandlerLibrary_lock

View File

@ -28,7 +28,6 @@
#include "code/codeCache.hpp"
#include "code/codeCacheExtensions.hpp"
#include "compiler/compileBroker.hpp"
#include "compiler/compilerOracle.hpp"
#include "gc/shared/isGCActiveMark.hpp"
#include "memory/heapInspection.hpp"
#include "memory/resourceArea.hpp"

View File

@ -25,6 +25,8 @@
#include "precompiled.hpp"
#include "classfile/classLoaderStats.hpp"
#include "classfile/compactHashtable.hpp"
#include "compiler/compileBroker.hpp"
#include "compiler/directivesParser.hpp"
#include "gc/shared/vmGCOperations.hpp"
#include "oops/oop.inline.hpp"
#include "runtime/globals.hpp"
@ -77,6 +79,11 @@ void DCmdRegistrant::register_dcmds(){
DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<CodeCacheDCmd>(full_export, true, false));
DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<TouchedMethodsDCmd>(full_export, true, false));
DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<CompilerDirectivesPrintDCmd>(full_export, true, false));
DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<CompilerDirectivesAddDCmd>(full_export, true, false));
DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<CompilerDirectivesRemoveDCmd>(full_export, true, false));
DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<CompilerDirectivesClearDCmd>(full_export, true, false));
// Enhanced JMX Agent Support
// These commands won't be exported via the DiagnosticCommandMBean until an
// appropriate permission is created for them
@ -837,6 +844,38 @@ void CodeCacheDCmd::execute(DCmdSource source, TRAPS) {
VMThread::execute(&printCodeCacheOp);
}
void CompilerDirectivesPrintDCmd::execute(DCmdSource source, TRAPS) {
DirectivesStack::print(output());
}
CompilerDirectivesAddDCmd::CompilerDirectivesAddDCmd(outputStream* output, bool heap) :
DCmdWithParser(output, heap),
_filename("filename","Name of the directives file", "STRING",true) {
_dcmdparser.add_dcmd_argument(&_filename);
}
void CompilerDirectivesAddDCmd::execute(DCmdSource source, TRAPS) {
DirectivesParser::parse_from_file(_filename.value(), output());
}
int CompilerDirectivesAddDCmd::num_arguments() {
ResourceMark rm;
CompilerDirectivesAddDCmd* dcmd = new CompilerDirectivesAddDCmd(NULL, false);
if (dcmd != NULL) {
DCmdMark mark(dcmd);
return dcmd->_dcmdparser.num_arguments();
} else {
return 0;
}
}
void CompilerDirectivesRemoveDCmd::execute(DCmdSource source, TRAPS) {
DirectivesStack::pop();
}
void CompilerDirectivesClearDCmd::execute(DCmdSource source, TRAPS) {
DirectivesStack::clear();
}
#if INCLUDE_SERVICES
ClassHierarchyDCmd::ClassHierarchyDCmd(outputStream* output, bool heap) :
DCmdWithParser(output, heap),

View File

@ -613,4 +613,90 @@ public:
virtual void execute(DCmdSource source, TRAPS);
};
class CompilerDirectivesPrintDCmd : public DCmd {
public:
CompilerDirectivesPrintDCmd(outputStream* output, bool heap) : DCmd(output, heap) {}
static const char* name() {
return "Compiler.directives_print";
}
static const char* description() {
return "Print all active compiler directives.";
}
static const char* impact() {
return "Low";
}
static const JavaPermission permission() {
JavaPermission p = {"java.lang.management.ManagementPermission",
"monitor", NULL};
return p;
}
static int num_arguments() { return 0; }
virtual void execute(DCmdSource source, TRAPS);
};
class CompilerDirectivesRemoveDCmd : public DCmd {
public:
CompilerDirectivesRemoveDCmd(outputStream* output, bool heap) : DCmd(output, heap) {}
static const char* name() {
return "Compiler.directives_remove";
}
static const char* description() {
return "Remove latest added compiler directive.";
}
static const char* impact() {
return "Low";
}
static const JavaPermission permission() {
JavaPermission p = {"java.lang.management.ManagementPermission",
"monitor", NULL};
return p;
}
static int num_arguments() { return 0; }
virtual void execute(DCmdSource source, TRAPS);
};
class CompilerDirectivesAddDCmd : public DCmdWithParser {
protected:
DCmdArgument<char*> _filename;
public:
CompilerDirectivesAddDCmd(outputStream* output, bool heap);
static const char* name() {
return "Compiler.directives_add";
}
static const char* description() {
return "Add compiler directives from file.";
}
static const char* impact() {
return "Low";
}
static const JavaPermission permission() {
JavaPermission p = {"java.lang.management.ManagementPermission",
"monitor", NULL};
return p;
}
static int num_arguments();
virtual void execute(DCmdSource source, TRAPS);
};
class CompilerDirectivesClearDCmd : public DCmd {
public:
CompilerDirectivesClearDCmd(outputStream* output, bool heap) : DCmd(output, heap) {}
static const char* name() {
return "Compiler.directives_clear";
}
static const char* description() {
return "Remove all compiler directives.";
}
static const char* impact() {
return "Low";
}
static const JavaPermission permission() {
JavaPermission p = {"java.lang.management.ManagementPermission",
"monitor", NULL};
return p;
}
static int num_arguments() { return 0; }
virtual void execute(DCmdSource source, TRAPS);
};
#endif // SHARE_VM_SERVICES_DIAGNOSTICCOMMAND_HPP

View File

@ -145,7 +145,8 @@ void SharkCompiler::initialize() {
void SharkCompiler::compile_method(ciEnv* env,
ciMethod* target,
int entry_bci) {
int entry_bci,
DirectiveSet* directive) {
assert(is_initialized(), "should be");
ResourceMark rm;
const char *name = methodname(
@ -216,8 +217,8 @@ void SharkCompiler::compile_method(ciEnv* env,
&handler_table,
&inc_table,
this,
env->comp_level(),
false,
directive(),
false);
}

View File

@ -30,6 +30,7 @@
#include "ci/ciMethod.hpp"
#include "compiler/abstractCompiler.hpp"
#include "compiler/compileBroker.hpp"
#include "compiler/compilerDirectives.hpp"
#include "shark/llvmHeaders.hpp"
#include "shark/sharkMemoryManager.hpp"
@ -54,7 +55,7 @@ class SharkCompiler : public AbstractCompiler {
void initialize();
// Compile a normal (bytecode) method and install it in the VM
void compile_method(ciEnv* env, ciMethod* target, int entry_bci);
void compile_method(ciEnv* env, ciMethod* target, int entry_bci, DirectiveSet* dirset);
// Print compilation timers and statistics
void print_timers();

View File

@ -0,0 +1,956 @@
/*
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
/*
* This is not really json in the state it is now.
* Some differences:
* - Double quotes around the key in an object is not enforced.
* i.e you can write: { foo : "bar" } instead of { "foo" : "bar" }.
* - Comments are allowed.
* - The last element in an object or array can have an ending comma.
*/
#include "precompiled.hpp"
#include "utilities/json.hpp"
#include "utilities/ostream.hpp"
#include <math.h>
const char* strchrnul_(const char *s, int c) {
const char* tmp = strchr(s, c);
return tmp == NULL ? s + strlen(s) : tmp;
}
JSON::JSON(const char* text, bool silent, outputStream* st)
: start(text), pos(text), mark(text),
level(0), line(1), column(0), silent(silent), _valid(true), _st(st)
{
}
void JSON::parse() {
assert(start != NULL, "Need something to parse");
if (start == NULL) {
_valid = false;
error(INTERNAL_ERROR, "JSON parser was called with a string that was NULL.");
} else {
_valid = parse_json_value();
}
}
bool JSON::valid() {
return _valid;
}
bool JSON::parse_json_value() {
int c;
c = skip_to_token();
if (c == -1) {
return false;
}
// Must start with object or array
if (level == 0) {
switch (c) {
case '{':
if (parse_json_object() == false) {
return false;
}
c = skip_to_token();
if (c > 0) {
mark_pos();
error(SYNTAX_ERROR, "Only one top level object/array is allowed.");
return false;
} else if (c < 0) {
return false;
}
return true;
case '[':
if (parse_json_array() == false) {
return false;
}
c = skip_to_token();
if (c > 0) {
mark_pos();
error(SYNTAX_ERROR, "Only one top level object/array is allowed.");
return false;
} else if (c < 0) {
return false;
}
return true;
case 0:
error(SYNTAX_ERROR, "EOS was encountered before any json declarations");
return false;
default:
error(SYNTAX_ERROR, "Json must start with an object or an array.");
return false;
}
} else { // level > 0
switch (c) {
case '{':
return parse_json_object();
case '[':
return parse_json_array();
case '"':
return parse_json_string();
case '-': case '0':
case '1': case '2': case '3':
case '4': case '5': case '6':
case '7': case '8': case '9':
return parse_json_number();
case 't':
return parse_json_symbol("true", JSON_TRUE);
case 'f':
return parse_json_symbol("false", JSON_FALSE);
case 'n':
return parse_json_symbol("null", JSON_NULL);
case 0:
error(SYNTAX_ERROR, "EOS was encountered when expecting a json value.");
return false;
default:
error(SYNTAX_ERROR, "Could not parse as a json value (did you forget to quote your strings?).");
return false;
}
}
}
// Should only be called when we actually have the start of an object
// Otherwise it is an internal error
bool JSON::parse_json_object() {
NOT_PRODUCT(const char* prev_pos);
int c;
mark_pos();
// Check that we are not called in error
if (expect_any("{", "object start", INTERNAL_ERROR) <= 0) {
return false;
}
if (!callback(JSON_OBJECT_BEGIN, NULL, level++)) {
return false;
}
for (;;) {
mark_pos();
c = skip_to_token();
if (c == 0) {
error(SYNTAX_ERROR, "EOS when expecting an object key or object end");
return false;
} else if (c < 0) {
return false;
} else if (c == '}') {
// We got here from either empty object "{}" or ending comma "{a:1,}"
next();
break;
}
NOT_PRODUCT(prev_pos = pos);
if (parse_json_key() == false) {
return false;
}
assert(pos > prev_pos, "parsing stalled");
skip_to_token();
mark_pos();
if (expect_any(":", "object key-value separator") <= 0) {
return false;
}
skip_to_token();
mark_pos();
NOT_PRODUCT(prev_pos = pos);
if (parse_json_value() == false) {
return false;
}
assert(pos > prev_pos, "parsing stalled");
c = skip_to_token();
mark_pos();
if (expect_any(",}", "value separator or object end") <= 0) {
return false;
}
if (c == '}') {
break;
}
}
assert(c == '}', "array parsing ended without object end token ('}')");
return callback(JSON_OBJECT_END, NULL, --level);
}
// Should only be called when we actually have the start of an array
// Otherwise it is an internal error
bool JSON::parse_json_array() {
NOT_PRODUCT(const char* prev_pos);
int c;
mark_pos();
// Check that we are not called in error
if (expect_any("[", "array start character", INTERNAL_ERROR) <= 0) {
return false;
}
if (!callback(JSON_ARRAY_BEGIN, NULL, level++)) {
return false;
}
for (;;) {
mark_pos();
c = skip_to_token();
if (c == 0) {
error(SYNTAX_ERROR, "EOS when expecting a json value or array end");
return false;
} else if (c < 0) {
return false;
} else if (c == ']') {
// We got here from either empty array "[]" or ending comma "[1,]"
next();
break;
}
mark_pos();
NOT_PRODUCT(prev_pos = pos);
if (parse_json_value() == false) {
return false;
}
assert(pos > prev_pos, "parsing stalled");
c = skip_to_token();
mark_pos();
if (expect_any(",]", "value separator or array end") <= 0) {
return false;
}
if (c == ']') {
break;
}
}
assert(c == ']', "array parsing ended without array end token (']')");
return callback(JSON_ARRAY_END, NULL, --level);
}
bool JSON::parse_json_string(bool key) {
const char* end;
JSON_VAL v;
mark_pos();
if (expect_any("\"", "string start character", INTERNAL_ERROR) <= 0) {
return false;
}
end = strchr(pos, '"'); // TODO: escapes
if (end == NULL) {
error(SYNTAX_ERROR, "String started here never ended. Expected \'\"\' before EOS.");
return false;
}
v.str.start = pos;
v.str.length = end - pos;
skip(end - pos);
if (expect_any("\"", "string end character", INTERNAL_ERROR) <= 0) {
return false;
}
if (key == true) {
return callback(JSON_KEY, &v, level);
} else {
return callback(JSON_STRING, &v, level);
}
}
// TODO: hotspot equivalents?
static bool is_alpha(u_char c) {
return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z');
}
static bool is_numeric(u_char c) {
return (c >= '0' && c <= '9');
}
static bool is_alnum(u_char c) {
return is_alpha(c) || is_numeric(c);
}
static bool is_word(u_char c) {
return c == '_' || is_alnum(c);
}
// Allow object keys to be without quotation,
// but then restrict to ([a-zA-Z0-9_])+
bool JSON::parse_json_key() {
const char* begin;
JSON_VAL v;
u_char c;
mark_pos();
c = peek();
if (c == '"') {
return parse_json_string(true);
}
begin = pos;
c = peek();
if (c == 0) {
error(SYNTAX_ERROR, "Got EOS when expecting an object key.");
return false;
} else if (is_word(c) == false) {
error(SYNTAX_ERROR, "Expected an object key, which can be a double-quoted (\") string or a simple string (only alphanumeric characters and underscore, separated by whitespace) that doesn't need to be quoted.");
return false;
}
for (;;) {
c = peek();
// Allow the key to be delimited by control characters and the object key-value separator ':'
if (c <= ' ' || c == ':') {
break;
} else if (is_word(c) == false) {
error(SYNTAX_ERROR, "Object key need to be quoted, or consist entirely of alphanumeric characters and underscores.");
return false;
}
next();
}
v.str.start = begin;
v.str.length = pos - begin;
return callback(JSON_KEY, &v, level);
}
bool JSON::parse_json_number() {
double double_value;
int tokens, read;
JSON_VAL v;
mark_pos();
// Parsing number - for simplicity ints are limited to 2**53
// sscanf as a double and check if part is 0.
tokens = sscanf(pos, "%lf%n", &double_value, &read);
assert(tokens <= 1, "scanf implementation that counts as a token, parsing json numbers will always fail");
if (tokens == 1) {
assert(read > 0, "sanity");
if (floor(double_value) == double_value) {
// No exponent - treat as an int
v.int_value = (int)double_value;
if (!callback(JSON_NUMBER_INT, &v, level)) {
return false;
}
} else {
v.double_value = double_value;
if (!callback(JSON_NUMBER_FLOAT, &v, level)) {
return false;
}
}
skip(read);
return true;
}
error(SYNTAX_ERROR, "Couldn't parse json number (note that exponents are not supported).");
return false;
}
bool JSON::parse_json_symbol(const char* name, JSON_TYPE symbol) {
if (expect_string(name, "maybe you forgot to quote your strings?") == false) {
mark_pos();
return false;
}
return callback(symbol, NULL, level);
}
void JSON::mark_pos() {
assert((mark == start || *(mark - 1)) != 0, "buffer overrun");
assert(mark <= pos, "mark runahead");
u_char c;
while (mark < pos) {
c = *mark;
assert(c != 0, "pos buffer overrun?");
if (c != 0) {
mark++;
column++;
}
if (c == '\n') {
line++;
column = 0;
}
}
assert(mark <= pos, "mark runahead");
}
u_char JSON::next() {
assert((pos == start || *(pos - 1)) != 0, "buffer overrun");
u_char c = *pos;
if (c != 0) {
pos++;
}
return c;
}
u_char JSON::peek() {
return *pos;
}
// Peek ahead i chars (0 is same as peek())
u_char JSON::peek(size_t i) {
u_char c;
const char* p;
p = pos;
c = *p;
while (i > 0 && c != 0) {
i--;
p++;
c = *p;
}
return c;
}
/*
* Check that one of the expected characters is next in the stream.
* If not, it is an error.
* Returns 0 if EOS is encountered.
* Returns -1 if the next character was not one of the expected.
* Otherwise consumes and returns the expected character that was encountered.
*/
int JSON::expect_any(const char* valid_chars, const char* error_msg, JSON_ERROR e) {
size_t len;
u_char c;
len = strlen(valid_chars);
assert(len > 0, "need non-empty string");
c = peek();
if (c == 0) {
error(e, "Got EOS when expecting %s (%s\'%s\').", error_msg, len > 1 ? "one of " : "", valid_chars);
return 0;
}
for (size_t i = 0; i < len; i++) {
if (c == valid_chars[i]) {
return next();
}
}
error(e, "Expected %s (%s\'%s\').", error_msg, len > 1 ? "one of " : "", valid_chars);
return -1;
}
/*
* Check that the expected string is next in the stream.
* If not, it is an error.
* Consumes the expected characters if they are present.
* Returns true if the expected characters were present, otherwise false.
*/
bool JSON::expect_string(const char* expected_string, const char* error_msg, JSON_ERROR e) {
u_char c, expected_char;
size_t len;
assert(expected_string != NULL, "need non-null string");
len = strlen(expected_string);
assert(len > 0, "need non-empty string");
for (size_t i = 0; i < len; i++) {
expected_char = expected_string[i];
assert(expected_char > ' ', "not sane for control characters");
if (expected_char <= ' ') {
error(INTERNAL_ERROR, "expect got a control char");
}
c = pos[i];
if (c == 0) {
error(e, "EOS encountered when expecting %s (\"%s\")", error_msg, expected_string);
return false;
} else if (c != expected_char) {
error(e, "Expected \"%s\" (%s)", expected_string, error_msg);
return false;
}
}
skip(len);
return true;
}
/*
* Skip i characters.
* Returns number of characters skipped.
*/
size_t JSON::skip(size_t i) {
u_char c;
size_t j;
c = peek();
for (j = i; c != 0 && j > 0; j--) {
c = next();
}
return i - j;
}
/*
* Skip whitespace and comments.
* Returns the first token after whitespace/comments without consuming it
* Returns 0 if EOS is encountered.
* Returns -1 if there is an error
*/
int JSON::skip_to_token() {
for (;;) {
int c = peek(0);
if (c == '/') {
u_char c2 = peek(1);
if (c2 == '/') {
c = skip_line_comment();
} else if (c2 == '*') {
c = skip_block_comment();
if (c < 0) {
return -1;
}
}
// Fall through to keep checking if there
// are more whitespace / comments to skip
}
if (c == 0 || c > ' ') {
return c;
}
next();
}
return 0;
}
/*
* Skip to, and return the wanted char without consuming it
* Returns 0 if EOS is encountered.
*/
u_char JSON::skip_to(u_char want) {
// We want the bookkeeping done in next().
// Otherwise strchr could have been used.
u_char c;
for(;;) {
c = peek();
if (c == 0 || c == want) {
return c;
}
next();
}
}
/*
* Should only be called when we actually have a line comment to skip.
* Otherwise it is an internal error.
*
* Will return the first token after the line comment without consuming it.
* Returns 0 if EOS is encoutered.
*/
u_char JSON::skip_line_comment() {
u_char c;
// Check that we are not called in error
expect_any("/", "line comment start", INTERNAL_ERROR);
expect_any("/", "line comment start", INTERNAL_ERROR);
c = skip_to('\n');
if (c == 0) {
return 0;
}
next();
return next();
}
/*
* Should only be called when we actually have a block comment to skip.
* Otherwise it is an internal error.
*
* Returns the first token after the block comment without consuming it.
* Returns -1 if EOS is encountered in the middle of a comment.
*/
int JSON::skip_block_comment() {
const char* current;
// Check that we are not called in error.
if (peek() != '/' || peek(1) != '*') {
// Let expect handle EOS.
expect_string("/*", "block comment start", INTERNAL_ERROR);
return 0;
}
current = pos;
for (;;) {
current = strchrnul_(current, '*');
if (current[0] == 0 || current[1] == 0) {
// Advance error marker to start of block comment
mark_pos();
error(SYNTAX_ERROR, "Block comment started here never ended. Expected \"*/\" before EOS.");
return -1;
}
if (current[1] == '/') {
pos = current;
if (expect_string("*/", "block comment end", INTERNAL_ERROR) == false) {
return -1;
}
// Found block comment end
return peek();
}
current++;
}
}
const char* JSON::strerror(JSON_ERROR e) {
switch (e) {
case SYNTAX_ERROR:
return "Syntax error";
case INTERNAL_ERROR:
return "Internal error";
case KEY_ERROR:
return "Key error";
case VALUE_ERROR:
return "Value error";
default:
ShouldNotReachHere();
return "Unknown error";
}
}
void JSON::error(JSON_ERROR e, const char* format, ...) {
_valid = false;
if (!silent) {
const char* line_start;
const char* tmp;
size_t line_length;
va_list args;
u_char c;
_st->print("%s on line %u byte %u: ", JSON::strerror(e), line, column + 1);
va_start(args, format);
_st->vprint(format, args);
_st->cr();
va_end(args);
line_start = mark - column;
assert(line_start >= start, "out of bounds");
assert(line_start <= mark, "out of bounds");
assert(line_start == start || line_start[-1] == '\n', "line counting error");
c = *pos;
if (c == 0) {
_st->print(" Got ");
_st->print_cr("EOS.");
}
tmp = mark;
c = *tmp;
if (c > ' ') {
_st->print(" At ");
_st->print("'");
while (c > ' ') {
_st->print("%c", c);
tmp++;
c = *tmp;
}
_st->print_cr("'.");
}
// Skip to newline or EOS
tmp = strchrnul_(mark, '\n');
line_length = tmp - line_start;
_st->print_cr("%s", line_start);
}
}
#ifndef PRODUCT
void JSONTest::test(const char* text, bool should_pass) {
JSONTest json(text);
if (should_pass) {
assert(json.valid() == true, "failed on a valid json string");
if (VerboseInternalVMTests) {
tty->print_cr("-- json test passed as expected --");
}
} else {
assert(json.valid() == false, "succeeded on an invalid json string");
if (VerboseInternalVMTests) {
tty->print_cr("-- json test failed as expected --");
}
}
}
JSONTest::JSONTest(const char* text) : JSON(text, !VerboseInternalVMTests, tty) {
prev = JSON_NONE;
parse();
}
bool JSONTest::test() {
JSONTest::test("{}", true);
JSONTest::test("[]", true);
JSONTest::test(" { } ", true);
JSONTest::test(" [ ] ", true);
JSONTest::test("\"error\"", false);
JSONTest::test("error", false);
JSONTest::test("1", false);
JSONTest::test("1.2", false);
JSONTest::test("true", false);
JSONTest::test("false", false);
JSONTest::test("null", false);
JSONTest::test("[ 1 ]", true);
JSONTest::test("[ 1, ]", true);
JSONTest::test("[ true ]", true);
JSONTest::test("[ true, ]", true);
JSONTest::test("[ false ]", true);
JSONTest::test("[ false, ]", true);
JSONTest::test("[ null ]", true);
JSONTest::test("[ null, ]", true);
JSONTest::test("[ \"\" ]", true);
JSONTest::test("[ \"\", ]", true);
JSONTest::test("[ \"elem1\" ]", true);
JSONTest::test("[ \"elem1\", ]", true);
JSONTest::test("[ \"elem1\", ]", true);
JSONTest::test("[ \"elem1\" ]", true);
JSONTest::test("[ \"elem1\", \"elem2\" ]", true);
JSONTest::test("[ \"elem1\", \"elem2\", ]", true);
JSONTest::test("[ \"elem1\" ] { }", false);
JSONTest::test("[ elem1, \"elem2\" ]", false);
JSONTest::test("[ \"elem1\"", false);
JSONTest::test("[ \"elem1 ]", false);
JSONTest::test("[ \"elem1\", \"elem2\"", false);
JSONTest::test("[ truefoo ]", false);
JSONTest::test("[ falsefoo ]", false);
JSONTest::test("[ nullfoo ]", false);
JSONTest::test("{ key : 1 }", true);
JSONTest::test("{ key : 1, }", true);
JSONTest::test("{ key : 1.2 }", true);
JSONTest::test("{ key : true }", true);
JSONTest::test("{ key : true, }", true);
JSONTest::test("{ key : false }", true);
JSONTest::test("{ key : false, }", true);
JSONTest::test("{ key : null }", true);
JSONTest::test("{ key : null, }", true);
JSONTest::test("{ \"\" : \"\" }", true);
JSONTest::test("{ \"\" : \"\", }", true);
JSONTest::test("{ \"key1\" : \"val1\" }", true);
JSONTest::test("{ \"key1\" : \"val1\", }", true);
JSONTest::test("{ \"key1\" : \"val1\", \"key2\" : \"val2\" }", true);
JSONTest::test("{ \"key1\" : \"val1\", \"key2\" : \"val2\", }", true);
JSONTest::test("{ \"key\" : \"val\" } [ \"error\" ]", false);
JSONTest::test("{ \"key\" : \"val\" ", false);
JSONTest::test("/**/ { }", true);
JSONTest::test("/* */ { }", true);
JSONTest::test("/*foo*/ { }", true);
JSONTest::test("/* *foo */ { }", true);
JSONTest::test("/* *foo* */ { }", true);
JSONTest::test("/* /*foo */ { }", true);
JSONTest::test("{ } /* foo */", true);
JSONTest::test("{ } /* foo */ ", true);
JSONTest::test("{ } //", true);
JSONTest::test("{ } // ", true);
JSONTest::test("{ } // foo", true);
JSONTest::test("/* * / { }", false);
JSONTest::test("/ * */ { }", false);
JSONTest::test("// { }", false);
JSONTest::test("/* { } */", false);
JSONTest::test("/* { } */ ", false);
JSONTest::test("/* { } ", false);
JSONTest::test("{ } /* ", false);
JSONTest::test("/* { } *", false);
JSONTest::test("{ /* } */", false);
JSONTest::test("[ /* ] */", false);
JSONTest::test("{ key : \"val\", /* } */", false);
JSONTest::test("[ \"val\", /* ] */", false);
JSONTest::test("/* comment */{ key1 : { \"key2\" : { \"key3\" : [ \"elem1\", \"elem2\", { \"key4\" : null }, 3 , 2 , 1 , 0 , -1 , -2 , -3 , true, false, null, ] }, \"key5\" : true }, \"key6\" : [ \"\" ], key7 : \"val\",}", true);
JSONTest::test("/* comment */ { \"key1\" : { \"key2\" : { \"key3\" : [ \"elem1\", \"elem2\", { \"key4\" : null }, 3 , 2 , 1 , 0 , -1 , -2 , -3 , true, false, null, ] }, \"key5\" : true }, \"key6\" : [ \"\" ], key7 : \"val\",}", true);
JSONTest::test("/*comment*/{\"ff1 fsd\":{\"\":{\"\":[\"\",\"\"]},\"\":true},\"\":[\"\"],\"foo\":\"\",}", true);
JSONTest::test("/* comment */ { key1 error : { \"\" : { \"\" : [ \"\", \"\" ] }, \"\" : true }, \"baz\" : [ \"\" ], foo : \"\",}", false); // first key needs to be quoted since it contains a space
JSONTest::test("[\n]", true);
JSONTest::test(
"[" "\n"
" {"
" // pattern to match against class+method+signature" "\n"
" // leading and trailing wildcard (*) allowed" "\n"
" match: \"foo.bar.*\"," "\n"
" " "\n"
" // override defaults for specified compiler" "\n"
" // we may differentiate between levels too. TBD." "\n"
" c1: {" "\n"
" //override c1 presets " "\n"
" array_bounds_check_removal: false" "\n"
" }," "\n"
"" "\n"
" c2: {" "\n"
" // control inlining of method" "\n"
" // + force inline, - dont inline" "\n"
" inline : [ \"+java.util.*\", \"-com.sun.*\"]," "\n"
" }," "\n"
"" "\n"
" // directives outside a specific preset applies to all compilers" "\n"
" inline : [ \"+java.util.*\", \"-com.sun.*\"]," "\n"
" print_assembly: true," "\n"
" verify_oopmaps: true," "\n"
" max_loop_unrolling: 5" "\n"
" }," "\n"
" {" "\n"
" // matching several patterns require an array" "\n"
" match: [\"baz.*\",\"frob*\"]," "\n"
"" "\n"
" // only enable c1 for this directive" "\n"
" // all enabled by default. Command disables all not listed" "\n"
" enable: \"c1\"," "\n"
"" "\n"
" // applies to all compilers" "\n"
" // + force inline, - dont inline" "\n"
" inline : [ \"+java.util.*\", \"-com.sun.*\"]," "\n"
" print_inlining: true," "\n"
"" "\n"
" // force matching compiles to be blocking/syncronous" "\n"
" blocking_compile: true" "\n"
" }," "\n"
"]" "\n", true);
return true;
}
void JSONTest::log(uint indent, const char* format, ...) {
if (VerboseInternalVMTests) {
if (prev != JSON_KEY) {
for (uint i = 0; i < indent; i++) {
_st->print(" ");
}
}
va_list args;
va_start(args, format);
_st->vprint(format, args);
va_end(args);
}
}
bool JSONTest::callback(JSON_TYPE t, JSON_VAL* v, uint rlevel) {
switch (t) {
case JSON_OBJECT_BEGIN:
log(rlevel, "{\n");
prev = JSON_NONE; // Only care about JSON_KEY, to indent correctly
return true;
case JSON_OBJECT_END:
log(rlevel, "},\n");
prev = JSON_NONE;
return true;
case JSON_ARRAY_BEGIN:
log(rlevel, "[\n");
prev = JSON_NONE;
return true;
case JSON_ARRAY_END:
log(rlevel, "],\n");
prev = JSON_NONE;
return true;
case JSON_KEY:
if (VerboseInternalVMTests) {
for (uint i = 0; i < rlevel; i++) {
_st->print(" ");
}
_st->print("<key>");
for (size_t i = 0; i < v->str.length; i++) {
u_char c = v->str.start[i];
assert(c != 0, "string overrun");
if (c == 0) {
return false;
}
_st->print("%c", c);
}
_st->print(" : ");
}
prev = JSON_KEY;
return true;
case JSON_STRING:
if (VerboseInternalVMTests) {
if (prev != JSON_KEY) {
for (uint i = 0; i < rlevel; i++) {
_st->print(" ");
}
}
_st->print("<str>");
for (size_t i = 0; i < v->str.length; i++) {
u_char c = v->str.start[i];
assert(c != 0, "string overrun");
if (c == 0) {
return false;
}
_st->print("%c", c);
}
_st->print(",\n");
}
prev = JSON_NONE;
return true;
case JSON_NUMBER_INT:
log(rlevel, "<int>%" PRId64 ",\n", v->int_value);
prev = JSON_NONE;
return true;
case JSON_NUMBER_FLOAT:
log(rlevel, "<double>%lf,\n", v->double_value);
prev = JSON_NONE;
return true;
case JSON_TRUE:
log(rlevel, "<true>,\n");
prev = JSON_NONE;
return true;
case JSON_FALSE:
log(rlevel, "<false>,\n");
prev = JSON_NONE;
return true;
case JSON_NULL:
log(rlevel, "<null>,\n");
prev = JSON_NONE;
return true;
default:
error(INTERNAL_ERROR, "unknown JSON type");
return false;
}
}
#endif

View File

@ -0,0 +1,127 @@
/*
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
#ifndef SHARE_VM_UTILITIES_JSON_HPP
#define SHARE_VM_UTILITIES_JSON_HPP
#include "memory/allocation.hpp"
#include "utilities/globalDefinitions.hpp"
#include "utilities/ostream.hpp"
class JSON : public ResourceObj {
protected:
JSON(const char* text, bool silent, outputStream* st);
void parse();
bool valid();
typedef enum {
JSON_NONE,
JSON_OBJECT_BEGIN,
JSON_OBJECT_END,
JSON_ARRAY_BEGIN,
JSON_ARRAY_END,
JSON_KEY,
JSON_STRING,
JSON_NUMBER_INT,
JSON_NUMBER_FLOAT,
JSON_TRUE,
JSON_FALSE,
JSON_NULL
} JSON_TYPE;
typedef union {
int64_t int_value;
double double_value;
struct {
const char* start;
size_t length;
} str;
} JSON_VAL;
typedef enum {
INTERNAL_ERROR,
SYNTAX_ERROR,
KEY_ERROR,
VALUE_ERROR
} JSON_ERROR;
void error(JSON_ERROR e, const char* format, ...) ATTRIBUTE_PRINTF(3, 4);
outputStream* _st;
private:
const char* start;
const char* pos;
// For error printing
const char* mark; // Error marker
uint level;
uint line;
uint column;
bool silent;
bool _valid;
bool parse_json_value();
bool parse_json_object();
bool parse_json_array();
bool parse_json_string(bool key = false);
bool parse_json_key();
bool parse_json_number();
bool parse_json_symbol(const char* name, JSON_TYPE symbol);
virtual bool callback(JSON_TYPE t, JSON_VAL* v, uint level) = 0;
void mark_pos();
u_char next();
u_char peek();
u_char peek(size_t i);
int expect_any(const char* valid_chars, const char* error_msg, JSON_ERROR e = SYNTAX_ERROR);
bool expect_string(const char* expected_string, const char* error_msg = "", JSON_ERROR e = SYNTAX_ERROR);
size_t skip(size_t i);
int skip_to_token();
u_char skip_to(u_char want);
u_char skip_line_comment();
int skip_block_comment();
const char* strerror(JSON_ERROR e);
};
#ifndef PRODUCT
class JSONTest : public JSON {
public:
static bool test();
private:
JSONTest(const char* text);
static void test(const char* json, bool valid);
void log(uint level, const char* format, ...) ATTRIBUTE_PRINTF(3, 4);
bool callback(JSON_TYPE t, JSON_VAL* v, uint level);
JSON_TYPE prev;
};
#endif
#endif // SHARE_VM_UTILITIES_JSON_HPP

View File

@ -0,0 +1,173 @@
/*
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test InlineMatcherTest
* @bug 8074095
* @library /testlibrary /../../test/lib
* @run main ClassFileInstaller sun.hotspot.WhiteBox
* sun.hotspot.WhiteBox$WhiteBoxPermission
* @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI InlineMatcherTest
* @summary Testing of compiler/InlineMatcher
*/
import java.lang.reflect.Method;
import java.util.ArrayList;
import sun.hotspot.WhiteBox;
public class InlineMatcherTest {
/** Instance of WhiteBox */
protected static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox();
Method helper;
Method getDate;
Method inner;
Method toString;
final public static int FORCE_INLINE = 2;
final public static int DONT_INLINE = 1;
final public static int NO_MATCH = 0;
final public static int PARSING_FAILURE = -1;
public InlineMatcherTest() {
}
public void test() throws Exception {
// instantiate before calling getMethod on innerHelper
TestCases testCases = new TestCases();
helper = getMethod(InlineMatcherTest.class, "helper");
testCases.add(helper, "*.*", PARSING_FAILURE);
testCases.add(helper, "+*.*", FORCE_INLINE);
testCases.add(helper, "++*.*", NO_MATCH); // + is a valid part of the
// class name
testCases.add(helper, "-*.*", DONT_INLINE);
testCases.add(helper, "--*.*", NO_MATCH); // - is a valid part of the
// class name
testCases.add(helper, "+InlineMatcherTest.*", FORCE_INLINE);
testCases.add(helper, "+InlineMatcherTest.helper", FORCE_INLINE);
testCases.add(helper, "+InlineMatcherTest.helper()", FORCE_INLINE);
testCases.add(helper, "+InlineMatcherTest.helper()V", FORCE_INLINE);
testCases.add(helper, "+InlineMatcherTest.helper(", FORCE_INLINE);
testCases.add(helper, "-InlineMatcherTest.*", DONT_INLINE);
testCases.add(helper, "-InlineMatcherTest.helper", DONT_INLINE);
testCases.add(helper, "-InlineMatcherTest.helper()", DONT_INLINE);
testCases.add(helper, "-InlineMatcherTest.helper()V", DONT_INLINE);
testCases.add(helper, "-InlineMatcherTest.helper(", DONT_INLINE);
testCases.add(helper, "+abc.*", NO_MATCH);
testCases.add(helper, "+*.abc", NO_MATCH);
testCases.add(helper, "-abc.*", NO_MATCH);
testCases.add(helper, "-*.abcls ", NO_MATCH);
int failures = 0;
for (TestCase t : testCases) {
System.out.println("Test case: " + t.pattern);
if (!t.test()) {
failures++;
System.out.println(" * FAILED");
}
}
if (failures != 0) {
throw new Exception("There where " + failures + " failures in this test");
}
}
public static void main(String... args) throws Exception {
InlineMatcherTest test = new InlineMatcherTest();
test.test();
}
public void helper() {
}
private static Method getMethod(Class klass, String name, Class<?>... parameterTypes) {
try {
return klass.getDeclaredMethod(name, parameterTypes);
} catch (NoSuchMethodException | SecurityException e) {
throw new RuntimeException("exception on getting method Helper." + name, e);
}
}
class TestCase {
String pattern;
Method testTarget;
int expectedResult;
public TestCase(Method testTarget, String pattern, int expectedResult) {
this.testTarget = testTarget;
this.pattern = pattern;
this.expectedResult = expectedResult;
}
public String resultAsStr(int errorCode) {
switch (errorCode) {
case PARSING_FAILURE:
return "Parsing failed";
case NO_MATCH:
return "No match";
case DONT_INLINE:
return "Dont Inline";
case FORCE_INLINE:
return "Force Inline";
default:
return "Unknown error";
}
}
boolean test() {
int result = WHITE_BOX.matchesInline(testTarget, pattern);
if (result != expectedResult) {
System.out
.println("FAIL Wrong result, Got: " + resultAsStr(result) + "\n TestCase: " + this.toString());
return false;
}
return true;
}
@Override
public String toString() {
return "Method: '" + testTarget.toString() + "' Pattern: '" + pattern + "' Expected: "
+ resultAsStr(expectedResult);
}
public void innerHelper() {
}
}
class TestCases extends ArrayList<TestCase> {
private static final long serialVersionUID = 1L;
public boolean add(Method testTarget, String pattern, int expectedResult) {
return super.add(new TestCase(testTarget, pattern, expectedResult));
}
}
}

View File

@ -0,0 +1,125 @@
/*
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test TestCompilerDirectivesCompatibilityBase
* @bug 8137167
* @library /testlibrary /../../test/lib
* @modules java.base/sun.misc
* java.compiler
* java.management
* @build jdk.test.lib.*
* @build jdk.test.lib.dcmd.*
* @build sun.hotspot.WhiteBox.*
* @run main ClassFileInstaller sun.hotspot.WhiteBox
* sun.hotspot.WhiteBox$WhiteBoxPermission
* @run testng/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI TestCompilerDirectivesCompatibilityBase
* @summary Test compiler control compatibility with compile command
*/
import jdk.test.lib.dcmd.CommandExecutor;
import jdk.test.lib.dcmd.JMXExecutor;
import org.testng.annotations.Test;
import org.testng.Assert;
import sun.hotspot.WhiteBox;
import java.io.BufferedReader;
import java.io.File;
import java.io.StringReader;
import java.lang.reflect.Method;
import java.util.Objects;
public class TestCompilerDirectivesCompatibilityBase {
public static final WhiteBox WB = WhiteBox.getWhiteBox();
public static String control_on, control_off;
Method method, nomatch;
public void run(CommandExecutor executor) throws Exception {
control_on = System.getProperty("test.src", ".") + File.separator + "control_on.txt";
control_off = System.getProperty("test.src", ".") + File.separator + "control_off.txt";
method = getMethod(TestCompilerDirectivesCompatibilityBase.class, "helper");
nomatch = getMethod(TestCompilerDirectivesCompatibilityBase.class, "another");
testCompatibility(executor);
}
public void testCompatibility(CommandExecutor executor) throws Exception {
// Call all validation twice to catch error when overwriting a directive
// Flag is default off
expect(!WB.getBooleanVMFlag("PrintAssembly"));
expect(!WB.shouldPrintAssembly(method));
expect(!WB.shouldPrintAssembly(nomatch));
expect(!WB.shouldPrintAssembly(method));
expect(!WB.shouldPrintAssembly(nomatch));
// load directives that turn it on
executor.execute("Compiler.directives_add " + control_on);
expect(WB.shouldPrintAssembly(method));
expect(!WB.shouldPrintAssembly(nomatch));
expect(WB.shouldPrintAssembly(method));
expect(!WB.shouldPrintAssembly(nomatch));
// remove and see that it is true again
executor.execute("Compiler.directives_remove");
expect(!WB.shouldPrintAssembly(method));
expect(!WB.shouldPrintAssembly(nomatch));
expect(!WB.shouldPrintAssembly(method));
expect(!WB.shouldPrintAssembly(nomatch));
}
public void expect(boolean test) throws Exception {
if (!test) {
throw new Exception("Test failed");
}
}
public void expect(boolean test, String msg) throws Exception {
if (!test) {
throw new Exception(msg);
}
}
@Test
public void jmx() throws Exception {
run(new JMXExecutor());
}
public void helper() {
}
public void another() {
}
public static Method getMethod(Class klass, String name, Class<?>... parameterTypes) {
try {
return klass.getDeclaredMethod(name, parameterTypes);
} catch (NoSuchMethodException | SecurityException e) {
throw new RuntimeException("exception on getting method Helper." + name, e);
}
}
}

View File

@ -0,0 +1,80 @@
/*
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test TestCompilerDirectivesCompatibilityCommandOff
* @bug 8137167
* @library /testlibrary /../../test/lib
* @modules java.base/sun.misc
* java.compiler
* java.management
* @build jdk.test.lib.*
* @build jdk.test.lib.dcmd.*
* @build sun.hotspot.WhiteBox.*
* @run main ClassFileInstaller sun.hotspot.WhiteBox
* sun.hotspot.WhiteBox$WhiteBoxPermission
* @run testng/othervm -Xbootclasspath/a:. -XX:-PrintAssembly -XX:CompileCommand=option,*.helper,bool,PrintAssembly,false -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI TestCompilerDirectivesCompatibilityCommandOff
* @summary Test compiler control compatibility with compile command
*/
// import jdk.test.lib.OutputAnalyzer;
import jdk.test.lib.dcmd.CommandExecutor;
import jdk.test.lib.dcmd.JMXExecutor;
import org.testng.annotations.Test;
import org.testng.Assert;
import sun.hotspot.WhiteBox;
import java.io.BufferedReader;
import java.io.File;
import java.io.StringReader;
import java.lang.reflect.Method;
import java.util.Objects;
public class TestCompilerDirectivesCompatibilityCommandOff extends TestCompilerDirectivesCompatibilityBase {
public void testCompatibility(CommandExecutor executor) throws Exception {
// Call all validation twice to catch error when overwriting a directive
// Flag is default off
expect(!WB.shouldPrintAssembly(method));
expect(!WB.shouldPrintAssembly(nomatch));
expect(!WB.shouldPrintAssembly(method));
expect(!WB.shouldPrintAssembly(nomatch));
// load directives that turn it on
executor.execute("Compiler.directives_add " + control_on);
expect(WB.shouldPrintAssembly(method));
expect(!WB.shouldPrintAssembly(nomatch));
expect(WB.shouldPrintAssembly(method));
expect(!WB.shouldPrintAssembly(nomatch));
// remove and see that it is false again
executor.execute("Compiler.directives_remove");
expect(!WB.shouldPrintAssembly(method));
expect(!WB.shouldPrintAssembly(nomatch));
expect(!WB.shouldPrintAssembly(method));
expect(!WB.shouldPrintAssembly(nomatch));
}
}

View File

@ -0,0 +1,80 @@
/*
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test TestCompilerDirectivesCompatibilityCommandOn
* @bug 8137167
* @library /testlibrary /../../test/lib
* @modules java.base/sun.misc
* java.compiler
* java.management
* @build jdk.test.lib.*
* @build jdk.test.lib.dcmd.*
* @build sun.hotspot.WhiteBox.*
* @run main ClassFileInstaller sun.hotspot.WhiteBox
* sun.hotspot.WhiteBox$WhiteBoxPermission
* @run testng/othervm -Xbootclasspath/a:. -XX:-PrintAssembly -XX:CompileCommand=print,*.* -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI TestCompilerDirectivesCompatibilityCommandOn
* @summary Test compiler control compatibility with compile command
*/
// import jdk.test.lib.OutputAnalyzer;
import jdk.test.lib.dcmd.CommandExecutor;
import jdk.test.lib.dcmd.JMXExecutor;
import org.testng.annotations.Test;
import org.testng.Assert;
import sun.hotspot.WhiteBox;
import java.io.BufferedReader;
import java.io.File;
import java.io.StringReader;
import java.lang.reflect.Method;
import java.util.Objects;
public class TestCompilerDirectivesCompatibilityCommandOn extends TestCompilerDirectivesCompatibilityBase{
public void testCompatibility(CommandExecutor executor) throws Exception {
// Call all validation twice to catch error when overwriting a directive
// Flag is default on
expect(WB.shouldPrintAssembly(method));
expect(WB.shouldPrintAssembly(nomatch));
expect(WB.shouldPrintAssembly(method));
expect(WB.shouldPrintAssembly(nomatch));
// load directives that turn it off
executor.execute("Compiler.directives_add " + control_off);
expect(!WB.shouldPrintAssembly(method));
expect(WB.shouldPrintAssembly(nomatch));
expect(!WB.shouldPrintAssembly(method));
expect(WB.shouldPrintAssembly(nomatch));
// remove and see that it is true again
executor.execute("Compiler.directives_remove");
expect(WB.shouldPrintAssembly(method));
expect(WB.shouldPrintAssembly(nomatch));
expect(WB.shouldPrintAssembly(method));
expect(WB.shouldPrintAssembly(nomatch));
}
}

View File

@ -0,0 +1,80 @@
/*
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test TestCompilerDirectivesCompatibilityFlag
* @bug 8137167
* @library /testlibrary /../../test/lib
* @modules java.base/sun.misc
* java.compiler
* java.management
* @build jdk.test.lib.*
* @build jdk.test.lib.dcmd.*
* @build sun.hotspot.WhiteBox.*
* @run main ClassFileInstaller sun.hotspot.WhiteBox
* sun.hotspot.WhiteBox$WhiteBoxPermission
* @run testng/othervm -Xbootclasspath/a:. -XX:+PrintAssembly -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI TestCompilerDirectivesCompatibilityFlag
* @summary Test compiler control compatibility with compile command
*/
import jdk.test.lib.dcmd.CommandExecutor;
import jdk.test.lib.dcmd.JMXExecutor;
import org.testng.annotations.Test;
import org.testng.Assert;
import sun.hotspot.WhiteBox;
import java.io.BufferedReader;
import java.io.File;
import java.io.StringReader;
import java.lang.reflect.Method;
import java.util.Objects;
public class TestCompilerDirectivesCompatibilityFlag extends TestCompilerDirectivesCompatibilityBase {
public void testCompatibility(CommandExecutor executor) throws Exception {
// Call all validation twice to catch error when overwriting a directive
// Flag is default on
expect(WB.getBooleanVMFlag("PrintAssembly"));
expect(WB.shouldPrintAssembly(method));
expect(WB.shouldPrintAssembly(nomatch));
expect(WB.shouldPrintAssembly(method));
expect(WB.shouldPrintAssembly(nomatch));
// load directives that turn it off
executor.execute("Compiler.directives_add " + control_off);
expect(!WB.shouldPrintAssembly(method));
expect(WB.shouldPrintAssembly(nomatch));
expect(!WB.shouldPrintAssembly(method));
expect(WB.shouldPrintAssembly(nomatch));
// remove and see that it is true again
executor.execute("Compiler.directives_remove");
expect(WB.shouldPrintAssembly(method));
expect(WB.shouldPrintAssembly(nomatch));
expect(WB.shouldPrintAssembly(method));
expect(WB.shouldPrintAssembly(nomatch));
}
}

View File

@ -0,0 +1,7 @@
[
{
match: "*.helper",
PrintAssembly: false,
DisableIntrinsic:"x"
}
]

View File

@ -0,0 +1,7 @@
[
{
match: "*.helper",
PrintAssembly: true,
DisableIntrinsic:"_dsin"
}
]

View File

@ -0,0 +1,158 @@
/*
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test CompilerDirectivesDCMDTest
* @bug 8137167
* @library /testlibrary
* @modules java.base/sun.misc
* java.compiler
* java.management
* @build jdk.test.lib.*
* @build jdk.test.lib.dcmd.*
* @run main ClassFileInstaller jdk.test.lib.Platform
* @run testng/othervm CompilerDirectivesDCMDTest
* @summary Test of diagnostic command
*/
import jdk.test.lib.OutputAnalyzer;
import jdk.test.lib.dcmd.CommandExecutor;
import jdk.test.lib.dcmd.JMXExecutor;
import jdk.test.lib.Platform;
import org.testng.annotations.Test;
import org.testng.Assert;
import java.io.BufferedReader;
import java.io.File;
import java.io.StringReader;
public class CompilerDirectivesDCMDTest {
public static String filename;
public void run(CommandExecutor executor) {
if (Platform.isServer()) {
filename = System.getProperty("test.src", ".") + File.separator + "control2.txt";
} else {
filename = System.getProperty("test.src", ".") + File.separator + "control1.txt";
}
testPrintCommand(executor);
testAddAndRemoveCommand(executor);
}
public static void testPrintCommand(CommandExecutor executor) {
// Get output from dcmd (diagnostic command)
OutputAnalyzer output = executor.execute("Compiler.directives_print");
int count = find(output, "Directive:");
if (count < 1) {
Assert.fail("Expected at least one directive - found " + count);
}
}
public static void testAddAndRemoveCommand(CommandExecutor executor) {
OutputAnalyzer output;
int count = 0;
// Start with clearing stack - expect only default directive left
output = executor.execute("Compiler.directives_clear");
output = executor.execute("Compiler.directives_print");
count = find(output, "Directive:");
if (count != 1) {
Assert.fail("Expected one directives - found " + count);
}
// Test that we can not remove the default directive
output = executor.execute("Compiler.directives_remove");
output = executor.execute("Compiler.directives_print");
count = find(output, "Directive:");
if (count != 1) {
Assert.fail("Expected one directives - found " + count);
}
// Test adding some directives from file
output = executor.execute("Compiler.directives_add " + filename);
output = executor.execute("Compiler.directives_print");
count = find(output, "Directive:");
if (count != 3) {
Assert.fail("Expected three directives - found " + count);
}
// Test remove one directive
output = executor.execute("Compiler.directives_remove");
output = executor.execute("Compiler.directives_print");
count = find(output, "Directive:");
if (count != 2) {
Assert.fail("Expected two directives - found " + count);
}
// Test adding directives again
output = executor.execute("Compiler.directives_add " + filename);
output = executor.execute("Compiler.directives_print");
count = find(output, "Directive:");
if (count != 4) {
Assert.fail("Expected four directives - found " + count);
}
// Test clearing
output = executor.execute("Compiler.directives_clear");
output = executor.execute("Compiler.directives_print");
count = find(output, "Directive:");
if (count != 1) {
Assert.fail("Expected one directives - found " + count);
}
// Test clear when already cleared
output = executor.execute("Compiler.directives_clear");
output = executor.execute("Compiler.directives_print");
count = find(output, "Directive:");
if (count != 1) {
Assert.fail("Expected one directives - found " + count);
}
// Test remove one directive when empty
output = executor.execute("Compiler.directives_remove");
output = executor.execute("Compiler.directives_print");
count = find(output, "Directive:");
if (count != 1) {
Assert.fail("Expected one directive - found " + count);
}
}
public static int find(OutputAnalyzer output, String find) {
int count = 0;
for (String line : output.asLines()) {
if (line.startsWith(find)) {
count++;
}
}
return count;
}
@Test
public void jmx() {
run(new JMXExecutor());
}
}

View File

@ -0,0 +1,17 @@
[
{
match: "foo/bar.*",
PrintAssembly: false,
c1: {
BreakAtExecute: false,
},
inline : [ "+javax/util.*", "-comx/sun.*"],
PrintAssembly: false,
},
{
match: ["baz.*","frob.*"],
inline : [ "+java/util.*", "-com/sun.*" ],
PrintAssembly: false,
BreakAtExecute: false,
}
]

View File

@ -0,0 +1,22 @@
[
{
match: "foo/bar.*",
PrintAssembly: false,
c1: {
BreakAtExecute: false,
},
c2: {
inline : "+java/util.*",
BreakAtCompile: true
},
inline : [ "+javax/util.*", "-comx/sun.*"],
PrintAssembly: false,
IGVPrintLevel: 2
},
{
match: ["baz.*","frob.*"],
inline : [ "+java/util.*", "-com/sun.*" ],
PrintAssembly: false,
BreakAtExecute: false,
}
]