hotspot/src/share/vm/interpreter/rewriter.cpp
// Rewrites a method given the index_map information
void Rewriter::scan_method(methodOop method, bool reverse) {
{- -------------------------------------------
(1) (変数宣言など)
---------------------------------------- -}
int nof_jsrs = 0;
bool has_monitor_bytecodes = false;
{- -------------------------------------------
(1) 以下のブロック内で, method 引数で指定されたメソッド中の
バイトコードの書き換え処理を行う.
---------------------------------------- -}
{
{- -------------------------------------------
(1.1) (No_Safepoint_Verifier)(= このブロック内では Safepoint 停止は起こらないはず)
---------------------------------------- -}
// We cannot tolerate a GC in this block, because we've
// cached the bytecodes in 'code_base'. If the methodOop
// moves, the bytecodes will also move.
No_Safepoint_Verifier nsv;
{- -------------------------------------------
(1.1) (変数宣言など)
---------------------------------------- -}
Bytecodes::Code c;
// Bytecodes and their length
const address code_base = method->code_base();
const int code_length = method->code_size();
{- -------------------------------------------
(1.1) 以下の for ループ中で,
method 引数で指定されたメソッド中の全バイトコードを辿り
書き換え対象のバイトコード命令であれば rewrite 処理を行う.
---------------------------------------- -}
int bc_length;
for (int bci = 0; bci < code_length; bci += bc_length) {
{- -------------------------------------------
(1.1.1) (変数宣言など)
---------------------------------------- -}
address bcp = code_base + bci;
int prefix_length = 0;
c = (Bytecodes::Code)(*bcp);
{- -------------------------------------------
(1.1.1) (局所変数の初期化)
---------------------------------------- -}
// Since we have the code, see if we can get the length
// directly. Some more complicated bytecodes will report
// a length of zero, meaning we need to make another method
// call to calculate the length.
bc_length = Bytecodes::length_for(c);
if (bc_length == 0) {
bc_length = Bytecodes::length_at(method, bcp);
// length_at will put us at the bytecode after the one modified
// by 'wide'. We don't currently examine any of the bytecodes
// modified by wide, but in case we do in the future...
if (c == Bytecodes::_wide) {
prefix_length = 1;
c = (Bytecodes::Code)bcp[1];
}
}
assert(bc_length != 0, "impossible bytecode length");
{- -------------------------------------------
(1.1.1) 以下の switch 内で, 対象のバイトコード種別に応じた処理を実施.
---------------------------------------- -}
switch (c) {
{- -------------------------------------------
(1.1.1.1) lookupswitch 命令の場合,
Bytecodes::_fast_linearswitch 命令, または Bytecodes::_fast_binaryswitch 命令に書き換え.
(どちらも HotSpot 独自のバイトコード命令)
(どちらにするかは, 飛び先候補の数に応じて決定.
候補数が BinarySwitchThreshold オプションの値より少なければ fast_linearswitch,
それ以上であれば _fast_binaryswitch にする)
(ただし, Interpreter が C++ Interpreter である場合 (= CC_INTERP が #define されている場合) はやらない)
---------------------------------------- -}
case Bytecodes::_lookupswitch : {
#ifndef CC_INTERP
Bytecode_lookupswitch bc(method, bcp);
(*bcp) = (
bc.number_of_pairs() < BinarySwitchThreshold
? Bytecodes::_fast_linearswitch
: Bytecodes::_fast_binaryswitch
);
#endif
break;
}
{- -------------------------------------------
(1.1.1.1) Bytecodes::_fast_linearswitch 命令や Bytecodes::_fast_binaryswitch 命令の場合,
lookupswitch 命令に書き換え.
(書き換えた lookupswitch 命令を元に戻す場合の処理)
(Interpreter が C++ Interpreter である場合 (= CC_INTERP が #define されている場合) はやらない)
---------------------------------------- -}
case Bytecodes::_fast_linearswitch:
case Bytecodes::_fast_binaryswitch: {
#ifndef CC_INTERP
(*bcp) = Bytecodes::_lookupswitch;
#endif
break;
}
{- -------------------------------------------
(1.1.1.1) {get|put}{static|field} 命令や invoke* 命令(invokedynamic除く) の場合,
Rewriter::rewrite_member_reference() を呼んで
バイトコード命令中の Constant Pool index が埋まっている 2byte を
Constant Pool Cache の index に置き換える.
(なお, reverse 引数が true の場合には, 逆に元に戻す処理が行われる)
---------------------------------------- -}
case Bytecodes::_getstatic : // fall through
case Bytecodes::_putstatic : // fall through
case Bytecodes::_getfield : // fall through
case Bytecodes::_putfield : // fall through
case Bytecodes::_invokevirtual : // fall through
case Bytecodes::_invokespecial : // fall through
case Bytecodes::_invokestatic :
case Bytecodes::_invokeinterface:
rewrite_member_reference(bcp, prefix_length+1, reverse);
break;
{- -------------------------------------------
(1.1.1.1) invokedynamic 命令の場合,
Rewriter::rewrite_invokedynamic() を呼んで
バイトコード命令中の Constant Pool index が埋まっている 4byte を
Constant Pool Cache の index に置き換える.
(なお, invokedynamic に関しては
Constant Pool の index と Constant Pool Cache の index が 1対1対応ではなく,
CP の 1つの index に対して CPC の複数の index が対応する.
invokedynamic が 2byte ではなく 4byte の operand を取るのは,
このような実装を考慮してのことらしい
(もちろん他の JVM 実装では他の用途で使うかもしれないが))
---------------------------------------- -}
case Bytecodes::_invokedynamic:
rewrite_invokedynamic(bcp, prefix_length+1, reverse);
break;
{- -------------------------------------------
(1.1.1.1) ldc 命令や ldc_w 命令の場合,
Rewriter::maybe_rewrite_ldc() を呼んで
バイトコード命令の書き換えを行う
(この関数では,
ロード対象が method handle もしくは method type の場合には
Bytecodes::_fast_aldc 命令や Bytecodes::_fast_aldc_w 命令に置き換える
(どちらも HotSpot 独自のバイトコード命令).
ロード対象がそれ以外の定数の場合は, 何もしない)
(なお, reverse 引数が true の場合には, 逆に元に戻す処理が行われる)
---------------------------------------- -}
case Bytecodes::_ldc:
case Bytecodes::_fast_aldc:
maybe_rewrite_ldc(bcp, prefix_length+1, false, reverse);
break;
case Bytecodes::_ldc_w:
case Bytecodes::_fast_aldc_w:
maybe_rewrite_ldc(bcp, prefix_length+1, true, reverse);
break;
{- -------------------------------------------
(1.1.1.1) jsr 命令, jsr_w 命令, monitorenter 命令, monitorexit 命令があった場合は,
そのことを局所変数に記録しておく.
(この関数内の後の処理で参照)
(ところで, 現状の使われ方を見る限り nof_jsrs も boolean でいい気がするが...)
---------------------------------------- -}
case Bytecodes::_jsr : // fall through
case Bytecodes::_jsr_w : nof_jsrs++; break;
case Bytecodes::_monitorenter : // fall through
case Bytecodes::_monitorexit : has_monitor_bytecodes = true; break;
}
}
}
{- -------------------------------------------
(1) monitorenter 命令や monitorexit 命令があった場合は,
このメソッドのフラグに JVM_ACC_HAS_MONITOR_BYTECODES ビットを立てておく.
(この情報は, JIT コンパイラが最適化の可否を判断する際などに用いられる模様 #TODO)
---------------------------------------- -}
// Update access flags
if (has_monitor_bytecodes) {
method->set_has_monitor_bytecodes();
}
{- -------------------------------------------
(1) jsr 命令や jsr_w 命令があった場合は,
このメソッドのフラグに JVM_ACC_HAS_JSRS ビットを立てておく.
(この情報は, 後で飛び先を再配置する際の目安として参照される (See: Rewriter::relocate_and_link()))
(また, この情報は JIT コンパイラが最適化の可否を判断する際などにも用いられる模様 #TODO)
---------------------------------------- -}
// The present of a jsr bytecode implies that the method might potentially
// have to be rewritten, so we run the oopMapGenerator on the method
if (nof_jsrs > 0) {
method->set_has_jsrs();
// Second pass will revisit this method.
assert(method->has_jsrs(), "didn't we just set this?");
}
}
This document is available under the GNU GENERAL PUBLIC LICENSE Version 2.