8230459: Test failed to resume JVMCI CompilerThread

Reviewed-by: dholmes, kvn
This commit is contained in:
Martin Doerr 2019-10-21 19:58:16 +02:00
parent 9dd7038c43
commit 0a5f074a77
2 changed files with 64 additions and 5 deletions

View file

@ -299,7 +299,7 @@ CompileTaskWrapper::~CompileTaskWrapper() {
/** /**
* Check if a CompilerThread can be removed and update count if requested. * Check if a CompilerThread can be removed and update count if requested.
*/ */
static bool can_remove(CompilerThread *ct, bool do_it) { bool CompileBroker::can_remove(CompilerThread *ct, bool do_it) {
assert(UseDynamicNumberOfCompilerThreads, "or shouldn't be here"); assert(UseDynamicNumberOfCompilerThreads, "or shouldn't be here");
if (!ReduceNumberOfCompilerThreads) return false; if (!ReduceNumberOfCompilerThreads) return false;
@ -313,13 +313,32 @@ static bool can_remove(CompilerThread *ct, bool do_it) {
// Keep thread alive for at least some time. // Keep thread alive for at least some time.
if (ct->idle_time_millis() < (c1 ? 500 : 100)) return false; if (ct->idle_time_millis() < (c1 ? 500 : 100)) return false;
#if INCLUDE_JVMCI
if (compiler->is_jvmci()) {
// Handles for JVMCI thread objects may get released concurrently.
if (do_it) {
assert(CompileThread_lock->owner() == ct, "must be holding lock");
} else {
// Skip check if it's the last thread and let caller check again.
return true;
}
}
#endif
// We only allow the last compiler thread of each type to get removed. // We only allow the last compiler thread of each type to get removed.
jobject last_compiler = c1 ? CompileBroker::compiler1_object(compiler_count - 1) jobject last_compiler = c1 ? compiler1_object(compiler_count - 1)
: CompileBroker::compiler2_object(compiler_count - 1); : compiler2_object(compiler_count - 1);
if (ct->threadObj() == JNIHandles::resolve_non_null(last_compiler)) { if (ct->threadObj() == JNIHandles::resolve_non_null(last_compiler)) {
if (do_it) { if (do_it) {
assert_locked_or_safepoint(CompileThread_lock); // Update must be consistent. assert_locked_or_safepoint(CompileThread_lock); // Update must be consistent.
compiler->set_num_compiler_threads(compiler_count - 1); compiler->set_num_compiler_threads(compiler_count - 1);
#if INCLUDE_JVMCI
if (compiler->is_jvmci()) {
// Old j.l.Thread object can die when no longer referenced elsewhere.
JNIHandles::destroy_global(compiler2_object(compiler_count - 1));
_compiler2_objects[compiler_count - 1] = NULL;
}
#endif
} }
return true; return true;
} }
@ -426,7 +445,7 @@ CompileTask* CompileQueue::get() {
if (UseDynamicNumberOfCompilerThreads && _first == NULL) { if (UseDynamicNumberOfCompilerThreads && _first == NULL) {
// Still nothing to compile. Give caller a chance to stop this thread. // Still nothing to compile. Give caller a chance to stop this thread.
if (can_remove(CompilerThread::current(), false)) return NULL; if (CompileBroker::can_remove(CompilerThread::current(), false)) return NULL;
} }
} }
@ -842,10 +861,15 @@ void CompileBroker::init_compiler_sweeper_threads() {
char name_buffer[256]; char name_buffer[256];
for (int i = 0; i < _c2_count; i++) { for (int i = 0; i < _c2_count; i++) {
jobject thread_handle = NULL;
// Create all j.l.Thread objects for C1 and C2 threads here, but only one
// for JVMCI compiler which can create further ones on demand.
JVMCI_ONLY(if (!UseJVMCICompiler || !UseDynamicNumberOfCompilerThreads || i == 0) {)
// Create a name for our thread. // Create a name for our thread.
sprintf(name_buffer, "%s CompilerThread%d", _compilers[1]->name(), i); sprintf(name_buffer, "%s CompilerThread%d", _compilers[1]->name(), i);
Handle thread_oop = create_thread_oop(name_buffer, CHECK); Handle thread_oop = create_thread_oop(name_buffer, CHECK);
jobject thread_handle = JNIHandles::make_global(thread_oop); thread_handle = JNIHandles::make_global(thread_oop);
JVMCI_ONLY(})
_compiler2_objects[i] = thread_handle; _compiler2_objects[i] = thread_handle;
_compiler2_logs[i] = NULL; _compiler2_logs[i] = NULL;
@ -912,6 +936,39 @@ void CompileBroker::possibly_add_compiler_threads() {
(int)(available_cc_np / (128*K))); (int)(available_cc_np / (128*K)));
for (int i = old_c2_count; i < new_c2_count; i++) { for (int i = old_c2_count; i < new_c2_count; i++) {
#if INCLUDE_JVMCI
if (UseJVMCICompiler) {
// Native compiler threads as used in C1/C2 can reuse the j.l.Thread
// objects as their existence is completely hidden from the rest of
// the VM (and those compiler threads can't call Java code to do the
// creation anyway). For JVMCI we have to create new j.l.Thread objects
// as they are visible and we can see unexpected thread lifecycle
// transitions if we bind them to new JavaThreads.
if (!THREAD->can_call_java()) break;
char name_buffer[256];
sprintf(name_buffer, "%s CompilerThread%d", _compilers[1]->name(), i);
Handle thread_oop;
{
// We have to give up the lock temporarily for the Java calls.
MutexUnlocker mu(CompileThread_lock);
thread_oop = create_thread_oop(name_buffer, THREAD);
}
if (HAS_PENDING_EXCEPTION) {
if (TraceCompilerThreads) {
ResourceMark rm;
tty->print_cr("JVMCI compiler thread creation failed:");
PENDING_EXCEPTION->print();
}
CLEAR_PENDING_EXCEPTION;
break;
}
// Check if another thread has beaten us during the Java calls.
if (_compilers[1]->num_compiler_threads() != i) break;
jobject thread_handle = JNIHandles::make_global(thread_oop);
assert(compiler2_object(i) == NULL, "Old one must be released!");
_compiler2_objects[i] = thread_handle;
}
#endif
JavaThread *ct = make_thread(compiler2_object(i), _c2_compile_queue, _compilers[1], CHECK); JavaThread *ct = make_thread(compiler2_object(i), _c2_compile_queue, _compilers[1], CHECK);
if (ct == NULL) break; if (ct == NULL) break;
_compilers[1]->set_num_compiler_threads(i + 1); _compilers[1]->set_num_compiler_threads(i + 1);

View file

@ -395,6 +395,8 @@ public:
return _compiler2_objects[idx]; return _compiler2_objects[idx];
} }
static bool can_remove(CompilerThread *ct, bool do_it);
static CompileLog* get_log(CompilerThread* ct); static CompileLog* get_log(CompilerThread* ct);
static int get_total_compile_count() { return _total_compile_count; } static int get_total_compile_count() { return _total_compile_count; }