Top


定義場所(file name)

hotspot/src/share/vm/compiler/compileBroker.cpp

説明(description)

// ------------------------------------------------------------------
// CompileBroker::compiler_thread_loop
//
// The main loop run by a CompilerThread.

名前(function name)

void CompileBroker::compiler_thread_loop() {

本体部(body)

  {- -------------------------------------------
  (1) (変数宣言など)
      ---------------------------------------- -}

      CompilerThread* thread = CompilerThread::current();
      CompileQueue* queue = thread->queue();

  {- -------------------------------------------
  (1) (ResourceMark)
      ---------------------------------------- -}

      // For the thread that initializes the ciObjectFactory
      // this resource mark holds all the shared objects
      ResourceMark rm;

  {- -------------------------------------------
  (1) 最初にここにたどり着いた CompilerThread は,
      ciObjectFactory::initialize() を呼んで ciObjectFactory の初期化を行う.
      (1回しか実行されないよう, DCL 方式のチェックを入れてある)
      ---------------------------------------- -}

      // First thread to get here will initialize the compiler interface

      if (!ciObjectFactory::is_initialized()) {
        ASSERT_IN_VM;
        MutexLocker only_one (CompileThread_lock, thread);
        if (!ciObjectFactory::is_initialized()) {
          ciObjectFactory::initialize();
        }
      }

  {- -------------------------------------------
  (1) (トレース出力用の処理)
      ログを初期化する
      ---------------------------------------- -}

      // Open a log.
      if (LogCompilation) {
        init_compiler_thread_log();
      }
      CompileLog* log = thread->log();
      if (log != NULL) {
        log->begin_elem("start_compile_thread thread='" UINTX_FORMAT "' process='%d'",
                        os::current_thread_id(),
                        os::current_process_id());
        log->stamp();
        log->end_elem();
      }

  {- -------------------------------------------
  (1) (以下の while ループが CompilerThread スレッドのメインループ)
      ---------------------------------------- -}

      while (true) {
        {

    {- -------------------------------------------
  (1.1) (HandleMark)
        ---------------------------------------- -}

          // We need this HandleMark to avoid leaking VM handles.
          HandleMark hm(thread);

    {- -------------------------------------------
  (1.1) もし CodeCache が一杯であれば,  
        CompileBroker::handle_full_code_cache() を呼んで
        これ以上の JIT コンパイルを禁止するか, あるいは空き領域を捻出する.

        また, まだ余裕がある場合でも UseCodeCacheFlushing オプションが指定されていれば, 
        必要に応じて NMethodSweeper::handle_full_code_cache() を呼んで, 空き領域を作っておく.
        ---------------------------------------- -}

          if (CodeCache::largest_free_block() < CodeCacheMinimumFreeSpace) {
            // the code cache is really full
            handle_full_code_cache();
          } else if (UseCodeCacheFlushing && CodeCache::needs_flushing()) {
            // Attempt to start cleaning the code cache while there is still a little headroom
            NMethodSweeper::handle_full_code_cache(false);
          }

    {- -------------------------------------------
  (1.1) キューから次のコンパイル要求を取得する.
        ---------------------------------------- -}

          CompileTask* task = queue->get();

    {- -------------------------------------------
  (1.1) (これから JIT コンパイル処理を始めるので)
        CompilerThreadHintNoPreempt オプションが指定されている場合には, 
        os::hint_no_preempt() を呼んで
        CompilerThread に time slice を多めに与えてくれるよう, OS に要望を出しておく

        (こうしておくと処理をタイムスライス内に終わらせられる可能性が高まる)
        ---------------------------------------- -}

          // Give compiler threads an extra quanta.  They tend to be bursty and
          // this helps the compiler to finish up the job.
          if( CompilerThreadHintNoPreempt )
            os::hint_no_preempt();

    {- -------------------------------------------
  (1.1) (プロファイル情報の記録) (See: CompilerCounters) (See: PerfTraceTime)
        ---------------------------------------- -}

          // trace per thread time and compile statistics
          CompilerCounters* counters = ((CompilerThread*)thread)->counters();
          PerfTraceTimedEvent(counters->time_counter(), counters->compile_counter());

    {- -------------------------------------------
  (1.1) カレントスレッドに, キューから受け取ったコンパイル要求を割り当てる.
        ---------------------------------------- -}

          // Assign the task to the current thread.  Mark this compilation
          // thread as active for the profiler.
          CompileTaskWrapper ctw(task);

    {- -------------------------------------------
  (1.1) 結果を保護するための nmethodLocker を用意しておく.
        ---------------------------------------- -}

          nmethodLocker result_handle;  // (handle for the nmethod produced by this task)
          task->set_code_handle(&result_handle);

    {- -------------------------------------------
  (1.1) (変数宣言など)
        ---------------------------------------- -}

          methodHandle method(thread,
                         (methodOop)JNIHandles::resolve(task->method_handle()));

    {- -------------------------------------------
  (1.1) CompileBroker::invoke_compiler_on_method() を呼んで, JIT コンパイル処理を行う.

        ただし, 以下の場合には行わない.
        * 対象のメソッドにブレークポイントが埋められている場合
        * UseCompiler オプション及び AlwaysCompileLoopMethods オプションの両方がオフにされている場合
          (この場合は, 対象のメソッドに対して methodOopDesc::clear_queued_for_compilation() を呼び, 
          JIT コンパイル要求が出ているという印を消しておく)
        * JIT コンパイラが次の作業を開始できない状況にある場合 (= CompileBroker::should_compile_new_jobs() が false)
          (この場合は, 対象のメソッドに対して methodOopDesc::clear_queued_for_compilation() を呼び, 
          JIT コンパイル要求が出ているという印を消しておく)


        (なお, C1 コンパイラを使う場合には CompilationRepeat オプションの値分だけループするので
        コンパイル速度についての性能評価を行うことが出来る模様.
        コメントに書いてある通り, 製品版では役に立たない機能だろうけど...)
        ---------------------------------------- -}

          // Never compile a method if breakpoints are present in it
          if (method()->number_of_breakpoints() == 0) {
            // Compile the method.
            if ((UseCompiler || AlwaysCompileLoopMethods) && CompileBroker::should_compile_new_jobs()) {
    #ifdef COMPILER1
              // Allow repeating compilations for the purpose of benchmarking
              // compile speed. This is not useful for customers.
              if (CompilationRepeat != 0) {
                int compile_count = CompilationRepeat;
                while (compile_count > 0) {
                  invoke_compiler_on_method(task);
                  nmethod* nm = method->code();
                  if (nm != NULL) {
                    nm->make_zombie();
                    method->clear_code();
                  }
                  compile_count--;
                }
              }
    #endif /* COMPILER1 */
              invoke_compiler_on_method(task);
            } else {
              // After compilation is disabled, remove remaining methods from queue
              method->clear_queued_for_compilation();
            }
          }
        }
      }
    }

This document is available under the GNU GENERAL PUBLIC LICENSE Version 2.