mirror of
https://github.com/openjdk/jdk.git
synced 2025-09-20 11:04:34 +02:00
Merge
This commit is contained in:
commit
832443d3b0
436 changed files with 12437 additions and 6911 deletions
|
@ -227,6 +227,11 @@ bool compileBroker_init() {
|
|||
CompileTaskWrapper::CompileTaskWrapper(CompileTask* task) {
|
||||
CompilerThread* thread = CompilerThread::current();
|
||||
thread->set_task(task);
|
||||
#if INCLUDE_JVMCI
|
||||
if (task->is_blocking() && CompileBroker::compiler(task->comp_level())->is_jvmci()) {
|
||||
task->set_jvmci_compiler_thread(thread);
|
||||
}
|
||||
#endif
|
||||
CompileLog* log = thread->log();
|
||||
if (log != NULL) task->log_task_start(log);
|
||||
}
|
||||
|
@ -245,10 +250,12 @@ CompileTaskWrapper::~CompileTaskWrapper() {
|
|||
MutexLocker notifier(task->lock(), thread);
|
||||
task->mark_complete();
|
||||
#if INCLUDE_JVMCI
|
||||
if (CompileBroker::compiler(task->comp_level())->is_jvmci() &&
|
||||
!task->has_waiter()) {
|
||||
// The waiting thread timed out and thus did not free the task.
|
||||
free_task = true;
|
||||
if (CompileBroker::compiler(task->comp_level())->is_jvmci()) {
|
||||
if (!task->has_waiter()) {
|
||||
// The waiting thread timed out and thus did not free the task.
|
||||
free_task = true;
|
||||
}
|
||||
task->set_jvmci_compiler_thread(NULL);
|
||||
}
|
||||
#endif
|
||||
if (!free_task) {
|
||||
|
@ -1332,11 +1339,56 @@ CompileTask* CompileBroker::create_compile_task(CompileQueue* queue,
|
|||
return new_task;
|
||||
}
|
||||
|
||||
// 1 second should be long enough to complete most JVMCI compilations
|
||||
// and not too long to stall a blocking JVMCI compilation that
|
||||
// is trying to acquire a lock held by the app thread that submitted the
|
||||
// compilation.
|
||||
static const long BLOCKING_JVMCI_COMPILATION_TIMEOUT = 1000;
|
||||
#if INCLUDE_JVMCI
|
||||
// The number of milliseconds to wait before checking if the
|
||||
// JVMCI compiler thread is blocked.
|
||||
static const long BLOCKING_JVMCI_COMPILATION_WAIT_TIMESLICE = 500;
|
||||
|
||||
// The number of successive times the above check is allowed to
|
||||
// see a blocked JVMCI compiler thread before unblocking the
|
||||
// thread waiting for the compilation to finish.
|
||||
static const int BLOCKING_JVMCI_COMPILATION_WAIT_TO_UNBLOCK_ATTEMPTS = 5;
|
||||
|
||||
/**
|
||||
* Waits for a JVMCI compiler to complete a given task. This thread
|
||||
* waits until either the task completes or it sees the JVMCI compiler
|
||||
* thread is blocked for N consecutive milliseconds where N is
|
||||
* BLOCKING_JVMCI_COMPILATION_WAIT_TIMESLICE *
|
||||
* BLOCKING_JVMCI_COMPILATION_WAIT_TO_UNBLOCK_ATTEMPTS.
|
||||
*
|
||||
* @return true if this thread needs to free/recycle the task
|
||||
*/
|
||||
bool CompileBroker::wait_for_jvmci_completion(CompileTask* task, JavaThread* thread) {
|
||||
MutexLocker waiter(task->lock(), thread);
|
||||
int consecutively_blocked = 0;
|
||||
while (task->lock()->wait(!Mutex::_no_safepoint_check_flag, BLOCKING_JVMCI_COMPILATION_WAIT_TIMESLICE)) {
|
||||
CompilerThread* jvmci_compiler_thread = task->jvmci_compiler_thread();
|
||||
if (jvmci_compiler_thread != NULL) {
|
||||
JavaThreadState state;
|
||||
{
|
||||
// A JVMCI compiler thread should not disappear at this point
|
||||
// but let's be extra safe.
|
||||
MutexLocker mu(Threads_lock, thread);
|
||||
state = jvmci_compiler_thread->thread_state();
|
||||
}
|
||||
if (state == _thread_blocked) {
|
||||
if (++consecutively_blocked == BLOCKING_JVMCI_COMPILATION_WAIT_TO_UNBLOCK_ATTEMPTS) {
|
||||
if (PrintCompilation) {
|
||||
task->print(tty, "wait for blocking compilation timed out");
|
||||
}
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
consecutively_blocked = 0;
|
||||
}
|
||||
} else {
|
||||
// Still waiting on JVMCI compiler queue
|
||||
}
|
||||
}
|
||||
task->clear_waiter();
|
||||
return task->is_complete();
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Wait for the compilation task to complete.
|
||||
|
@ -1356,16 +1408,7 @@ void CompileBroker::wait_for_completion(CompileTask* task) {
|
|||
bool free_task;
|
||||
#if INCLUDE_JVMCI
|
||||
if (compiler(task->comp_level())->is_jvmci()) {
|
||||
MutexLocker waiter(task->lock(), thread);
|
||||
// No need to check if compilation has completed - just
|
||||
// rely on the time out. The JVMCI compiler thread will
|
||||
// recycle the CompileTask.
|
||||
task->lock()->wait(!Mutex::_no_safepoint_check_flag, BLOCKING_JVMCI_COMPILATION_TIMEOUT);
|
||||
// If the compilation completes while has_waiter is true then
|
||||
// this thread is responsible for freeing the task. Otherwise
|
||||
// the compiler thread will free the task.
|
||||
task->clear_waiter();
|
||||
free_task = task->is_complete();
|
||||
free_task = wait_for_jvmci_completion(task, thread);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
|
@ -1755,6 +1798,8 @@ void CompileBroker::invoke_compiler_on_method(CompileTask* task) {
|
|||
push_jni_handle_block();
|
||||
Method* target_handle = task->method();
|
||||
int compilable = ciEnv::MethodCompilable;
|
||||
const char* failure_reason = NULL;
|
||||
const char* retry_message = NULL;
|
||||
AbstractCompiler *comp = compiler(task_level);
|
||||
|
||||
int system_dictionary_modification_counter;
|
||||
|
@ -1774,10 +1819,16 @@ void CompileBroker::invoke_compiler_on_method(CompileTask* task) {
|
|||
jvmci->compile_method(method, osr_bci, &env);
|
||||
|
||||
post_compile(thread, task, event, task->code() != NULL, NULL);
|
||||
|
||||
failure_reason = env.failure_reason();
|
||||
if (!env.retryable()) {
|
||||
retry_message = "not retryable";
|
||||
compilable = ciEnv::MethodCompilable_not_at_tier;
|
||||
}
|
||||
|
||||
} else
|
||||
#endif // INCLUDE_JVMCI
|
||||
{
|
||||
|
||||
NoHandleMark nhm;
|
||||
ThreadToNativeFromVM ttn(thread);
|
||||
|
||||
|
@ -1825,31 +1876,45 @@ void CompileBroker::invoke_compiler_on_method(CompileTask* task) {
|
|||
compilable = ci_env.compilable();
|
||||
|
||||
if (ci_env.failing()) {
|
||||
task->set_failure_reason(ci_env.failure_reason());
|
||||
ci_env.report_failure(ci_env.failure_reason());
|
||||
const char* retry_message = ci_env.retry_message();
|
||||
if (_compilation_log != NULL) {
|
||||
_compilation_log->log_failure(thread, task, ci_env.failure_reason(), retry_message);
|
||||
}
|
||||
if (PrintCompilation) {
|
||||
FormatBufferResource msg = retry_message != NULL ?
|
||||
FormatBufferResource("COMPILE SKIPPED: %s (%s)", ci_env.failure_reason(), retry_message) :
|
||||
FormatBufferResource("COMPILE SKIPPED: %s", ci_env.failure_reason());
|
||||
task->print(tty, msg);
|
||||
}
|
||||
failure_reason = ci_env.failure_reason();
|
||||
retry_message = ci_env.retry_message();
|
||||
ci_env.report_failure(failure_reason);
|
||||
}
|
||||
|
||||
post_compile(thread, task, event, !ci_env.failing(), &ci_env);
|
||||
}
|
||||
DirectivesStack::release(directive);
|
||||
// Remove the JNI handle block after the ciEnv destructor has run in
|
||||
// the previous block.
|
||||
pop_jni_handle_block();
|
||||
|
||||
if (failure_reason != NULL) {
|
||||
task->set_failure_reason(failure_reason);
|
||||
if (_compilation_log != NULL) {
|
||||
_compilation_log->log_failure(thread, task, failure_reason, retry_message);
|
||||
}
|
||||
if (PrintCompilation) {
|
||||
FormatBufferResource msg = retry_message != NULL ?
|
||||
FormatBufferResource("COMPILE SKIPPED: %s (%s)", failure_reason, retry_message) :
|
||||
FormatBufferResource("COMPILE SKIPPED: %s", failure_reason);
|
||||
task->print(tty, msg);
|
||||
}
|
||||
}
|
||||
|
||||
methodHandle method(thread, task->method());
|
||||
|
||||
DTRACE_METHOD_COMPILE_END_PROBE(method, compiler_name(task_level), task->is_success());
|
||||
|
||||
collect_statistics(thread, time, task);
|
||||
|
||||
bool printnmethods = directive->PrintAssemblyOption || directive->PrintNMethodsOption;
|
||||
if (printnmethods || PrintDebugInfo || PrintRelocations || PrintDependencies || PrintExceptionHandlers) {
|
||||
nmethod* nm = task->code();
|
||||
if (nm != NULL) {
|
||||
nm->print_nmethod(printnmethods);
|
||||
}
|
||||
}
|
||||
DirectivesStack::release(directive);
|
||||
|
||||
if (PrintCompilation && PrintCompilation2) {
|
||||
tty->print("%7d ", (int) tty->time_stamp().milliseconds()); // print timestamp
|
||||
tty->print("%4d ", compile_id); // print compilation number
|
||||
|
|
|
@ -233,6 +233,9 @@ class CompileBroker: AllStatic {
|
|||
const char* comment,
|
||||
bool blocking);
|
||||
static void wait_for_completion(CompileTask* task);
|
||||
#if INCLUDE_JVMCI
|
||||
static bool wait_for_jvmci_completion(CompileTask* task, JavaThread* thread);
|
||||
#endif
|
||||
|
||||
static void invoke_compiler_on_method(CompileTask* task);
|
||||
static void post_compile(CompilerThread* thread, CompileTask* task, EventCompilation& event, bool success, ciEnv* ci_env);
|
||||
|
|
|
@ -91,6 +91,7 @@ void CompileTask::initialize(int compile_id,
|
|||
_osr_bci = osr_bci;
|
||||
_is_blocking = is_blocking;
|
||||
JVMCI_ONLY(_has_waiter = CompileBroker::compiler(comp_level)->is_jvmci();)
|
||||
JVMCI_ONLY(_jvmci_compiler_thread = NULL;)
|
||||
_comp_level = comp_level;
|
||||
_num_inlined_bytecodes = 0;
|
||||
|
||||
|
|
|
@ -56,6 +56,8 @@ class CompileTask : public CHeapObj<mtCompiler> {
|
|||
bool _is_blocking;
|
||||
#if INCLUDE_JVMCI
|
||||
bool _has_waiter;
|
||||
// Compiler thread for a blocking JVMCI compilation
|
||||
CompilerThread* _jvmci_compiler_thread;
|
||||
#endif
|
||||
int _comp_level;
|
||||
int _num_inlined_bytecodes;
|
||||
|
@ -92,6 +94,12 @@ class CompileTask : public CHeapObj<mtCompiler> {
|
|||
#if INCLUDE_JVMCI
|
||||
bool has_waiter() const { return _has_waiter; }
|
||||
void clear_waiter() { _has_waiter = false; }
|
||||
CompilerThread* jvmci_compiler_thread() const { return _jvmci_compiler_thread; }
|
||||
void set_jvmci_compiler_thread(CompilerThread* t) {
|
||||
assert(is_blocking(), "must be");
|
||||
assert((t == NULL) != (_jvmci_compiler_thread == NULL), "must be");
|
||||
_jvmci_compiler_thread = t;
|
||||
}
|
||||
#endif
|
||||
|
||||
nmethodLocker* code_handle() const { return _code_handle; }
|
||||
|
|
|
@ -164,20 +164,15 @@ int CompilerDirectives::refcount() {
|
|||
|
||||
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()) {
|
||||
} else if (comp->is_c2()) {
|
||||
return _c2_store;
|
||||
} else if (comp->is_c1()) {
|
||||
} else {
|
||||
// use c1_store as default
|
||||
assert(comp->is_c1() || comp->is_jvmci() || comp->is_shark(), "");
|
||||
return _c1_store;
|
||||
} else if (comp->is_shark()) {
|
||||
return NULL;
|
||||
} else if (comp->is_jvmci()) {
|
||||
return NULL;
|
||||
}
|
||||
ShouldNotReachHere();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// In the list of disabled intrinsics, the ID of the disabled intrinsics can separated:
|
||||
|
@ -459,6 +454,7 @@ DirectiveSet* DirectivesStack::getDefaultDirective(AbstractCompiler* comp) {
|
|||
MutexLockerEx locker(DirectivesStack_lock, Mutex::_no_safepoint_check_flag);
|
||||
|
||||
assert(_bottom != NULL, "Must never be empty");
|
||||
_bottom->inc_refcount();
|
||||
return _bottom->get_for(comp);
|
||||
}
|
||||
|
||||
|
@ -521,12 +517,13 @@ void DirectivesStack::print(outputStream* st) {
|
|||
}
|
||||
|
||||
void DirectivesStack::release(DirectiveSet* set) {
|
||||
assert(set != NULL, "Never NULL");
|
||||
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, "");
|
||||
assert(set->directive() != NULL, "Never NULL");
|
||||
release(set->directive());
|
||||
}
|
||||
}
|
||||
|
@ -553,26 +550,18 @@ DirectiveSet* DirectivesStack::getMatchingDirective(methodHandle method, Abstrac
|
|||
while (dir != NULL) {
|
||||
if (dir->is_default_directive() || dir->match(method)) {
|
||||
match = dir->get_for(comp);
|
||||
if (match == NULL) {
|
||||
// temporary workaround for compilers without directives.
|
||||
if (dir->is_default_directive()) {
|
||||
// default dir is always enabled
|
||||
// match c1 store - it contains all common flags even if C1 is unavailable
|
||||
match = dir->_c1_store;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
if (match->EnableOption) {
|
||||
// The directiveSet for this compile is also enabled -> success
|
||||
break;
|
||||
}
|
||||
assert(match != NULL, "Consistency");
|
||||
if (match->EnableOption) {
|
||||
// The directiveSet for this compile is also enabled -> success
|
||||
dir->inc_refcount();
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -513,6 +513,7 @@ address decode_env::decode_instructions(address start, address end) {
|
|||
|
||||
|
||||
void Disassembler::decode(CodeBlob* cb, outputStream* st) {
|
||||
ttyLocker ttyl;
|
||||
if (!load_library()) return;
|
||||
if (cb->is_nmethod()) {
|
||||
decode((nmethod*)cb, st);
|
||||
|
@ -526,12 +527,14 @@ void Disassembler::decode(CodeBlob* cb, outputStream* st) {
|
|||
}
|
||||
|
||||
void Disassembler::decode(address start, address end, outputStream* st, CodeStrings c) {
|
||||
ttyLocker ttyl;
|
||||
if (!load_library()) return;
|
||||
decode_env env(CodeCache::find_blob_unsafe(start), st, c);
|
||||
env.decode_instructions(start, end);
|
||||
}
|
||||
|
||||
void Disassembler::decode(nmethod* nm, outputStream* st) {
|
||||
ttyLocker ttyl;
|
||||
if (!load_library()) return;
|
||||
decode_env env(nm, st);
|
||||
env.output()->print_cr("----------------------------------------------------------------------");
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue