hotspot/src/share/vm/runtime/compilationPolicy.cpp
RFrame* StackWalkCompPolicy::findTopInlinableFrame(GrowableArray<RFrame*>* stack) {
{- -------------------------------------------
(1) (この関数では, 呼び出し元に恐らくインライン展開されないだろう, という
フレームを見つけるまでスタックフレームをさかのぼっていく)
---------------------------------------- -}
// go up the stack until finding a frame that (probably) won't be inlined
// into its caller
{- -------------------------------------------
(1) (変数宣言など) &(assert)
---------------------------------------- -}
RFrame* current = stack->at(0); // current choice for stopping
assert( current && !current->is_compiled(), "" );
const char* msg = NULL;
{- -------------------------------------------
(1) 以下の while ループで該当するスタックフレームを見つけるまでループ.
---------------------------------------- -}
while (1) {
{- -------------------------------------------
(1.1) StackWalkCompPolicy::senderOf() を呼んで,
処理対象の1つ上のスタックフレーム(呼び出し元のフレーム)の取得を試みる.
---------------------------------------- -}
// before going up the stack further, check if doing so would get us into
// compiled code
RFrame* next = senderOf(current, stack);
{- -------------------------------------------
(1.1) 以下の条件に当てはまる場合は, ここでループは終了
* もう上のスタックフレームがない場合
---------------------------------------- -}
if( !next ) // No next frame up the stack?
break; // Then compile with current frame
{- -------------------------------------------
(1.1) (変数宣言など)
---------------------------------------- -}
methodHandle m = current->top_method();
methodHandle next_m = next->top_method();
{- -------------------------------------------
(1.1) (トレース出力)
---------------------------------------- -}
if (TraceCompilationPolicy && Verbose) {
tty->print("[caller: ");
next_m->print_short_name(tty);
tty->print("] ");
}
{- -------------------------------------------
(1.1) 以下の条件のどれかに当てはまる場合は, ここでループは終了
* そもそも, JIT コンパイラのインライン展開機能が無効にされている場合 (= Inline オプションが false)
(<= これはループに入る前にチェックしてもいい気がするが...)
* 1つ上のスタックフレームが, JIT コンパイルを禁止されているメソッドのフレームである場合
* スタックをさかのぼりすぎて, 対象のスタックフレームの数が MaxRecompilationSearchLength 個を超えた場合
* スタックをさかのぼりすぎて, 対象のスタックフレーム中の interpreter frame の数が MaxInterpretedSearchLength 個を超えた場合
* 1つ上のスタックフレームが, JIT 生成コードで実行されているメソッドのフレームである場合
(= そのメソッドの JIT コンパイル時に, 今回対象となっているメソッドはインライン展開しないと判断された場合)
* 現在のスタックフレームは interpreter で実行されているメソッドのフレームであり, かつ
1つ上のスタックフレームが, 既にメソッド全体の JIT コンパイル処理が終わっているメソッドのフレームである場合
(= まだ JIT 生成コードによる実行はされてはいないが, 既に JIT コンパイル処理自体は行われている状態)
(<= ところで, この「interpreter で実行されているメソッドのフレーム」という条件は必要?
これが false になる処理パスはない気もするんだが... #TODO)
<= ところで, MaxRecompilationSearchLength と MaxInterpretedSearchLength の関係は??
そもそも JIT コンパイル済みのメソッドのフレームに突き当たったらループは終了するので,
MaxRecompilationSearchLength の意味はあんまりないような... #TODO
---------------------------------------- -}
if( !Inline ) { // Inlining turned off
msg = "Inlining turned off";
break;
}
if (next_m->is_not_compilable()) { // Did fail to compile this before/
msg = "caller not compilable";
break;
}
if (next->num() > MaxRecompilationSearchLength) {
// don't go up too high when searching for recompilees
msg = "don't go up any further: > MaxRecompilationSearchLength";
break;
}
if (next->distance() > MaxInterpretedSearchLength) {
// don't go up too high when searching for recompilees
msg = "don't go up any further: next > MaxInterpretedSearchLength";
break;
}
// Compiled frame above already decided not to inline;
// do not recompile him.
if (next->is_compiled()) {
msg = "not going up into optimized code";
break;
}
// Interpreted frame above us was already compiled. Do not force
// a recompile, although if the frame above us runs long enough an
// OSR might still happen.
if( current->is_interpreted() && next_m->has_compiled_code() ) {
msg = "not going up -- already compiled caller";
break;
}
{- -------------------------------------------
(1.1) (変数宣言など)
(以下の cnt 及び freq を定義している.
cnt は, 呼び出し元がこれまでに現在のバイトコードを実行した回数(= このメソッド呼び出しを実行した回数) (<= ダイナミックディスパッチがあるとこのメソッドとは限らないが...).
freq は, cnt の値を「呼び出し元メソッド自体が呼び出された回数」で割ったもの(= 1回の呼び出し中に平均して何回このメソッドを呼んでいるか)
---------------------------------------- -}
// Compute how frequent this call site is. We have current method 'm'.
// We know next method 'next_m' is interpreted. Find the call site and
// check the various invocation counts.
int invcnt = 0; // Caller counts
if (ProfileInterpreter) {
invcnt = next_m->interpreter_invocation_count();
}
int cnt = 0; // Call site counts
if (ProfileInterpreter && next_m->method_data() != NULL) {
ResourceMark rm;
int bci = next->top_vframe()->bci();
ProfileData* data = next_m->method_data()->bci_to_data(bci);
if (data != NULL && data->is_CounterData())
cnt = data->as_CounterData()->count();
}
// Caller counts / call-site counts; i.e. is this call site
// a hot call site for method next_m?
int freq = (invcnt) ? cnt/invcnt : cnt;
{- -------------------------------------------
(1.1) 以下の条件のどれかに当てはまる場合は, ここでループは終了
* 1つ上のスタックフレームについて, StackWalkCompPolicy::shouldInline() が「インライン展開すべきでない」と判定した場合
* 1つ上のスタックフレームについて, StackWalkCompPolicy::shouldNotInline() が「インライン展開すべきでない」と判定した場合
* 1つ上のスタックフレームのメソッドが, JIT コンパイルが禁止されているメソッドである場合 (= CompilationPolicy::can_be_compiled() が false)
* 1つ上のスタックフレームのメソッドが, "<clinit>"(= クラスの初期化用メソッド) である場合.
---------------------------------------- -}
// Check size and frequency limits
if ((msg = shouldInline(m, freq, cnt)) != NULL) {
break;
}
// Check inlining negative tests
if ((msg = shouldNotInline(m)) != NULL) {
break;
}
// If the caller method is too big or something then we do not want to
// compile it just to inline a method
if (!can_be_compiled(next_m)) {
msg = "caller cannot be compiled";
break;
}
if( next_m->name() == vmSymbols::class_initializer_name() ) {
msg = "do not compile class initializer (OSR ok)";
break;
}
{- -------------------------------------------
(1.1) (トレース出力)
---------------------------------------- -}
if (TraceCompilationPolicy && Verbose) {
tty->print("\n\t check caller: ");
next_m->print_short_name(tty);
tty->print(" ( interpreted " INTPTR_FORMAT ", size=%d ) ", (address)next_m(), next_m->code_size());
}
{- -------------------------------------------
(1.1) 対象を1つ上のスタックフレームに上げ, ループの先頭に戻って繰り返し
---------------------------------------- -}
current = next;
}
{- -------------------------------------------
(1) (assert)
---------------------------------------- -}
assert( !current || !current->is_compiled(), "" );
{- -------------------------------------------
(1) (トレース出力)
---------------------------------------- -}
if (TraceCompilationPolicy && msg) tty->print("(%s)\n", msg);
{- -------------------------------------------
(1) 結果をリターン
---------------------------------------- -}
return current;
}
This document is available under the GNU GENERAL PUBLIC LICENSE Version 2.