Top


定義場所(file name)

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

説明(description)

// ------------------------------------------------------------------
// CompileBroker::invoke_compiler_on_method
//
// Compile a method.
//

名前(function name)

void CompileBroker::invoke_compiler_on_method(CompileTask* task) {

本体部(body)

  {- -------------------------------------------
  (1) (トレース出力)
      ---------------------------------------- -}

      if (PrintCompilation) {
        ResourceMark rm;
        task->print_line();
      }

  {- -------------------------------------------
  (1) (トレース出力用の処理) (See: elapsedTimer)
      ---------------------------------------- -}

      elapsedTimer time;

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

      CompilerThread* thread = CompilerThread::current();

  {- -------------------------------------------
  (1) (ResourceMark) (カレントスレッドの ResourceArea を使用)
      ---------------------------------------- -}

      ResourceMark rm(thread);

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

      // Common flags.
      uint compile_id = task->compile_id();
      int osr_bci = task->osr_bci();
      bool is_osr = (osr_bci != standard_entry_bci);
      bool should_log = (thread->log() != NULL);
      bool should_break = false;
      {
        // 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.
        methodHandle method(thread,
                            (methodOop)JNIHandles::resolve(task->method_handle()));
        should_break = check_break_at(method, compile_id, is_osr);
        if (should_log && !CompilerOracle::should_log(method)) {
          should_log = false;
        }

  {- -------------------------------------------
  (1) (assert)
      ---------------------------------------- -}

        assert(!method->is_native(), "no longer compile natives");

  {- -------------------------------------------
  (1) 失敗したときのために, 情報を記録しておく
      ---------------------------------------- -}

        // Save information about this method in case of failure.
        set_last_compile(thread, method, is_osr, task->comp_level());

  {- -------------------------------------------
  (1) (DTrace のフック点)
      ---------------------------------------- -}

        DTRACE_METHOD_COMPILE_BEGIN_PROBE(compiler(task->comp_level()), method);
      }

  {- -------------------------------------------
  (1) 新しい JNIHandleBlock を準備しておく
      ---------------------------------------- -}

      // Allocate a new set of JNI handles.
      push_jni_handle_block();

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

      jobject target_handle = JNIHandles::make_local(thread, JNIHandles::resolve(task->method_handle()));
      int compilable = ciEnv::MethodCompilable;
      {
        int system_dictionary_modification_counter;
        {
          MutexLocker locker(Compile_lock, thread);
          system_dictionary_modification_counter = SystemDictionary::number_of_modifications();
        }

  {- -------------------------------------------
  (1) (NoHandleMark)
      ---------------------------------------- -}

        NoHandleMark  nhm;

  {- -------------------------------------------
  (1) (ここでスレッドを状態遷移させる) (See: ThreadToNativeFromVM)
      ---------------------------------------- -}

        ThreadToNativeFromVM ttn(thread);

  {- -------------------------------------------
  (1) JIT コンパイル処理で使う ciEnv オブジェクトを初期化する.
      ---------------------------------------- -}

        ciEnv ci_env(task, system_dictionary_modification_counter);
        if (should_break) {
          ci_env.set_break_at_compile(true);
        }
        if (should_log) {
          ci_env.set_log(thread->log());
        }
        assert(thread->env() == &ci_env, "set by ci_env");
        // The thread-env() field is cleared in ~CompileTaskWrapper.

        // Cache Jvmti state
        ci_env.cache_jvmti_state();

        // Cache DTrace flags
        ci_env.cache_dtrace_flags();

  {- -------------------------------------------
  (1) JIT 対象のメソッドを ciMethod 化しておく.
      ---------------------------------------- -}

        ciMethod* target = ci_env.get_method_from_handle(target_handle);

  {- -------------------------------------------
  (1) (トレース出力) (See: TraceTime)
      ---------------------------------------- -}

        TraceTime t1("compilation", &time);

  {- -------------------------------------------
  (1) CompileBroker::compiler() で適切なコンパイラオブジェクト (AbstractCompilerのサブクラスのインスタンス) を取得し, 
      AbstractCompiler::compile_method() (を各サブクラスがオーバーライドしたもの) を呼ぶことで JIT コンパイル処理を実行する.
      ---------------------------------------- -}

        compiler(task->comp_level())->compile_method(&ci_env, target, osr_bci);

  {- -------------------------------------------
  (1) JIT コンパイルが失敗したが, 理由を表す文字列が ciEnv 内に格納されてなければ (= ciEnv::failing() が NULL), 
      ここで適当な文字列("compile failed")を格納しておく.
      ---------------------------------------- -}

        if (!ci_env.failing() && task->code() == NULL) {
          //assert(false, "compiler should always document failure");
          // 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", !TieredCompilation);
        }

  {- -------------------------------------------
  (1) JIT コンパイルが成功していた場合は, 該当の CompileTask にそのことを記録しておく (mark_success()), 
      さらに, インライン展開されたバイトコード数も CompileTask に記録しておく.

      (逆に, JIT コンパイルが失敗した場合は, compilable 局所変数を変更しておく. また (トレース出力) も出す)
      ---------------------------------------- -}

        if (ci_env.failing()) {
          // Copy this bit to the enclosing block:
          compilable = ci_env.compilable();
          if (PrintCompilation) {
            const char* reason = ci_env.failure_reason();
            if (compilable == ciEnv::MethodCompilable_not_at_tier) {
                tty->print_cr("%3d   COMPILE SKIPPED: %s (retry at different tier)", compile_id, reason);
            } else if (compilable == ciEnv::MethodCompilable_never) {
              tty->print_cr("%3d   COMPILE SKIPPED: %s (not retryable)", compile_id, reason);
            } else if (compilable == ciEnv::MethodCompilable) {
              tty->print_cr("%3d   COMPILE SKIPPED: %s", compile_id, reason);
            }
          }
        } else {
          task->mark_success();
          task->set_num_inlined_bytecodes(ci_env.num_inlined_bytecodes());
        }
      }

  {- -------------------------------------------
  (1) (JIT コンパイルが終わったので, 生成した JNIHandleBlock を破棄する)
      ---------------------------------------- -}

      pop_jni_handle_block();

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

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

  {- -------------------------------------------
  (1) (DTrace のフック点)
      ---------------------------------------- -}

      DTRACE_METHOD_COMPILE_END_PROBE(compiler(task->comp_level()), method, task->is_success());

  {- -------------------------------------------
  (1) (プロファイル情報の記録)
      ---------------------------------------- -}

      collect_statistics(thread, time, task);

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

      if (compilable == ciEnv::MethodCompilable_never) {
        if (is_osr) {
          method->set_not_osr_compilable();
        } else {
          method->set_not_compilable_quietly();
        }
      } else if (compilable == ciEnv::MethodCompilable_not_at_tier) {
        method->set_not_compilable_quietly(task->comp_level());
      }

  {- -------------------------------------------
  (1) JIT コンパイルが終わったので, 
      対象のメソッドに対して methodOopDesc::clear_queued_for_compilation() を呼び, 
      JIT コンパイル要求が出ているという印を消しておく
      ---------------------------------------- -}

      // Note that the queued_for_compilation bits are cleared without
      // protection of a mutex. [They were set by the requester thread,
      // when adding the task to the complie queue -- at which time the
      // 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();

  {- -------------------------------------------
  (1) (デバッグ用の処理) (#ifdef ASSERT 時にのみ実行)
      ---------------------------------------- -}

    #ifdef ASSERT
      if (CollectedHeap::fired_fake_oom()) {
        // The current compile received a fake OOM during compilation so
        // go ahead and exit the VM since the test apparently succeeded
        tty->print_cr("*** Shutting down VM after successful fake OOM");
        vm_exit(0);
      }
    #endif
    }

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