< prev index next >

src/hotspot/share/compiler/compileBroker.cpp

Print this page
@@ -21,21 +21,25 @@
   * questions.
   *
   */
  
  #include "precompiled.hpp"
+ #include "cds/aotLinkedClassBulkLoader.hpp"
+ #include "cds/cdsConfig.hpp"
  #include "classfile/javaClasses.inline.hpp"
  #include "classfile/symbolTable.hpp"
  #include "classfile/vmClasses.hpp"
  #include "classfile/vmSymbols.hpp"
  #include "code/codeCache.hpp"
  #include "code/codeHeapState.hpp"
  #include "code/dependencyContext.hpp"
+ #include "code/SCCache.hpp"
  #include "compiler/compilationLog.hpp"
  #include "compiler/compilationMemoryStatistic.hpp"
  #include "compiler/compilationPolicy.hpp"
  #include "compiler/compileBroker.hpp"
+ #include "compiler/compilerDefinitions.inline.hpp"
  #include "compiler/compileLog.hpp"
  #include "compiler/compilerEvent.hpp"
  #include "compiler/compilerOracle.hpp"
  #include "compiler/directivesParser.hpp"
  #include "gc/shared/memAllocator.hpp"

@@ -65,18 +69,20 @@
  #include "runtime/os.hpp"
  #include "runtime/perfData.hpp"
  #include "runtime/safepointVerifiers.hpp"
  #include "runtime/sharedRuntime.hpp"
  #include "runtime/threads.hpp"
- #include "runtime/threadSMR.hpp"
+ #include "runtime/threadSMR.inline.hpp"
  #include "runtime/timerTrace.hpp"
  #include "runtime/vframe.inline.hpp"
+ #include "services/management.hpp"
  #include "utilities/debug.hpp"
  #include "utilities/dtrace.hpp"
  #include "utilities/events.hpp"
  #include "utilities/formatBuffer.hpp"
  #include "utilities/macros.hpp"
+ #include "utilities/nonblockingQueue.inline.hpp"
  #ifdef COMPILER1
  #include "c1/c1_Compiler.hpp"
  #endif
  #ifdef COMPILER2
  #include "opto/c2compiler.hpp"

@@ -120,27 +126,34 @@
  #define DTRACE_METHOD_COMPILE_END_PROBE(method, comp_name, success)
  
  #endif // ndef DTRACE_ENABLED
  
  bool CompileBroker::_initialized = false;
+ bool CompileBroker::_replay_initialized = false;
  volatile bool CompileBroker::_should_block = false;
  volatile int  CompileBroker::_print_compilation_warning = 0;
  volatile jint CompileBroker::_should_compile_new_jobs = run_compilation;
  
  // The installed compiler(s)
- AbstractCompiler* CompileBroker::_compilers[2];
+ AbstractCompiler* CompileBroker::_compilers[3];
  
  // The maximum numbers of compiler threads to be determined during startup.
  int CompileBroker::_c1_count = 0;
  int CompileBroker::_c2_count = 0;
+ int CompileBroker::_c3_count = 0;
+ int CompileBroker::_sc_count = 0;
  
  // An array of compiler names as Java String objects
  jobject* CompileBroker::_compiler1_objects = nullptr;
  jobject* CompileBroker::_compiler2_objects = nullptr;
+ jobject* CompileBroker::_compiler3_objects = nullptr;
+ jobject* CompileBroker::_sc_objects = nullptr;
  
  CompileLog** CompileBroker::_compiler1_logs = nullptr;
  CompileLog** CompileBroker::_compiler2_logs = nullptr;
+ CompileLog** CompileBroker::_compiler3_logs = nullptr;
+ CompileLog** CompileBroker::_sc_logs = nullptr;
  
  // 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;
  volatile jint CompileBroker::_native_compilation_id = 0;

@@ -176,10 +189,11 @@
  elapsedTimer CompileBroker::_t_invalidated_compilation;
  elapsedTimer CompileBroker::_t_bailedout_compilation;
  
  uint CompileBroker::_total_bailout_count            = 0;
  uint CompileBroker::_total_invalidated_count        = 0;
+ uint CompileBroker::_total_not_entrant_count        = 0;
  uint CompileBroker::_total_compile_count            = 0;
  uint CompileBroker::_total_osr_compile_count        = 0;
  uint CompileBroker::_total_standard_compile_count   = 0;
  uint CompileBroker::_total_compiler_stopped_count   = 0;
  uint CompileBroker::_total_compiler_restarted_count = 0;

@@ -190,13 +204,18 @@
  uint CompileBroker::_sum_nmethod_code_size          = 0;
  
  jlong CompileBroker::_peak_compilation_time        = 0;
  
  CompilerStatistics CompileBroker::_stats_per_level[CompLevel_full_optimization];
+ CompilerStatistics CompileBroker::_scc_stats;
+ CompilerStatistics CompileBroker::_scc_stats_per_level[CompLevel_full_optimization + 1];
  
+ CompileQueue* CompileBroker::_c3_compile_queue     = nullptr;
  CompileQueue* CompileBroker::_c2_compile_queue     = nullptr;
  CompileQueue* CompileBroker::_c1_compile_queue     = nullptr;
+ CompileQueue* CompileBroker::_sc1_compile_queue    = nullptr;
+ CompileQueue* CompileBroker::_sc2_compile_queue    = nullptr;
  
  bool compileBroker_init() {
    if (LogEvents) {
      CompilationLog::init();
    }

@@ -223,20 +242,21 @@
  
  CompileTaskWrapper::~CompileTaskWrapper() {
    CompilerThread* thread = CompilerThread::current();
    CompileTask* task = thread->task();
    CompileLog*  log  = thread->log();
+   AbstractCompiler* comp = thread->compiler();
    if (log != nullptr && !task->is_unloaded())  task->log_task_done(log);
    thread->set_task(nullptr);
    thread->set_env(nullptr);
    if (task->is_blocking()) {
      bool free_task = false;
      {
        MutexLocker notifier(thread, task->lock());
        task->mark_complete();
  #if INCLUDE_JVMCI
-       if (CompileBroker::compiler(task->comp_level())->is_jvmci()) {
+       if (comp->is_jvmci()) {
          if (!task->has_waiter()) {
            // The waiting thread timed out and thus did not free the task.
            free_task = true;
          }
          task->set_blocking_jvmci_compile_state(nullptr);

@@ -266,10 +286,12 @@
   */
  bool CompileBroker::can_remove(CompilerThread *ct, bool do_it) {
    assert(UseDynamicNumberOfCompilerThreads, "or shouldn't be here");
    if (!ReduceNumberOfCompilerThreads) return false;
  
+   if (CompilationPolicy::have_recompilation_work()) return false;
+ 
    AbstractCompiler *compiler = ct->compiler();
    int compiler_count = compiler->num_compiler_threads();
    bool c1 = compiler->is_c1();
  
    // Keep at least 1 compiler thread of each type.

@@ -312,11 +334,11 @@
  
  /**
   * Add a CompileTask to a CompileQueue.
   */
  void CompileQueue::add(CompileTask* task) {
-   assert(MethodCompileQueue_lock->owned_by_self(), "must own lock");
+   assert(_lock->owned_by_self(), "must own lock");
  
    task->set_next(nullptr);
    task->set_prev(nullptr);
  
    if (_last == nullptr) {

@@ -338,30 +360,88 @@
    }
  
    // Mark the method as being in the compile queue.
    task->method()->set_queued_for_compilation();
  
+   task->mark_queued(os::elapsed_counter());
+ 
    if (CIPrintCompileQueue) {
      print_tty();
    }
  
    if (LogCompilation && xtty != nullptr) {
      task->log_task_queued();
    }
  
+   if (TrainingData::need_data() &&
+       !CDSConfig::is_dumping_final_static_archive()) { // FIXME: !!! MetaspaceShared::preload_and_dump() temporarily enables RecordTraining !!!
+     CompileTrainingData* tdata = CompileTrainingData::make(task);
+     if (tdata != nullptr) {
+       tdata->record_compilation_queued(task);
+       task->set_training_data(tdata);
+     }
+   }
+ 
    // Notify CompilerThreads that a task is available.
-   MethodCompileQueue_lock->notify_all();
+   _lock->notify_all();
+ }
+ 
+ void CompileQueue::add_pending(CompileTask* task) {
+   assert(_lock->owned_by_self() == false, "must NOT own lock");
+   assert(UseLockFreeCompileQueues, "");
+   task->method()->set_queued_for_compilation();
+   _queue.push(*task);
+   // FIXME: additional coordination needed? e.g., is it possible for compiler thread to block w/o processing pending tasks?
+   if (is_empty()) {
+     MutexLocker ml(_lock);
+     _lock->notify_all();
+   }
+ }
+ 
+ static bool process_pending(CompileTask* task) {
+ //  guarantee(task->method()->queued_for_compilation(), "");
+   if (task->is_unloaded()) {
+     return true; // unloaded
+   }
+   task->method()->set_queued_for_compilation(); // FIXME
+   if (task->method()->pending_queue_processed()) {
+     return true; // already queued
+   }
+   // Mark the method as being in the compile queue.
+   task->method()->set_pending_queue_processed();
+   if (CompileBroker::compilation_is_complete(task->method(), task->osr_bci(), task->comp_level(),
+                                              task->requires_online_compilation(), task->compile_reason())) {
+     return true; // already compiled
+   }
+   return false; // active
+ }
+ 
+ void CompileQueue::transfer_pending() {
+   assert(_lock->owned_by_self(), "must own lock");
+   while (!_queue.empty()) {
+     CompileTask* task = _queue.pop();
+     bool is_stale = process_pending(task);
+     if (is_stale) {
+       task->set_next(_first_stale);
+       task->set_prev(nullptr);
+       _first_stale = task;
+     } else {
+       add(task);
+     }
+   }
  }
  
  /**
   * Empties compilation queue by putting all compilation tasks onto
   * a freelist. Furthermore, the method wakes up all threads that are
   * waiting on a compilation task to finish. This can happen if background
   * compilation is disabled.
   */
  void CompileQueue::free_all() {
-   MutexLocker mu(MethodCompileQueue_lock);
+   MutexLocker mu(_lock);
+   transfer_pending();
+ 
    CompileTask* next = _first;
  
    // Iterate over all tasks in the compile queue
    while (next != nullptr) {
      CompileTask* current = next;

@@ -376,23 +456,27 @@
    }
    _first = nullptr;
    _last = nullptr;
  
    // Wake up all threads that block on the queue.
-   MethodCompileQueue_lock->notify_all();
+   _lock->notify_all();
  }
  
  /**
   * Get the next CompileTask from a CompileQueue
   */
  CompileTask* CompileQueue::get(CompilerThread* thread) {
    // save methods from RedefineClasses across safepoint
-   // across MethodCompileQueue_lock below.
+   // across compile queue lock below.
    methodHandle save_method;
    methodHandle save_hot_method;
  
-   MonitorLocker locker(MethodCompileQueue_lock);
+   MonitorLocker locker(_lock);
+   transfer_pending();
+ 
+   CompilationPolicy::sample_load_average();
+ 
    // 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.

@@ -417,10 +501,14 @@
      // 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);
  
+     transfer_pending(); // reacquired lock
+ 
+     if (CompilationPolicy::have_recompilation_work()) return nullptr;
+ 
      if (UseDynamicNumberOfCompilerThreads && _first == nullptr) {
        // Still nothing to compile. Give caller a chance to stop this thread.
        if (CompileBroker::can_remove(CompilerThread::current(), false)) return nullptr;
      }
    }

@@ -430,11 +518,11 @@
    }
  
    CompileTask* task;
    {
      NoSafepointVerifier nsv;
-     task = CompilationPolicy::select_task(this);
+     task = CompilationPolicy::select_task(this, thread);
      if (task != nullptr) {
        task = task->select_for_compilation();
      }
    }
  

@@ -452,32 +540,33 @@
  }
  
  // Clean & deallocate stale compile tasks.
  // Temporarily releases MethodCompileQueue lock.
  void CompileQueue::purge_stale_tasks() {
-   assert(MethodCompileQueue_lock->owned_by_self(), "must own lock");
+   assert(_lock->owned_by_self(), "must own lock");
    if (_first_stale != nullptr) {
      // Stale tasks are purged when MCQ lock is released,
      // but _first_stale updates are protected by MCQ lock.
      // Once task processing starts and MCQ lock is released,
      // other compiler threads can reuse _first_stale.
      CompileTask* head = _first_stale;
      _first_stale = nullptr;
      {
-       MutexUnlocker ul(MethodCompileQueue_lock);
+       MutexUnlocker ul(_lock);
        for (CompileTask* task = head; task != nullptr; ) {
          CompileTask* next_task = task->next();
          CompileTaskWrapper ctw(task); // Frees the task
          task->set_failure_reason("stale task");
          task = next_task;
        }
      }
+     transfer_pending(); // transfer pending after reacquiring MCQ lock
    }
  }
  
  void CompileQueue::remove(CompileTask* task) {
-   assert(MethodCompileQueue_lock->owned_by_self(), "must own lock");
+   assert(_lock->owned_by_self(), "must own lock");
    if (task->prev() != nullptr) {
      task->prev()->set_next(task->next());
    } else {
      // max is the first element
      assert(task == _first, "Sanity");

@@ -494,11 +583,11 @@
    --_size;
    ++_total_removed;
  }
  
  void CompileQueue::remove_and_mark_stale(CompileTask* task) {
-   assert(MethodCompileQueue_lock->owned_by_self(), "must own lock");
+   assert(_lock->owned_by_self(), "must own lock");
    remove(task);
  
    // Enqueue the task for reclamation (should be done outside MCQ lock)
    task->set_next(_first_stale);
    task->set_prev(nullptr);

@@ -506,21 +595,23 @@
  }
  
  // methods in the compile queue need to be marked as used on the stack
  // so that they don't get reclaimed by Redefine Classes
  void CompileQueue::mark_on_stack() {
-   CompileTask* task = _first;
-   while (task != nullptr) {
+   for (CompileTask* task = _first; task != nullptr; task = task->next()) {
+     task->mark_on_stack();
+   }
+   for (CompileTask* task = _queue.first(); !_queue.is_end(task); task = task->next()) {
+     assert(task != nullptr, "");
      task->mark_on_stack();
-     task = task->next();
    }
  }
  
  
- CompileQueue* CompileBroker::compile_queue(int comp_level) {
-   if (is_c2_compile(comp_level)) return _c2_compile_queue;
-   if (is_c1_compile(comp_level)) return _c1_compile_queue;
+ CompileQueue* CompileBroker::compile_queue(int comp_level, bool is_scc) {
+   if (is_c2_compile(comp_level)) return ((is_scc  && (_sc_count > 0)) ? _sc2_compile_queue : _c2_compile_queue);
+   if (is_c1_compile(comp_level)) return ((is_scc && (_sc_count > 0)) ? _sc1_compile_queue : _c1_compile_queue);
    return nullptr;
  }
  
  CompileQueue* CompileBroker::c1_compile_queue() {
    return _c1_compile_queue;

@@ -542,14 +633,23 @@
      _c1_compile_queue->print(st);
    }
    if (_c2_compile_queue != nullptr) {
      _c2_compile_queue->print(st);
    }
+   if (_c3_compile_queue != nullptr) {
+     _c3_compile_queue->print(st);
+   }
+   if (_sc1_compile_queue != nullptr) {
+     _sc1_compile_queue->print(st);
+   }
+   if (_sc2_compile_queue != nullptr) {
+     _sc2_compile_queue->print(st);
+   }
  }
  
  void CompileQueue::print(outputStream* st) {
-   assert_locked_or_safepoint(MethodCompileQueue_lock);
+   assert_locked_or_safepoint(_lock);
    st->print_cr("%s:", name());
    CompileTask* task = _first;
    if (task == nullptr) {
      st->print_cr("Empty");
    } else {

@@ -612,10 +712,12 @@
      return;
    }
    // Set the interface to the current compiler(s).
    _c1_count = CompilationPolicy::c1_count();
    _c2_count = CompilationPolicy::c2_count();
+   _c3_count = CompilationPolicy::c3_count();
+   _sc_count = CompilationPolicy::sc_count();
  
  #if INCLUDE_JVMCI
    if (EnableJVMCI) {
      // This is creating a JVMCICompiler singleton.
      JVMCICompiler* jvmci = new JVMCICompiler();

@@ -634,10 +736,15 @@
        } else {
  #ifdef COMPILER1
          _c1_count = JVMCIHostThreads;
  #endif // COMPILER1
        }
+ #ifdef COMPILER2
+       if (SCCache::is_on() && (_c3_count > 0)) {
+         _compilers[2] = new C2Compiler();
+       }
+ #endif
      }
    }
  #endif // INCLUDE_JVMCI
  
  #ifdef COMPILER1

@@ -768,13 +875,23 @@
                                            PerfData::U_None,
                                            (jlong)CompileBroker::no_compile,
                                            CHECK);
    }
  
+   log_info(scc, init)("CompileBroker is initialized");
    _initialized = true;
  }
  
+ Handle CompileBroker::create_thread_oop(const char* name, TRAPS) {
+   Handle thread_oop = JavaThread::create_system_thread_object(name, CHECK_NH);
+   return thread_oop;
+ }
+ 
+ void TrainingReplayThread::training_replay_thread_entry(JavaThread* thread, TRAPS) {
+   CompilationPolicy::replay_training_at_init_loop(thread);
+ }
+ 
  #if defined(ASSERT) && COMPILER2_OR_JVMCI
  // Stress testing. Dedicated threads revert optimizations based on escape analysis concurrently to
  // the running java application.  Configured with vm options DeoptimizeObjectsALot*.
  class DeoptimizeObjectsALotThread : public JavaThread {
  

@@ -862,10 +979,13 @@
  #if defined(ASSERT) && COMPILER2_OR_JVMCI
      case deoptimizer_t:
        new_thread = new DeoptimizeObjectsALotThread();
        break;
  #endif // ASSERT
+     case training_replay_t:
+       new_thread = new TrainingReplayThread();
+       break;
      default:
        ShouldNotReachHere();
    }
  
    // At this point the new CompilerThread data-races with this startup

@@ -941,47 +1061,69 @@
      LogStream ls(lt);
      ls.print_cr("%s", msg.as_string());
    }
  }
  
+ static void print_compiler_thread(JavaThread *ct) {
+   if (trace_compiler_threads()) {
+     ResourceMark rm;
+     ThreadsListHandle tlh;  // name() depends on the TLH.
+     assert(tlh.includes(ct), "ct=" INTPTR_FORMAT " exited unexpectedly.", p2i(ct));
+     stringStream msg;
+     msg.print("Added initial compiler thread %s", ct->name());
+     print_compiler_threads(msg);
+   }
+ }
+ 
  void CompileBroker::init_compiler_threads() {
    // Ensure any exceptions lead to vm_exit_during_initialization.
    EXCEPTION_MARK;
  #if !defined(ZERO)
    assert(_c2_count > 0 || _c1_count > 0, "No compilers?");
  #endif // !ZERO
    // Initialize the compilation queue
    if (_c2_count > 0) {
      const char* name = JVMCI_ONLY(UseJVMCICompiler ? "JVMCI compile queue" :) "C2 compile queue";
-     _c2_compile_queue  = new CompileQueue(name);
+     _c2_compile_queue  = new CompileQueue(name, MethodCompileQueueC2_lock);
      _compiler2_objects = NEW_C_HEAP_ARRAY(jobject, _c2_count, mtCompiler);
      _compiler2_logs = NEW_C_HEAP_ARRAY(CompileLog*, _c2_count, mtCompiler);
    }
    if (_c1_count > 0) {
-     _c1_compile_queue  = new CompileQueue("C1 compile queue");
+     _c1_compile_queue  = new CompileQueue("C1 compile queue", MethodCompileQueueC1_lock);
      _compiler1_objects = NEW_C_HEAP_ARRAY(jobject, _c1_count, mtCompiler);
      _compiler1_logs = NEW_C_HEAP_ARRAY(CompileLog*, _c1_count, mtCompiler);
    }
  
+   if (_c3_count > 0) {
+     const char* name = "C2 compile queue";
+     _c3_compile_queue  = new CompileQueue(name, MethodCompileQueueC3_lock);
+     _compiler3_objects = NEW_C_HEAP_ARRAY(jobject, _c3_count, mtCompiler);
+     _compiler3_logs = NEW_C_HEAP_ARRAY(CompileLog*, _c3_count, mtCompiler);
+   }
+   if (_sc_count > 0) {
+     if (_c1_count > 0) { // C1 is present
+       _sc1_compile_queue  = new CompileQueue("C1 SC compile queue", MethodCompileQueueSC1_lock);
+     }
+     if (_c2_count > 0) { // C2 is present
+       _sc2_compile_queue  = new CompileQueue("C2 SC compile queue", MethodCompileQueueSC2_lock);
+     }
+     _sc_objects = NEW_C_HEAP_ARRAY(jobject, _sc_count, mtCompiler);
+     _sc_logs = NEW_C_HEAP_ARRAY(CompileLog*, _sc_count, mtCompiler);
+   }
+   char name_buffer[256];
+ 
    for (int i = 0; i < _c2_count; i++) {
      // Create a name for our thread.
      jobject thread_handle = create_compiler_thread(_compilers[1], i, CHECK);
      _compiler2_objects[i] = thread_handle;
      _compiler2_logs[i] = nullptr;
  
      if (!UseDynamicNumberOfCompilerThreads || i == 0) {
        JavaThread *ct = make_thread(compiler_t, thread_handle, _c2_compile_queue, _compilers[1], THREAD);
        assert(ct != nullptr, "should have been handled for initial thread");
        _compilers[1]->set_num_compiler_threads(i + 1);
-       if (trace_compiler_threads()) {
-         ResourceMark rm;
-         ThreadsListHandle tlh;  // name() depends on the TLH.
-         assert(tlh.includes(ct), "ct=" INTPTR_FORMAT " exited unexpectedly.", p2i(ct));
-         stringStream msg;
-         msg.print("Added initial compiler thread %s", ct->name());
-         print_compiler_threads(msg);
-       }
+       print_compiler_thread(ct);
      }
    }
  
    for (int i = 0; i < _c1_count; i++) {
      // Create a name for our thread.

@@ -991,23 +1133,57 @@
  
      if (!UseDynamicNumberOfCompilerThreads || i == 0) {
        JavaThread *ct = make_thread(compiler_t, thread_handle, _c1_compile_queue, _compilers[0], THREAD);
        assert(ct != nullptr, "should have been handled for initial thread");
        _compilers[0]->set_num_compiler_threads(i + 1);
-       if (trace_compiler_threads()) {
-         ResourceMark rm;
-         ThreadsListHandle tlh;  // name() depends on the TLH.
-         assert(tlh.includes(ct), "ct=" INTPTR_FORMAT " exited unexpectedly.", p2i(ct));
-         stringStream msg;
-         msg.print("Added initial compiler thread %s", ct->name());
-         print_compiler_threads(msg);
-       }
+       print_compiler_thread(ct);
+     }
+   }
+ 
+   for (int i = 0; i < _c3_count; i++) {
+     // Create a name for our thread.
+     os::snprintf_checked(name_buffer, sizeof(name_buffer), "C2 CompilerThread%d", i);
+     Handle thread_oop = create_thread_oop(name_buffer, CHECK);
+     jobject thread_handle = JNIHandles::make_global(thread_oop);
+     _compiler3_objects[i] = thread_handle;
+     _compiler3_logs[i] = nullptr;
+ 
+     JavaThread *ct = make_thread(compiler_t, thread_handle, _c3_compile_queue, _compilers[2], THREAD);
+     assert(ct != nullptr, "should have been handled for initial thread");
+     _compilers[2]->set_num_compiler_threads(i + 1);
+     print_compiler_thread(ct);
+   }
+ 
+   if (_sc_count > 0) {
+     int i = 0;
+     if (_c1_count > 0) { // C1 is present
+       os::snprintf_checked(name_buffer, sizeof(name_buffer), "C%d SC CompilerThread", 1);
+       Handle thread_oop = create_thread_oop(name_buffer, CHECK);
+       jobject thread_handle = JNIHandles::make_global(thread_oop);
+       _sc_objects[i] = thread_handle;
+       _sc_logs[i] = nullptr;
+       i++;
+ 
+       JavaThread *ct = make_thread(compiler_t, thread_handle, _sc1_compile_queue, _compilers[0], THREAD);
+       assert(ct != nullptr, "should have been handled for initial thread");
+       print_compiler_thread(ct);
+     }
+     if (_c2_count > 0) { // C2 is present
+       os::snprintf_checked(name_buffer, sizeof(name_buffer), "C%d SC CompilerThread", 2);
+       Handle thread_oop = create_thread_oop(name_buffer, CHECK);
+       jobject thread_handle = JNIHandles::make_global(thread_oop);
+       _sc_objects[i] = thread_handle;
+       _sc_logs[i] = nullptr;
+ 
+       JavaThread *ct = make_thread(compiler_t, thread_handle, _sc2_compile_queue, _compilers[1], THREAD);
+       assert(ct != nullptr, "should have been handled for initial thread");
+       print_compiler_thread(ct);
      }
    }
  
    if (UsePerfData) {
-     PerfDataManager::create_constant(SUN_CI, "threads", PerfData::U_Bytes, _c1_count + _c2_count, CHECK);
+     PerfDataManager::create_constant(SUN_CI, "threads", PerfData::U_Bytes, _c1_count + _c2_count + _c3_count, CHECK);
    }
  
  #if defined(ASSERT) && COMPILER2_OR_JVMCI
    if (DeoptimizeObjectsALot) {
      // Initialize and start the object deoptimizer threads

@@ -1019,10 +1195,23 @@
      }
    }
  #endif // defined(ASSERT) && COMPILER2_OR_JVMCI
  }
  
+ void CompileBroker::init_training_replay() {
+   // Ensure any exceptions lead to vm_exit_during_initialization.
+   EXCEPTION_MARK;
+   if (TrainingData::have_data()) {
+     if (UseConcurrentTrainingReplay) {
+       Handle thread_oop = create_thread_oop("Training replay thread", CHECK);
+       jobject thread_handle = JNIHandles::make_local(THREAD, thread_oop());
+       make_thread(training_replay_t, thread_handle, nullptr, nullptr, THREAD);
+     }
+     _replay_initialized = true;
+   }
+ }
+ 
  void CompileBroker::possibly_add_compiler_threads(JavaThread* THREAD) {
  
    julong free_memory = os::free_memory();
    // If SegmentedCodeCache is off, both values refer to the single heap (with type CodeBlobType::All).
    size_t available_cc_np  = CodeCache::unallocated_capacity(CodeBlobType::MethodNonProfiled),

@@ -1125,16 +1314,25 @@
   */
  void CompileBroker::mark_on_stack() {
    assert(SafepointSynchronize::is_at_safepoint(), "sanity check");
    // Since we are at a safepoint, we do not need a lock to access
    // the compile queues.
+   if (_c3_compile_queue != nullptr) {
+     _c3_compile_queue->mark_on_stack();
+   }
    if (_c2_compile_queue != nullptr) {
      _c2_compile_queue->mark_on_stack();
    }
    if (_c1_compile_queue != nullptr) {
      _c1_compile_queue->mark_on_stack();
    }
+   if (_sc1_compile_queue != nullptr) {
+     _sc1_compile_queue->mark_on_stack();
+   }
+   if (_sc2_compile_queue != nullptr) {
+     _sc2_compile_queue->mark_on_stack();
+   }
  }
  
  // ------------------------------------------------------------------
  // CompileBroker::compile_method
  //

@@ -1143,17 +1341,20 @@
                                          int osr_bci,
                                          int comp_level,
                                          const methodHandle& hot_method,
                                          int hot_count,
                                          CompileTask::CompileReason compile_reason,
+                                         bool requires_online_compilation,
                                          bool blocking,
                                          Thread* thread) {
    guarantee(!method->is_abstract(), "cannot compile abstract methods");
    assert(method->method_holder()->is_instance_klass(),
           "sanity check");
-   assert(!method->method_holder()->is_not_initialized(),
-          "method holder must be initialized");
+   assert(!method->method_holder()->is_not_initialized()   ||
+          compile_reason == CompileTask::Reason_Preload    ||
+          compile_reason == CompileTask::Reason_Precompile ||
+          compile_reason == CompileTask::Reason_PrecompileForPreload, "method holder must be initialized");
    assert(!method->is_method_handle_intrinsic(), "do not enqueue these guys");
  
    if (CIPrintRequests) {
      tty->print("request: ");
      method->print_short_name(tty);

@@ -1173,11 +1374,11 @@
    }
  
    // A request has been made for compilation.  Before we do any
    // real work, check to see if the method has been compiled
    // in the meantime with a definitive result.
-   if (compilation_is_complete(method, osr_bci, comp_level)) {
+   if (compilation_is_complete(method(), osr_bci, comp_level, requires_online_compilation, compile_reason)) {
      return;
    }
  
  #ifndef PRODUCT
    if (osr_bci != -1 && !FLAG_IS_DEFAULT(OSROnlyBCI)) {

@@ -1202,19 +1403,32 @@
      return;
    }
  
    // Tiered policy requires MethodCounters to exist before adding a method to
    // the queue. Create if we don't have them yet.
-   method->get_method_counters(thread);
+   if (compile_reason != CompileTask::Reason_Preload) {
+     method->get_method_counters(thread);
+   }
+ 
+   SCCEntry* scc_entry = find_scc_entry(method, osr_bci, comp_level, compile_reason, requires_online_compilation);
+   bool is_scc = (scc_entry != nullptr);
  
    // Outputs from the following MutexLocker block:
-   CompileTask* task     = nullptr;
-   CompileQueue* queue  = compile_queue(comp_level);
+   CompileTask* task = nullptr;
+   CompileQueue* queue;
+ #if INCLUDE_JVMCI
+   if (is_c2_compile(comp_level) && compiler2()->is_jvmci() && compiler3() != nullptr &&
+       ((JVMCICompiler*)compiler2())->force_comp_at_level_simple(method)) {
+     assert(_c3_compile_queue != nullptr, "sanity");
+     queue = _c3_compile_queue; // JVMCI compiler's methods compilation
+   } else
+ #endif
+   queue = compile_queue(comp_level, is_scc);
  
    // Acquire our lock.
    {
-     MutexLocker locker(thread, MethodCompileQueue_lock);
+     ConditionalMutexLocker locker(thread, queue->lock(), !UseLockFreeCompileQueues);
  
      // Make sure the method has not slipped into the queues since
      // last we checked; note that those checks were "fast bail-outs".
      // Here we need to be more careful, see 14012000 below.
      if (compilation_is_in_queue(method)) {

@@ -1222,11 +1436,11 @@
      }
  
      // We need to check again to see if the compilation has
      // completed.  A previous compilation may have registered
      // some result.
-     if (compilation_is_complete(method, osr_bci, comp_level)) {
+     if (compilation_is_complete(method(), osr_bci, comp_level, requires_online_compilation, compile_reason)) {
        return;
      }
  
      // We now know that this compilation is not pending, complete,
      // or prohibited.  Assign a compile_id to this compilation

@@ -1312,29 +1526,65 @@
      // these bits, and their updating (here and elsewhere) under a
      // common lock.
      task = create_compile_task(queue,
                                 compile_id, method,
                                 osr_bci, comp_level,
-                                hot_method, hot_count, compile_reason,
-                                blocking);
+                                hot_method, hot_count, scc_entry, compile_reason,
+                                requires_online_compilation, blocking);
+ 
+     if (task->is_scc() && (_sc_count > 0)) {
+       // Put it on SC queue
+       queue = is_c1_compile(comp_level) ? _sc1_compile_queue : _sc2_compile_queue;
+     }
+ 
+     if (UseLockFreeCompileQueues) {
+       assert(queue->lock()->owned_by_self() == false, "");
+       queue->add_pending(task);
+     } else {
+       queue->add(task);
+     }
    }
  
    if (blocking) {
      wait_for_completion(task);
    }
  }
  
+ SCCEntry* CompileBroker::find_scc_entry(const methodHandle& method, int osr_bci, int comp_level,
+                                         CompileTask::CompileReason compile_reason,
+                                         bool requires_online_compilation) {
+   SCCEntry* scc_entry = nullptr;
+   if (osr_bci == InvocationEntryBci && !requires_online_compilation && SCCache::is_on_for_read()) {
+     // Check for cached code.
+     if (compile_reason == CompileTask::Reason_Preload) {
+       scc_entry = method->scc_entry();
+       assert(scc_entry != nullptr && scc_entry->for_preload(), "sanity");
+     } else {
+       scc_entry = SCCache::find_code_entry(method, comp_level);
+     }
+   }
+   return scc_entry;
+ }
+ 
  nmethod* CompileBroker::compile_method(const methodHandle& method, int osr_bci,
                                         int comp_level,
                                         const methodHandle& hot_method, int hot_count,
+                                        bool requires_online_compilation,
                                         CompileTask::CompileReason compile_reason,
                                         TRAPS) {
    // Do nothing if compilebroker is not initialized or compiles are submitted on level none
    if (!_initialized || comp_level == CompLevel_none) {
      return nullptr;
    }
  
+ #if INCLUDE_JVMCI
+   if (EnableJVMCI && UseJVMCICompiler &&
+       comp_level == CompLevel_full_optimization && !AOTLinkedClassBulkLoader::class_preloading_finished()) {
+     return nullptr;
+   }
+ #endif
+ 
    AbstractCompiler *comp = CompileBroker::compiler(comp_level);
    assert(comp != nullptr, "Ensure we have a compiler");
  
  #if INCLUDE_JVMCI
    if (comp->is_jvmci() && !JVMCI::can_initialize_JVMCI()) {

@@ -1343,29 +1593,37 @@
    }
  #endif
  
    DirectiveSet* directive = DirectivesStack::getMatchingDirective(method, comp);
    // CompileBroker::compile_method can trap and can have pending async exception.
-   nmethod* nm = CompileBroker::compile_method(method, osr_bci, comp_level, hot_method, hot_count, compile_reason, directive, THREAD);
+   nmethod* nm = CompileBroker::compile_method(method, osr_bci, comp_level, hot_method, hot_count, requires_online_compilation, compile_reason, directive, THREAD);
    DirectivesStack::release(directive);
    return nm;
  }
  
  nmethod* CompileBroker::compile_method(const methodHandle& method, int osr_bci,
                                           int comp_level,
                                           const methodHandle& hot_method, int hot_count,
+                                          bool requires_online_compilation,
                                           CompileTask::CompileReason compile_reason,
                                           DirectiveSet* directive,
                                           TRAPS) {
  
    // make sure arguments make sense
    assert(method->method_holder()->is_instance_klass(), "not an instance method");
    assert(osr_bci == InvocationEntryBci || (0 <= osr_bci && osr_bci < method->code_size()), "bci out of range");
    assert(!method->is_abstract() && (osr_bci == InvocationEntryBci || !method->is_native()), "cannot compile abstract/native methods");
-   assert(!method->method_holder()->is_not_initialized(), "method holder must be initialized");
+   assert(!method->method_holder()->is_not_initialized()   ||
+          compile_reason == CompileTask::Reason_Preload    ||
+          compile_reason == CompileTask::Reason_Precompile ||
+          compile_reason == CompileTask::Reason_PrecompileForPreload, "method holder must be initialized");
    // return quickly if possible
  
+   if (PrecompileOnlyAndExit && !CompileTask::reason_is_precompiled(compile_reason)) {
+     return nullptr;
+   }
+ 
    // lock, make sure that the compilation
    // isn't prohibited in a straightforward way.
    AbstractCompiler* comp = CompileBroker::compiler(comp_level);
    if (comp == nullptr || compilation_is_prohibited(method, osr_bci, comp_level, directive->ExcludeOption)) {
      return nullptr;

@@ -1373,11 +1631,11 @@
  
    if (osr_bci == InvocationEntryBci) {
      // standard compilation
      nmethod* method_code = method->code();
      if (method_code != nullptr) {
-       if (compilation_is_complete(method, osr_bci, comp_level)) {
+       if (compilation_is_complete(method(), osr_bci, comp_level, requires_online_compilation, compile_reason)) {
          return method_code;
        }
      }
      if (method->is_not_compilable(comp_level)) {
        return nullptr;

@@ -1390,11 +1648,11 @@
      if (method->is_not_osr_compilable(comp_level)) return nullptr;
    }
  
    assert(!HAS_PENDING_EXCEPTION, "No exception should be present");
    // some prerequisites that are compiler specific
-   if (comp->is_c2() || comp->is_jvmci()) {
+   if (compile_reason != CompileTask::Reason_Preload && (comp->is_c2() || comp->is_jvmci())) {
      InternalOOMEMark iom(THREAD);
      method->constants()->resolve_string_constants(CHECK_AND_CLEAR_NONASYNC_NULL);
      // Resolve all classes seen in the signature of the method
      // we are compiling.
      Method::load_signature_classes(method, CHECK_AND_CLEAR_NONASYNC_NULL);

@@ -1469,12 +1727,15 @@
      // If the compiler is shut off due to code cache getting full
      // fail out now so blocking compiles dont hang the java thread
      if (!should_compile_new_jobs()) {
        return nullptr;
      }
-     bool is_blocking = !directive->BackgroundCompilationOption || ReplayCompiles;
-     compile_method_base(method, osr_bci, comp_level, hot_method, hot_count, compile_reason, is_blocking, THREAD);
+     bool is_blocking = ReplayCompiles                                             ||
+                        !directive->BackgroundCompilationOption                    ||
+                        (compile_reason == CompileTask::Reason_Precompile)         ||
+                        (compile_reason == CompileTask::Reason_PrecompileForPreload);
+ 	  compile_method_base(method, osr_bci, comp_level, hot_method, hot_count, compile_reason, requires_online_compilation, is_blocking, THREAD);
    }
  
    // return requested nmethod
    // We accept a higher level osr method
    if (osr_bci == InvocationEntryBci) {

@@ -1486,13 +1747,19 @@
  
  // ------------------------------------------------------------------
  // CompileBroker::compilation_is_complete
  //
  // See if compilation of this method is already complete.
- bool CompileBroker::compilation_is_complete(const methodHandle& method,
-                                             int                 osr_bci,
-                                             int                 comp_level) {
+ bool CompileBroker::compilation_is_complete(Method*                    method,
+                                             int                        osr_bci,
+                                             int                        comp_level,
+                                             bool                       online_only,
+                                             CompileTask::CompileReason compile_reason) {
+   if (compile_reason == CompileTask::Reason_Precompile ||
+       compile_reason == CompileTask::Reason_PrecompileForPreload) {
+     return false; // FIXME: any restrictions?
+   }
    bool is_osr = (osr_bci != standard_entry_bci);
    if (is_osr) {
      if (method->is_not_osr_compilable(comp_level)) {
        return true;
      } else {

@@ -1502,12 +1769,21 @@
    } else {
      if (method->is_not_compilable(comp_level)) {
        return true;
      } else {
        nmethod* result = method->code();
-       if (result == nullptr) return false;
-       return comp_level == result->comp_level();
+       if (result == nullptr) {
+         return false;
+       }
+       if (online_only && result->is_scc()) {
+         return false;
+       }
+       bool same_level = (comp_level == result->comp_level());
+       if (result->has_clinit_barriers()) {
+         return !same_level; // Allow replace preloaded code with new code of the same level
+       }
+       return same_level;
      }
    }
  }
  
  

@@ -1603,11 +1879,10 @@
  // ------------------------------------------------------------------
  // CompileBroker::assign_compile_id_unlocked
  //
  // Public wrapper for assign_compile_id that acquires the needed locks
  int CompileBroker::assign_compile_id_unlocked(Thread* thread, const methodHandle& method, int osr_bci) {
-   MutexLocker locker(thread, MethodCompileQueue_lock);
    return assign_compile_id(method, osr_bci);
  }
  
  // ------------------------------------------------------------------
  // CompileBroker::create_compile_task

@@ -1619,17 +1894,18 @@
                                                  const methodHandle& method,
                                                  int                 osr_bci,
                                                  int                 comp_level,
                                                  const methodHandle& hot_method,
                                                  int                 hot_count,
+                                                 SCCEntry*           scc_entry,
                                                  CompileTask::CompileReason compile_reason,
+                                                 bool                requires_online_compilation,
                                                  bool                blocking) {
    CompileTask* new_task = CompileTask::allocate();
    new_task->initialize(compile_id, method, osr_bci, comp_level,
-                        hot_method, hot_count, compile_reason,
-                        blocking);
-   queue->add(new_task);
+                        hot_method, hot_count, scc_entry, compile_reason, queue,
+                        requires_online_compilation, blocking);
    return new_task;
  }
  
  #if INCLUDE_JVMCI
  // The number of milliseconds to wait before checking if

@@ -1766,10 +2042,14 @@
  
      // Switch back to VM state to do compiler initialization
      ThreadInVMfromNative tv(thread);
  
      // Perform per-thread and global initializations
+     {
+       MutexLocker only_one (thread, CompileThread_lock);
+       SCCache::init_table();
+     }
      comp->initialize();
    }
  
    if (comp->is_failed()) {
      disable_compilation_forever();

@@ -1803,10 +2083,12 @@
   * out to be a problem.
   */
  void CompileBroker::shutdown_compiler_runtime(AbstractCompiler* comp, CompilerThread* thread) {
    free_buffer_blob_if_allocated(thread);
  
+   log_info(compilation)("shutdown_compiler_runtime: " INTPTR_FORMAT, p2i(thread));
+ 
    if (comp->should_perform_shutdown()) {
      // There are two reasons for shutting down the compiler
      // 1) compiler runtime initialization failed
      // 2) The code cache is full and the following flag is set: -XX:-UseCodeCacheFlushing
      warning("%s initialization failed. Shutting down all compilers", comp->name());

@@ -1822,10 +2104,14 @@
  
      if (_c2_compile_queue != nullptr) {
        _c2_compile_queue->free_all();
      }
  
+     if (_c3_compile_queue != nullptr) {
+       _c3_compile_queue->free_all();
+     }
+ 
      // Set flags so that we continue execution with using interpreter only.
      UseCompiler    = false;
      UseInterpreter = true;
  
      // We could delete compiler runtimes also. However, there are references to

@@ -1839,17 +2125,23 @@
   */
  CompileLog* CompileBroker::get_log(CompilerThread* ct) {
    if (!LogCompilation) return nullptr;
  
    AbstractCompiler *compiler = ct->compiler();
+   bool jvmci = JVMCI_ONLY( compiler->is_jvmci() ||) false;
    bool c1 = compiler->is_c1();
-   jobject* compiler_objects = c1 ? _compiler1_objects : _compiler2_objects;
+   jobject* compiler_objects = c1 ? _compiler1_objects : (_c3_count == 0 ? _compiler2_objects : (jvmci ? _compiler2_objects : _compiler3_objects));
    assert(compiler_objects != nullptr, "must be initialized at this point");
-   CompileLog** logs = c1 ? _compiler1_logs : _compiler2_logs;
+   CompileLog** logs = c1 ? _compiler1_logs : (_c3_count == 0 ? _compiler2_logs : (jvmci ? _compiler2_logs : _compiler3_logs));
    assert(logs != nullptr, "must be initialized at this point");
-   int count = c1 ? _c1_count : _c2_count;
+   int count = c1 ? _c1_count : (_c3_count == 0 ? _c2_count : (jvmci ? _c2_count : _c3_count));
  
+   if (ct->queue() == _sc1_compile_queue || ct->queue() == _sc2_compile_queue) {
+     compiler_objects = _sc_objects;
+     logs  = _sc_logs;
+     count = _sc_count;
+   }
    // Find Compiler number by its threadObj.
    oop compiler_obj = ct->threadObj();
    int compiler_number = 0;
    bool found = false;
    for (; compiler_number < count; compiler_number++) {

@@ -1923,11 +2215,14 @@
    // space in the code cache to generate the necessary stubs, etc.
    while (!is_compilation_disabled_forever()) {
      // We need this HandleMark to avoid leaking VM handles.
      HandleMark hm(thread);
  
+     CompilationPolicy::recompilation_step(RecompilationWorkUnitSize, thread);
+ 
      CompileTask* task = queue->get(thread);
+ 
      if (task == nullptr) {
        if (UseDynamicNumberOfCompilerThreads) {
          // Access compiler_count under lock to enforce consistency.
          MutexLocker only_one(CompileThread_lock);
          if (can_remove(thread, true)) {

@@ -1961,10 +2256,11 @@
            invoke_compiler_on_method(task);
            thread->start_idle_timer();
          } else {
            // After compilation is disabled, remove remaining methods from queue
            method->clear_queued_for_compilation();
+           method->set_pending_queue_processed(false);
            task->set_failure_reason("compilation is disabled");
          }
        } else {
          task->set_failure_reason("breakpoints are present");
        }

@@ -2169,10 +2465,13 @@
    bool is_osr = (osr_bci != standard_entry_bci);
    bool should_log = (thread->log() != nullptr);
    bool should_break = false;
    const int task_level = task->comp_level();
    AbstractCompiler* comp = task->compiler();
+   CompileTrainingData* tdata = task->training_data();
+   assert(tdata == nullptr || TrainingData::need_data() ||
+          CDSConfig::is_dumping_preimage_static_archive(), ""); // FIXME: MetaspaceShared::preload_and_dump() messes with RecordTraining flag
    {
      // 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.

@@ -2186,10 +2485,14 @@
      }
  
      DTRACE_METHOD_COMPILE_BEGIN_PROBE(method, compiler_name(task_level));
    }
  
+   if (tdata != nullptr) {
+     tdata->record_compilation_start(task);
+   }
+ 
    should_break = directive->BreakAtCompileOption || task->check_break_at_flags();
    if (should_log && !directive->LogOption) {
      should_log = false;
    }
  

@@ -2292,17 +2595,21 @@
      ciMethod* target = ci_env.get_method_from_handle(target_handle);
  
      TraceTime t1("compilation", &time);
      EventCompilation event;
  
+     bool install_code = true;
      if (comp == nullptr) {
        ci_env.record_method_not_compilable("no compiler");
      } else if (!ci_env.failing()) {
        if (WhiteBoxAPI && WhiteBox::compilation_locked) {
          whitebox_lock_compilation();
        }
-       comp->compile_method(&ci_env, target, osr_bci, true, directive);
+       if (StoreCachedCode && task->is_precompiled()) {
+         install_code = false; // not suitable in the current context
+       }
+       comp->compile_method(&ci_env, target, osr_bci, install_code, directive);
  
        /* Repeat compilation without installing code for profiling purposes */
        int repeat_compilation_count = directive->RepeatCompilationOption;
        while (repeat_compilation_count > 0) {
          ResourceMark rm(thread);

@@ -2312,11 +2619,11 @@
        }
      }
  
      DirectivesStack::release(directive);
  
-     if (!ci_env.failing() && !task->is_success()) {
+     if (!ci_env.failing() && !task->is_success() && install_code) {
        assert(ci_env.failure_reason() != nullptr, "expect failure reason");
        assert(false, "compiler should always document failure: %s", ci_env.failure_reason());
        // The compiler elected, without comment, not to register a result.
        // Do not attempt further compilations of this method.
        ci_env.record_method_not_compilable("compile failed");

@@ -2352,20 +2659,26 @@
          FormatBufferResource("COMPILE SKIPPED: %s",      failure_reason);
        task->print(tty, msg);
      }
    }
  
+   task->mark_finished(os::elapsed_counter());
+ 
+   if (tdata != nullptr) {
+     tdata->record_compilation_end(task);
+   }
+ 
    methodHandle method(thread, task->method());
  
    DTRACE_METHOD_COMPILE_END_PROBE(method, compiler_name(task_level), task->is_success());
  
    collect_statistics(thread, time, task);
  
    if (PrintCompilation && PrintCompilation2) {
      tty->print("%7d ", (int) tty->time_stamp().milliseconds());  // print timestamp
      tty->print("%4d ", compile_id);    // print compilation number
-     tty->print("%s ", (is_osr ? "%" : " "));
+     tty->print("%s ", (is_osr ? "%" : (task->is_scc() ? "A" : " ")));
      if (task->is_success()) {
        tty->print("size: %d(%d) ", task->nm_total_size(), task->nm_insts_size());
      }
      tty->print_cr("time: %d inlined: %d bytes", (int)time.milliseconds(), task->num_inlined_bytecodes());
    }

@@ -2400,10 +2713,16 @@
    // compile queue lock was held. Subsequently, we acquired the compile
    // queue lock to get this task off the compile queue; thus (to belabour
    // the point somewhat) our clearing of the bits must be occurring
    // only after the setting of the bits. See also 14012000 above.
    method->clear_queued_for_compilation();
+   method->set_pending_queue_processed(false);
+ 
+   if (PrintCompilation) {
+     ResourceMark rm;
+     task->print_tty();
+   }
  }
  
  /**
   * The CodeCache is full. Print warning and disable compilation.
   * Schedule code cache cleaning so compilation can continue later.

@@ -2512,48 +2831,79 @@
    // updated regardless of the setting of the CITime and CITimeEach flags
    //
  
    // account all time, including bailouts and failures in this counter;
    // C1 and C2 counters are counting both successful and unsuccessful compiles
-   _t_total_compilation.add(time);
+   _t_total_compilation.add(&time);
  
    if (!success) {
      _total_bailout_count++;
      if (UsePerfData) {
        _perf_last_failed_method->set_value(counters->current_method());
        _perf_last_failed_type->set_value(counters->compile_type());
        _perf_total_bailout_count->inc();
      }
-     _t_bailedout_compilation.add(time);
+     _t_bailedout_compilation.add(&time);
+ 
+     if (CITime || log_is_enabled(Info, init)) {
+       CompilerStatistics* stats = nullptr;
+       if (task->is_scc()) {
+         int level = task->preload() ? CompLevel_full_optimization : (comp_level - 1);
+         stats = &_scc_stats_per_level[level];
+       } else {
+         stats = &_stats_per_level[comp_level-1];
+       }
+       stats->_bailout.update(time, 0);
+     }
    } else if (!task->is_success()) {
      if (UsePerfData) {
        _perf_last_invalidated_method->set_value(counters->current_method());
        _perf_last_invalidated_type->set_value(counters->compile_type());
        _perf_total_invalidated_count->inc();
      }
      _total_invalidated_count++;
-     _t_invalidated_compilation.add(time);
+     _t_invalidated_compilation.add(&time);
+ 
+     if (CITime || log_is_enabled(Info, init)) {
+       CompilerStatistics* stats = nullptr;
+       if (task->is_scc()) {
+         int level = task->preload() ? CompLevel_full_optimization : (comp_level - 1);
+         stats = &_scc_stats_per_level[level];
+       } else {
+         stats = &_stats_per_level[comp_level-1];
+       }
+       stats->_invalidated.update(time, 0);
+     }
    } else {
      // Compilation succeeded
  
      // update compilation ticks - used by the implementation of
      // java.lang.management.CompilationMXBean
      _perf_total_compilation->inc(time.ticks());
      _peak_compilation_time = time.milliseconds() > _peak_compilation_time ? time.milliseconds() : _peak_compilation_time;
  
-     if (CITime) {
+     if (CITime || log_is_enabled(Info, init)) {
        int bytes_compiled = method->code_size() + task->num_inlined_bytecodes();
        if (is_osr) {
-         _t_osr_compilation.add(time);
+         _t_osr_compilation.add(&time);
          _sum_osr_bytes_compiled += bytes_compiled;
        } else {
-         _t_standard_compilation.add(time);
+         _t_standard_compilation.add(&time);
          _sum_standard_bytes_compiled += method->code_size() + task->num_inlined_bytecodes();
        }
  
        // Collect statistic per compilation level
-       if (comp_level > CompLevel_none && comp_level <= CompLevel_full_optimization) {
+       if (task->is_scc()) {
+         _scc_stats._standard.update(time, bytes_compiled);
+         _scc_stats._nmethods_size += task->nm_total_size();
+         _scc_stats._nmethods_code_size += task->nm_insts_size();
+         int level = task->preload() ? CompLevel_full_optimization : (comp_level - 1);
+         CompilerStatistics* stats = &_scc_stats_per_level[level];
+         stats->_standard.update(time, bytes_compiled);
+         stats->_nmethods_size += task->nm_total_size();
+         stats->_nmethods_code_size += task->nm_insts_size();
+       } else if (comp_level > CompLevel_none && comp_level <= CompLevel_full_optimization) {
          CompilerStatistics* stats = &_stats_per_level[comp_level-1];
          if (is_osr) {
            stats->_osr.update(time, bytes_compiled);
          } else {
            stats->_standard.update(time, bytes_compiled);

@@ -2563,21 +2913,21 @@
        } else {
          assert(false, "CompilerStatistics object does not exist for compilation level %d", comp_level);
        }
  
        // Collect statistic per compiler
-       AbstractCompiler* comp = compiler(comp_level);
-       if (comp) {
+       AbstractCompiler* comp = task->compiler();
+       if (comp && !task->is_scc()) {
          CompilerStatistics* stats = comp->stats();
          if (is_osr) {
            stats->_osr.update(time, bytes_compiled);
          } else {
            stats->_standard.update(time, bytes_compiled);
          }
          stats->_nmethods_size += task->nm_total_size();
          stats->_nmethods_code_size += task->nm_insts_size();
-       } else { // if (!comp)
+       } else if (!task->is_scc()) { // if (!comp)
          assert(false, "Compiler object must exist");
        }
      }
  
      if (UsePerfData) {

@@ -2636,32 +2986,161 @@
  
  jlong CompileBroker::total_compilation_ticks() {
    return _perf_total_compilation != nullptr ? _perf_total_compilation->get_value() : 0;
  }
  
+ void CompileBroker::log_not_entrant(nmethod* nm) {
+   _total_not_entrant_count++;
+   if (CITime || log_is_enabled(Info, init)) {
+     CompilerStatistics* stats = nullptr;
+     int level = nm->comp_level();
+     if (nm->is_scc()) {
+       if (nm->preloaded()) {
+         assert(level == CompLevel_full_optimization, "%d", level);
+         level = CompLevel_full_optimization + 1;
+       }
+       stats = &_scc_stats_per_level[level - 1];
+     } else {
+       stats = &_stats_per_level[level - 1];
+     }
+     stats->_made_not_entrant._count++;
+   }
+ }
+ 
  void CompileBroker::print_times(const char* name, CompilerStatistics* stats) {
    tty->print_cr("  %s {speed: %6.3f bytes/s; standard: %6.3f s, %u bytes, %u methods; osr: %6.3f s, %u bytes, %u methods; nmethods_size: %u bytes; nmethods_code_size: %u bytes}",
                  name, stats->bytes_per_second(),
                  stats->_standard._time.seconds(), stats->_standard._bytes, stats->_standard._count,
                  stats->_osr._time.seconds(), stats->_osr._bytes, stats->_osr._count,
                  stats->_nmethods_size, stats->_nmethods_code_size);
  }
  
+ static void print_helper(outputStream* st, const char* name, CompilerStatistics::Data data, bool print_time = true) {
+   if (data._count > 0) {
+     st->print("; %s: %4u methods", name, data._count);
+     if (print_time) {
+       st->print(" (in %.3fs)", data._time.seconds());
+     }
+   }
+ }
+ 
+ static void print_tier_helper(outputStream* st, const char* prefix, int tier, CompilerStatistics* stats) {
+   st->print("    %s%d: %5u methods", prefix, tier, stats->_standard._count);
+   if (stats->_standard._count > 0) {
+     st->print(" (in %.3fs)", stats->_standard._time.seconds());
+   }
+   print_helper(st, "osr",     stats->_osr);
+   print_helper(st, "bailout", stats->_bailout);
+   print_helper(st, "invalid", stats->_invalidated);
+   print_helper(st, "not_entrant", stats->_made_not_entrant, false);
+   st->cr();
+ }
+ 
+ static void print_queue_info(outputStream* st, CompileQueue* queue) {
+   if (queue != nullptr) {
+     MutexLocker ml(queue->lock());
+ 
+     uint  total_cnt = 0;
+     uint active_cnt = 0;
+     for (JavaThread* jt : *ThreadsSMRSupport::get_java_thread_list()) {
+       guarantee(jt != nullptr, "");
+       if (jt->is_Compiler_thread()) {
+         CompilerThread* ct = (CompilerThread*)jt;
+ 
+         guarantee(ct != nullptr, "");
+         if (ct->queue() == queue) {
+           ++total_cnt;
+           CompileTask* task = ct->task();
+           if (task != nullptr) {
+             ++active_cnt;
+           }
+         }
+       }
+     }
+ 
+     st->print("  %s (%d active / %d total threads): %u tasks",
+               queue->name(), active_cnt, total_cnt, queue->size());
+     if (queue->size() > 0) {
+       uint counts[] = {0, 0, 0, 0, 0}; // T1 ... T5
+       for (CompileTask* task = queue->first(); task != nullptr; task = task->next()) {
+         int tier = task->comp_level();
+         if (task->is_scc() && task->preload()) {
+           assert(tier == CompLevel_full_optimization, "%d", tier);
+           tier = CompLevel_full_optimization + 1;
+         }
+         counts[tier-1]++;
+       }
+       st->print(":");
+       for (int tier = CompLevel_simple; tier <= CompilationPolicy::highest_compile_level() + 1; tier++) {
+         uint cnt = counts[tier-1];
+         if (cnt > 0) {
+           st->print(" T%d: %u tasks;", tier, cnt);
+         }
+       }
+     }
+     st->cr();
+ 
+ //    for (JavaThread* jt : *ThreadsSMRSupport::get_java_thread_list()) {
+ //      guarantee(jt != nullptr, "");
+ //      if (jt->is_Compiler_thread()) {
+ //        CompilerThread* ct = (CompilerThread*)jt;
+ //
+ //        guarantee(ct != nullptr, "");
+ //        if (ct->queue() == queue) {
+ //          ResourceMark rm;
+ //          CompileTask* task = ct->task();
+ //          st->print("    %s: ", ct->name_raw());
+ //          if (task != nullptr) {
+ //            task->print(st, nullptr, true /*short_form*/, false /*cr*/);
+ //          }
+ //          st->cr();
+ //        }
+ //      }
+ //    }
+   }
+ }
+ void CompileBroker::print_statistics_on(outputStream* st) {
+   st->print_cr("  Total: %u methods; %u bailouts, %u invalidated, %u non_entrant",
+                _total_compile_count, _total_bailout_count, _total_invalidated_count, _total_not_entrant_count);
+   for (int tier = CompLevel_simple; tier <= CompilationPolicy::highest_compile_level(); tier++) {
+     print_tier_helper(st, "Tier", tier, &_stats_per_level[tier-1]);
+   }
+   st->cr();
+ 
+   if (LoadCachedCode || StoreCachedCode) {
+     for (int tier = CompLevel_simple; tier <= CompilationPolicy::highest_compile_level() + 1; tier++) {
+       if (tier != CompLevel_full_profile) {
+         print_tier_helper(st, "SC T", tier, &_scc_stats_per_level[tier - 1]);
+       }
+     }
+     st->cr();
+   }
+ 
+   print_queue_info(st, _c1_compile_queue);
+   print_queue_info(st, _c2_compile_queue);
+   print_queue_info(st, _c3_compile_queue);
+   print_queue_info(st, _sc1_compile_queue);
+   print_queue_info(st, _sc2_compile_queue);
+ }
+ 
  void CompileBroker::print_times(bool per_compiler, bool aggregate) {
    if (per_compiler) {
      if (aggregate) {
        tty->cr();
-       tty->print_cr("Individual compiler times (for compiled methods only)");
+       tty->print_cr("[%dms] Individual compiler times (for compiled methods only)", (int)tty->time_stamp().milliseconds());
        tty->print_cr("------------------------------------------------");
        tty->cr();
      }
      for (unsigned int i = 0; i < sizeof(_compilers) / sizeof(AbstractCompiler*); i++) {
        AbstractCompiler* comp = _compilers[i];
        if (comp != nullptr) {
          print_times(comp->name(), comp->stats());
        }
      }
+     if (_scc_stats._standard._count > 0) {
+       print_times("SC", &_scc_stats);
+     }
      if (aggregate) {
        tty->cr();
        tty->print_cr("Individual compilation Tier times (for compiled methods only)");
        tty->print_cr("------------------------------------------------");
        tty->cr();

@@ -2670,10 +3149,17 @@
      for (int tier = CompLevel_simple; tier <= CompilationPolicy::highest_compile_level(); tier++) {
        CompilerStatistics* stats = &_stats_per_level[tier-1];
        os::snprintf_checked(tier_name, sizeof(tier_name), "Tier%d", tier);
        print_times(tier_name, stats);
      }
+     for (int tier = CompLevel_simple; tier <= CompilationPolicy::highest_compile_level() + 1; tier++) {
+       CompilerStatistics* stats = &_scc_stats_per_level[tier-1];
+       if (stats->_standard._bytes > 0) {
+         os::snprintf_checked(tier_name, sizeof(tier_name), "SC T%d", tier);
+         print_times(tier_name, stats);
+       }
+     }
    }
  
    if (!aggregate) {
      return;
    }

@@ -2711,20 +3197,29 @@
                  osr_compile_count == 0 ? 0.0 : osr_compilation.seconds() / osr_compile_count);
    tty->print_cr("    Invalidated            : %7.3f s, Average : %2.3f s",
                  CompileBroker::_t_invalidated_compilation.seconds(),
                  total_invalidated_count == 0 ? 0.0 : CompileBroker::_t_invalidated_compilation.seconds() / total_invalidated_count);
  
+   if (StoreCachedCode || LoadCachedCode) { // Check flags because SC cache could be closed already
+     tty->cr();
+     SCCache::print_timers_on(tty);
+   }
    AbstractCompiler *comp = compiler(CompLevel_simple);
    if (comp != nullptr) {
      tty->cr();
      comp->print_timers();
    }
    comp = compiler(CompLevel_full_optimization);
    if (comp != nullptr) {
      tty->cr();
      comp->print_timers();
    }
+   comp = _compilers[2];
+   if (comp != nullptr) {
+     tty->cr();
+     comp->print_timers();
+   }
  #if INCLUDE_JVMCI
    if (EnableJVMCI) {
      JVMCICompiler *jvmci_comp = JVMCICompiler::instance(false, JavaThread::current_or_null());
      if (jvmci_comp != nullptr && jvmci_comp != comp) {
        tty->cr();
< prev index next >