< prev index next >

src/hotspot/share/compiler/compileBroker.cpp

Print this page

        

@@ -38,11 +38,10 @@
 #include "jfr/jfrEvents.hpp"
 #include "logging/log.hpp"
 #include "logging/logStream.hpp"
 #include "memory/allocation.inline.hpp"
 #include "memory/resourceArea.hpp"
-#include "memory/universe.hpp"
 #include "oops/methodData.hpp"
 #include "oops/method.inline.hpp"
 #include "oops/oop.inline.hpp"
 #include "prims/nativeLookup.hpp"
 #include "prims/whitebox.hpp"

@@ -67,12 +66,14 @@
 #include "utilities/macros.hpp"
 #ifdef COMPILER1
 #include "c1/c1_Compiler.hpp"
 #endif
 #if INCLUDE_JVMCI
-#include "jvmci/jvmciEnv.hpp"
+#include "jvmci/jvmciCompiler.hpp"
 #include "jvmci/jvmciRuntime.hpp"
+#include "jvmci/jvmciJavaClasses.hpp"
+#include "runtime/vframe.hpp"
 #endif
 #ifdef COMPILER2
 #include "opto/c2compiler.hpp"
 #endif
 

@@ -132,10 +133,15 @@
 
 // These counters are used to assign an unique ID to each compilation.
 volatile jint CompileBroker::_compilation_id     = 0;
 volatile jint CompileBroker::_osr_compilation_id = 0;
 
+// Debugging information
+int  CompileBroker::_last_compile_type     = no_compile;
+int  CompileBroker::_last_compile_level    = CompLevel_none;
+char CompileBroker::_last_method_compiled[CompileBroker::name_buffer_length];
+
 // Performance counters
 PerfCounter* CompileBroker::_perf_total_compilation = NULL;
 PerfCounter* CompileBroker::_perf_osr_compilation = NULL;
 PerfCounter* CompileBroker::_perf_standard_compilation = NULL;
 

@@ -190,11 +196,11 @@
   CompilationLog() : StringEventLog("Compilation events") {
   }
 
   void log_compile(JavaThread* thread, CompileTask* task) {
     StringLogMessage lm;
-    stringStream sstr(lm.buffer(), lm.size());
+    stringStream sstr = lm.stream();
     // msg.time_stamp().update_to(tty->time_stamp().ticks());
     task->print(&sstr, NULL, true, false);
     log(thread, "%s", (const char*)lm);
   }
 

@@ -399,11 +405,11 @@
   // save methods from RedefineClasses across safepoint
   // across MethodCompileQueue_lock below.
   methodHandle save_method;
   methodHandle save_hot_method;
 
-  MonitorLocker locker(MethodCompileQueue_lock);
+  MutexLocker locker(MethodCompileQueue_lock);
   // If _first is NULL we have no more compile jobs. There are two reasons for
   // having no compile jobs: First, we compiled everything we wanted. Second,
   // we ran out of code cache so compilation has been disabled. In the latter
   // case we perform code cache sweeps to free memory such that we can re-enable
   // compilation.

@@ -420,11 +426,11 @@
     // the stable state, i.e., we do not want to evict methods from the
     // code cache if it is unnecessary.
     // We need a timed wait here, since compiler threads can exit if compilation
     // is disabled forever. We use 5 seconds wait time; the exiting of compiler threads
     // is not critical and we do not want idle compiler threads to wake up too often.
-    locker.wait(5*1000);
+    MethodCompileQueue_lock->wait(!Mutex::_no_safepoint_check_flag, 5*1000);
 
     if (UseDynamicNumberOfCompilerThreads && _first == NULL) {
       // Still nothing to compile. Give caller a chance to stop this thread.
       if (can_remove(CompilerThread::current(), false)) return NULL;
     }

@@ -448,12 +454,12 @@
     // the compilation queue, which is walked during RedefineClasses.
     save_method = methodHandle(task->method());
     save_hot_method = methodHandle(task->hot_method());
 
     remove(task);
+    purge_stale_tasks(); // may temporarily release MCQ lock
   }
-  purge_stale_tasks(); // may temporarily release MCQ lock
   return task;
 }
 
 // Clean & deallocate stale compile tasks.
 // Temporarily releases MethodCompileQueue lock.

@@ -569,10 +575,12 @@
 // ------------------------------------------------------------------
 // CompileBroker::compilation_init
 //
 // Initialize the Compilation object
 void CompileBroker::compilation_init_phase1(TRAPS) {
+  _last_method_compiled[0] = '\0';
+
   // No need to initialize compilation system if we do not use it.
   if (!UseCompiler) {
     return;
   }
   // Set the interface to the current compiler(s).

@@ -1061,40 +1069,40 @@
       // The compilation falls outside the allowed range.
       return;
     }
 
 #if INCLUDE_JVMCI
-    if (UseJVMCICompiler && blocking) {
-      // Don't allow blocking compiles for requests triggered by JVMCI.
-      if (thread->is_Compiler_thread()) {
-        blocking = false;
-      }
+    if (UseJVMCICompiler) {
+      if (blocking) {
+        // Don't allow blocking compiles for requests triggered by JVMCI.
+        if (thread->is_Compiler_thread()) {
+          blocking = false;
+        }
 
-      if (!UseJVMCINativeLibrary) {
         // Don't allow blocking compiles if inside a class initializer or while performing class loading
         vframeStream vfst((JavaThread*) thread);
         for (; !vfst.at_end(); vfst.next()) {
           if (vfst.method()->is_static_initializer() ||
               (vfst.method()->method_holder()->is_subclass_of(SystemDictionary::ClassLoader_klass()) &&
                   vfst.method()->name() == vmSymbols::loadClass_name())) {
             blocking = false;
             break;
           }
         }
-      }
 
-      // Don't allow blocking compilation requests to JVMCI
-      // if JVMCI itself is not yet initialized
-      if (!JVMCI::is_compiler_initialized() && compiler(comp_level)->is_jvmci()) {
-        blocking = false;
-      }
+        // Don't allow blocking compilation requests to JVMCI
+        // if JVMCI itself is not yet initialized
+        if (!JVMCIRuntime::is_HotSpotJVMCIRuntime_initialized() && compiler(comp_level)->is_jvmci()) {
+          blocking = false;
+        }
 
-      // Don't allow blocking compilation requests if we are in JVMCIRuntime::shutdown
-      // to avoid deadlock between compiler thread(s) and threads run at shutdown
-      // such as the DestroyJavaVM thread.
-      if (JVMCI::shutdown_called()) {
-        blocking = false;
+        // Don't allow blocking compilation requests if we are in JVMCIRuntime::shutdown
+        // to avoid deadlock between compiler thread(s) and threads run at shutdown
+        // such as the DestroyJavaVM thread.
+        if (JVMCIRuntime::shutdown_called()) {
+          blocking = false;
+        }
       }
     }
 #endif // INCLUDE_JVMCI
 
     // We will enter the compilation in the queue.

@@ -1190,11 +1198,11 @@
       compilation_is_prohibited(method, osr_bci, comp_level, directive->ExcludeOption)) {
     return NULL;
   }
 
 #if INCLUDE_JVMCI
-  if (comp->is_jvmci() && !JVMCI::can_initialize_JVMCI()) {
+  if (comp->is_jvmci() && !JVMCIRuntime::can_initialize_JVMCI()) {
     return NULL;
   }
 #endif
 
   if (osr_bci == InvocationEntryBci) {

@@ -1493,15 +1501,15 @@
  * JVMCI_COMPILATION_PROGRESS_WAIT_ATTEMPTS.
  *
  * @return true if this thread needs to free/recycle the task
  */
 bool CompileBroker::wait_for_jvmci_completion(JVMCICompiler* jvmci, CompileTask* task, JavaThread* thread) {
-  MonitorLocker ml(task->lock(), thread);
+  MutexLocker waiter(task->lock(), thread);
   int progress_wait_attempts = 0;
   int methods_compiled = jvmci->methods_compiled();
   while (!task->is_complete() && !is_compilation_disabled_forever() &&
-         ml.wait(JVMCI_COMPILATION_PROGRESS_WAIT_TIMESLICE)) {
+         task->lock()->wait(!Mutex::_no_safepoint_check_flag, JVMCI_COMPILATION_PROGRESS_WAIT_TIMESLICE)) {
     CompilerThread* jvmci_compiler_thread = task->jvmci_compiler_thread();
 
     bool progress;
     if (jvmci_compiler_thread != NULL) {
       // If the JVMCI compiler thread is not blocked or suspended, we deem it to be making progress.

@@ -1555,14 +1563,14 @@
   if (comp->is_jvmci()) {
     free_task = wait_for_jvmci_completion((JVMCICompiler*) comp, task, thread);
   } else
 #endif
   {
-    MonitorLocker ml(task->lock(), thread);
+    MutexLocker waiter(task->lock(), thread);
     free_task = true;
     while (!task->is_complete() && !is_compilation_disabled_forever()) {
-      ml.wait();
+      task->lock()->wait();
     }
   }
 
   thread->set_blocked_on_compilation(false);
   if (free_task) {

@@ -1641,11 +1649,11 @@
  * out to be a problem.
  */
 void CompileBroker::shutdown_compiler_runtime(AbstractCompiler* comp, CompilerThread* thread) {
   // Free buffer blob, if allocated
   if (thread->get_buffer_blob() != NULL) {
-    MutexLocker mu(CodeCache_lock, Mutex::_no_safepoint_check_flag);
+    MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag);
     CodeCache::free(thread->get_buffer_blob());
   }
 
   if (comp->should_perform_shutdown()) {
     // There are two reasons for shutting down the compiler

@@ -1777,11 +1785,11 @@
             tty->print_cr("Removing compiler thread %s after " JLONG_FORMAT " ms idle time",
                           thread->name(), thread->idle_time_millis());
           }
           // Free buffer blob, if allocated
           if (thread->get_buffer_blob() != NULL) {
-            MutexLocker mu(CodeCache_lock, Mutex::_no_safepoint_check_flag);
+            MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag);
             CodeCache::free(thread->get_buffer_blob());
           }
           return; // Stop this thread.
         }
       }

@@ -1907,11 +1915,11 @@
 {
   ResourceMark rm;
   stringStream s;
   // Dump code cache  into a buffer before locking the tty,
   {
-    MutexLocker mu(CodeCache_lock, Mutex::_no_safepoint_check_flag);
+    MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag);
     CodeCache::print_summary(&s, detailed);
   }
   ttyLocker ttyl;
   tty->print("%s", s.as_string());
 }

@@ -1921,11 +1929,11 @@
   ResourceMark rm;
   stringStream s;
 
   // Dump code cache into a buffer
   {
-    MutexLocker mu(CodeCache_lock, Mutex::_no_safepoint_check_flag);
+    MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag);
     CodeCache::print_summary(&s, detailed);
   }
 
   char* remaining_log = s.as_string();
   while (*remaining_log != '\0') {

@@ -2022,14 +2030,12 @@
     assert(!method->is_native(), "no longer compile natives");
 
     // Look up matching directives
     directive = DirectivesStack::getMatchingDirective(method, comp);
 
-    // Update compile information when using perfdata.
-    if (UsePerfData) {
-      update_compile_perf_data(thread, method, is_osr);
-    }
+    // Save information about this method in case of failure.
+    set_last_compile(thread, method, is_osr, task_level);
 
     DTRACE_METHOD_COMPILE_BEGIN_PROBE(method, compiler_name(task_level));
   }
 
   should_break = directive->BreakAtExecuteOption || task->check_break_at_flags();

@@ -2058,28 +2064,24 @@
     TraceTime t1("compilation", &time);
     EventCompilation event;
 
     // Skip redefined methods
     if (target_handle->is_old()) {
-      failure_reason = "redefined method";
-      retry_message = "not retryable";
-      compilable = ciEnv::MethodCompilable_never;
-    } else {
-      JVMCICompileState compile_state(task, system_dictionary_modification_counter);
-      JVMCIEnv env(thread, &compile_state, __FILE__, __LINE__);
-      methodHandle method(thread, target_handle);
-      env.runtime()->compile_method(&env, jvmci, method, osr_bci);
-
-      failure_reason = compile_state.failure_reason();
-      failure_reason_on_C_heap = compile_state.failure_reason_on_C_heap();
-      if (!compile_state.retryable()) {
+        failure_reason = "redefined method";
         retry_message = "not retryable";
-        compilable = ciEnv::MethodCompilable_not_at_tier;
-      }
-      if (task->code() == NULL) {
-        assert(failure_reason != NULL, "must specify failure_reason");
-      }
+        compilable = ciEnv::MethodCompilable_never;
+    } else {
+        JVMCIEnv env(task, system_dictionary_modification_counter);
+        methodHandle method(thread, target_handle);
+        jvmci->compile_method(method, osr_bci, &env);
+
+        failure_reason = env.failure_reason();
+        failure_reason_on_C_heap = env.failure_reason_on_C_heap();
+        if (!env.retryable()) {
+          retry_message = "not retryable";
+          compilable = ciEnv::MethodCompilable_not_at_tier;
+        }
     }
     post_compile(thread, task, task->code() != NULL, NULL, compilable, failure_reason);
     if (event.should_commit()) {
       post_compilation_event(&event, task);
     }

@@ -2113,13 +2115,13 @@
 
     if (comp == NULL) {
       ci_env.record_method_not_compilable("no compiler", !TieredCompilation);
     } else {
       if (WhiteBoxAPI && WhiteBox::compilation_locked) {
-        MonitorLocker locker(Compilation_lock, Mutex::_no_safepoint_check_flag);
+        MonitorLockerEx locker(Compilation_lock, Mutex::_no_safepoint_check_flag);
         while (WhiteBox::compilation_locked) {
-          locker.wait();
+          locker.wait(Mutex::_no_safepoint_check_flag);
         }
       }
       comp->compile_method(&ci_env, target, osr_bci, directive);
     }
 

@@ -2260,53 +2262,62 @@
     CodeCache::report_codemem_full(code_blob_type, should_print_compiler_warning());
   }
 }
 
 // ------------------------------------------------------------------
-// CompileBroker::update_compile_perf_data
+// CompileBroker::set_last_compile
 //
 // Record this compilation for debugging purposes.
-void CompileBroker::update_compile_perf_data(CompilerThread* thread, const methodHandle& method, bool is_osr) {
+void CompileBroker::set_last_compile(CompilerThread* thread, const methodHandle& method, bool is_osr, int comp_level) {
   ResourceMark rm;
   char* method_name = method->name()->as_C_string();
+  strncpy(_last_method_compiled, method_name, CompileBroker::name_buffer_length);
+  _last_method_compiled[CompileBroker::name_buffer_length - 1] = '\0'; // ensure null terminated
   char current_method[CompilerCounters::cmname_buffer_length];
   size_t maxLen = CompilerCounters::cmname_buffer_length;
 
-  const char* class_name = method->method_holder()->name()->as_C_string();
+  if (UsePerfData) {
+    const char* class_name = method->method_holder()->name()->as_C_string();
 
-  size_t s1len = strlen(class_name);
-  size_t s2len = strlen(method_name);
+    size_t s1len = strlen(class_name);
+    size_t s2len = strlen(method_name);
 
-  // check if we need to truncate the string
-  if (s1len + s2len + 2 > maxLen) {
+    // check if we need to truncate the string
+    if (s1len + s2len + 2 > maxLen) {
 
-    // the strategy is to lop off the leading characters of the
-    // class name and the trailing characters of the method name.
+      // the strategy is to lop off the leading characters of the
+      // class name and the trailing characters of the method name.
 
-    if (s2len + 2 > maxLen) {
-      // lop of the entire class name string, let snprintf handle
-      // truncation of the method name.
-      class_name += s1len; // null string
-    }
-    else {
-      // lop off the extra characters from the front of the class name
-      class_name += ((s1len + s2len + 2) - maxLen);
+      if (s2len + 2 > maxLen) {
+        // lop of the entire class name string, let snprintf handle
+        // truncation of the method name.
+        class_name += s1len; // null string
+      }
+      else {
+        // lop off the extra characters from the front of the class name
+        class_name += ((s1len + s2len + 2) - maxLen);
+      }
     }
-  }
 
-  jio_snprintf(current_method, maxLen, "%s %s", class_name, method_name);
+    jio_snprintf(current_method, maxLen, "%s %s", class_name, method_name);
+  }
 
-  int last_compile_type = normal_compile;
   if (CICountOSR && is_osr) {
-    last_compile_type = osr_compile;
+    _last_compile_type = osr_compile;
+  } else {
+    _last_compile_type = normal_compile;
   }
+  _last_compile_level = comp_level;
 
-  CompilerCounters* counters = thread->counters();
-  counters->set_current_method(current_method);
-  counters->set_compile_type((jlong) last_compile_type);
+  if (UsePerfData) {
+    CompilerCounters* counters = thread->counters();
+    counters->set_current_method(current_method);
+    counters->set_compile_type((jlong)_last_compile_type);
+  }
 }
 
+
 // ------------------------------------------------------------------
 // CompileBroker::push_jni_handle_block
 //
 // Push on a new block of JNI handles.
 void CompileBroker::push_jni_handle_block() {

@@ -2605,10 +2616,25 @@
   tty->cr();
   tty->print_cr("  nmethod code size         : %8d bytes", nmethods_code_size);
   tty->print_cr("  nmethod total size        : %8d bytes", nmethods_size);
 }
 
+// Debugging output for failure
+void CompileBroker::print_last_compile() {
+  if (_last_compile_level != CompLevel_none &&
+      compiler(_last_compile_level) != NULL &&
+      _last_compile_type != no_compile) {
+    if (_last_compile_type == osr_compile) {
+      tty->print_cr("Last parse:  [osr]%d+++(%d) %s",
+                    _osr_compilation_id, _last_compile_level, _last_method_compiled);
+    } else {
+      tty->print_cr("Last parse:  %d+++(%d) %s",
+                    _compilation_id, _last_compile_level, _last_method_compiled);
+    }
+  }
+}
+
 // Print general/accumulated JIT information.
 void CompileBroker::print_info(outputStream *out) {
   if (out == NULL) out = tty;
   out->cr();
   out->print_cr("======================");

@@ -2679,29 +2705,29 @@
   // across user interaction.
   // Acquire this lock before acquiring the CodeCache_lock.
   // CodeHeapStateAnalytics_lock could be held by a concurrent thread for a long time,
   // leading to an unnecessarily long hold time of the CodeCache_lock.
   ts.update(); // record starting point
-  MutexLocker mu1(CodeHeapStateAnalytics_lock, Mutex::_no_safepoint_check_flag);
+  MutexLockerEx mu1(CodeHeapStateAnalytics_lock, Mutex::_no_safepoint_check_flag);
   out->print_cr("\n__ CodeHeapStateAnalytics lock wait took %10.3f seconds _________\n", ts.seconds());
 
   // If we serve an "allFun" call, it is beneficial to hold the CodeCache_lock
   // for the entire duration of aggregation and printing. That makes sure
   // we see a consistent picture and do not run into issues caused by
   // the CodeHeap being altered concurrently.
   Monitor* global_lock   = allFun ? CodeCache_lock : NULL;
   Monitor* function_lock = allFun ? NULL : CodeCache_lock;
   ts_global.update(); // record starting point
-  MutexLocker mu2(global_lock, Mutex::_no_safepoint_check_flag);
+  MutexLockerEx mu2(global_lock, Mutex::_no_safepoint_check_flag);
   if (global_lock != NULL) {
     out->print_cr("\n__ CodeCache (global) lock wait took %10.3f seconds _________\n", ts_global.seconds());
     ts_global.update(); // record starting point
   }
 
   if (aggregate) {
     ts.update(); // record starting point
-    MutexLocker mu3(function_lock, Mutex::_no_safepoint_check_flag);
+    MutexLockerEx mu3(function_lock, Mutex::_no_safepoint_check_flag);
     if (function_lock != NULL) {
       out->print_cr("\n__ CodeCache (function) lock wait took %10.3f seconds _________\n", ts.seconds());
     }
 
     ts.update(); // record starting point

@@ -2717,11 +2743,11 @@
   if (methodSpace) CodeCache::print_space(out);
   if (methodAge) CodeCache::print_age(out);
   if (methodNames) {
     // print_names() has shown to be sensitive to concurrent CodeHeap modifications.
     // Therefore, request  the CodeCache_lock before calling...
-    MutexLocker mu3(function_lock, Mutex::_no_safepoint_check_flag);
+    MutexLockerEx mu3(function_lock, Mutex::_no_safepoint_check_flag);
     CodeCache::print_names(out);
   }
   if (discard) CodeCache::discard(out);
 
   if (global_lock != NULL) {
< prev index next >