8230459: Test failed to resume JVMCI CompilerThread
authormdoerr
Mon, 21 Oct 2019 19:58:16 +0200
changeset 59050 7bbaa3c416e7
parent 59049 dc1899bb84c0
child 59051 f0312c7d5b37
8230459: Test failed to resume JVMCI CompilerThread Reviewed-by: dholmes, kvn
src/hotspot/share/compiler/compileBroker.cpp
src/hotspot/share/compiler/compileBroker.hpp
--- a/src/hotspot/share/compiler/compileBroker.cpp	Wed Nov 13 17:24:53 2019 +0800
+++ b/src/hotspot/share/compiler/compileBroker.cpp	Mon Oct 21 19:58:16 2019 +0200
@@ -299,7 +299,7 @@
 /**
  * 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");
   if (!ReduceNumberOfCompilerThreads) return false;
 
@@ -313,13 +313,32 @@
   // Keep thread alive for at least some time.
   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.
-  jobject last_compiler = c1 ? CompileBroker::compiler1_object(compiler_count - 1)
-                             : CompileBroker::compiler2_object(compiler_count - 1);
+  jobject last_compiler = c1 ? compiler1_object(compiler_count - 1)
+                             : compiler2_object(compiler_count - 1);
   if (ct->threadObj() == JNIHandles::resolve_non_null(last_compiler)) {
     if (do_it) {
       assert_locked_or_safepoint(CompileThread_lock); // Update must be consistent.
       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;
   }
@@ -426,7 +445,7 @@
 
     if (UseDynamicNumberOfCompilerThreads && _first == NULL) {
       // 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 @@
   char name_buffer[256];
 
   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.
     sprintf(name_buffer, "%s CompilerThread%d", _compilers[1]->name(), i);
     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_logs[i] = NULL;
 
@@ -912,6 +936,39 @@
         (int)(available_cc_np / (128*K)));
 
     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);
       if (ct == NULL) break;
       _compilers[1]->set_num_compiler_threads(i + 1);
--- a/src/hotspot/share/compiler/compileBroker.hpp	Wed Nov 13 17:24:53 2019 +0800
+++ b/src/hotspot/share/compiler/compileBroker.hpp	Mon Oct 21 19:58:16 2019 +0200
@@ -395,6 +395,8 @@
     return _compiler2_objects[idx];
   }
 
+  static bool can_remove(CompilerThread *ct, bool do_it);
+
   static CompileLog* get_log(CompilerThread* ct);
 
   static int get_total_compile_count() {            return _total_compile_count; }