hotspot/src/share/vm/compiler/compileBroker.cpp
// ------------------------------------------------------------------
// CompileBroker::invoke_compiler_on_method
//
// Compile a method.
//
void CompileBroker::invoke_compiler_on_method(CompileTask* task) {
{- -------------------------------------------
(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.