hotspot/src/cpu/x86/vm/templateInterpreter_x86_64.cpp
// increment invocation count & check for overflow
//
// Note: checking for negative value instead of overflow
// so we have a 'sticky' overflow test
//
// rbx: method
// ecx: invocation counter
//
void InterpreterGenerator::generate_counter_incr(
Label* overflow,
Label* profile_method,
Label* profile_method_continue) {
{- -------------------------------------------
(1) (この関数には, TieredCompilation オプションの値に応じて 2つの処理パスがある)
---------------------------------------- -}
{- -------------------------------------------
(1) (変数宣言など)
---------------------------------------- -}
const Address invocation_counter(rbx, in_bytes(methodOopDesc::invocation_counter_offset()) +
in_bytes(InvocationCounter::counter_offset()));
{- -------------------------------------------
(1) (以下が, TieredCompilation オプションが指定されている場合の処理)
---------------------------------------- -}
// Note: In tiered we increment either counters in methodOop or in MDO depending if we're profiling or not.
if (TieredCompilation) {
{- -------------------------------------------
(1.1) (変数宣言など)
---------------------------------------- -}
int increment = InvocationCounter::count_increment;
int mask = ((1 << Tier0InvokeNotifyFreqLog) - 1) << InvocationCounter::count_shift;
Label no_mdo, done;
{- -------------------------------------------
(1.1) コード生成: (ただし, ProfileInterpreter オプションが指定されていない場合には生成しない)
「もし methodDataOopDesc(mdo) が付いていれば,
InterpreterMacroAssembler::increment_mask_and_jump() が生成するコードによって
mdo の _invocation_counter フィールドのカウンタ値をインクリメントし, 閾値チェックを行う.
閾値に達していた場合は, 引数で指定された overflow ラベルにジャンプする.
そうでなければ, done ラベルまでジャンプする (= 今回のカウンタ値の処理は終了).
もし methodDataOopDesc が付いていなければ,
no_mdo ラベルまでジャンプする」
---------------------------------------- -}
if (ProfileInterpreter) {
// Are we profiling?
__ movptr(rax, Address(rbx, methodOopDesc::method_data_offset()));
__ testptr(rax, rax);
__ jccb(Assembler::zero, no_mdo);
// Increment counter in the MDO
const Address mdo_invocation_counter(rax, in_bytes(methodDataOopDesc::invocation_counter_offset()) +
in_bytes(InvocationCounter::counter_offset()));
__ increment_mask_and_jump(mdo_invocation_counter, increment, mask, rcx, false, Assembler::zero, overflow);
__ jmpb(done);
}
{- -------------------------------------------
(1.1) コード生成:
「(ここが no_mdo ラベルの位置)」
---------------------------------------- -}
__ bind(no_mdo);
{- -------------------------------------------
(1.1) コード生成:
「InterpreterMacroAssembler::increment_mask_and_jump() が生成するコードによって
実行中のメソッドに対応する methodOopDesc の
_invocation_counter フィールドのカウンタ値をインクリメントし, 閾値チェックを行う.
閾値に達していた場合は, 引数で指定された overflow ラベルにジャンプする.
そうでなければ, このままフォールスルーして, 今回のカウンタ値の処理は終了」
---------------------------------------- -}
// Increment counter in methodOop (we don't need to load it, it's in ecx).
__ increment_mask_and_jump(invocation_counter, increment, mask, rcx, true, Assembler::zero, overflow);
{- -------------------------------------------
(1.1) コード生成:
「(ここが done ラベルの位置)」
---------------------------------------- -}
__ bind(done);
{- -------------------------------------------
(1) (以下が, TieredCompilation オプションが指定されていない場合の処理)
---------------------------------------- -}
} else {
{- -------------------------------------------
(1.1) (変数宣言など)
---------------------------------------- -}
const Address backedge_counter(rbx,
methodOopDesc::backedge_counter_offset() +
InvocationCounter::counter_offset());
{- -------------------------------------------
(1.1) コード生成: (ただし, ProfileInterpreter オプションが指定されていない場合には生成しない)
「(プロファイル情報を取得する場合には)
実行中のメソッドに対応する methodOopDesc の
_interpreter_invocation_count フィールドの値をインクリメントしておく」
---------------------------------------- -}
if (ProfileInterpreter) { // %%% Merge this into methodDataOop
__ incrementl(Address(rbx,
methodOopDesc::interpreter_invocation_counter_offset()));
}
{- -------------------------------------------
(1.1) コード生成:
「実行中のメソッドに対応する methodOopDesc の
_invocation_counter フィールドのカウンタ値をインクリメントする.
(なおついでに, rcx レジスタに
_backedge_counter と _invocation_counter を足した値をセットしている)」
(なお, このコードでは
rcx に予め _invocation_counter フィールドのアドレスが入っていると想定している.
この関数の先頭にあるコメントも参照)
---------------------------------------- -}
// Update standard invocation counters
__ movl(rax, backedge_counter); // load backedge counter
__ incrementl(rcx, InvocationCounter::count_increment);
__ andl(rax, InvocationCounter::count_mask_value); // mask out the status bits
__ movl(invocation_counter, rcx); // save invocation count
__ addl(rcx, rax); // add both counters
{- -------------------------------------------
(1.1) コード生成: (ただし, ProfileInterpreter オプションが指定されていない場合や, 引数の profile_method が NULL の場合には生成しない)
「(プロファイル情報を取得する場合, ある程度実行回数が多いコードには methodDataOopDesc(mdo) を付ける.
ここでカウンタ値をチェックし, カウンタ値が大きいのに mdo がまだ付いてなければ, 付けるコードにジャンプする)
カウンタの値を閾値(InvocationCounter::InterpreterProfileLimitの値)と比較する.
もしカウンタ値が閾値未満であれば, 引数で指定された profile_method_continue ラベルにジャンプする.
そうでなければ, InterpreterMacroAssembler::test_method_data_pointer() が生成するコードによって
ImethodDataPtr レジスタの値を調べる.
まだ mdo が生成されてなければ, 引数で指定された profile_method ラベルにジャンプする」
(なお, 引数の profile_method が NULL 以外の値を取るのは
インタープリタで実行されているメソッドの場合のみ.
つまり, "profile_method != NULL" という条件は「ネイティブメソッドではない」という意味)
---------------------------------------- -}
// profile_method is non-null only for interpreted method so
// profile_method != NULL == !native_call
if (ProfileInterpreter && profile_method != NULL) {
// Test to see if we should create a method data oop
__ cmp32(rcx, ExternalAddress((address)&InvocationCounter::InterpreterProfileLimit));
__ jcc(Assembler::less, *profile_method_continue);
// if no method data exists, go to profile_method
__ test_method_data_pointer(rax, *profile_method);
}
{- -------------------------------------------
(1.1) コード生成:
「カウンタの値を閾値(InvocationCounter::InterpreterInvocationLimitの値)と比較する.
もしカウンタ値が閾値以上であれば, 引数で指定された overflow ラベルにジャンプする.」
---------------------------------------- -}
__ cmp32(rcx, ExternalAddress((address)&InvocationCounter::InterpreterInvocationLimit));
__ jcc(Assembler::aboveEqual, *overflow);
}
}
This document is available under the GNU GENERAL PUBLIC LICENSE Version 2.