hotspot/src/cpu/sparc/vm/interp_masm_sparc.cpp
// unlock if synchronized method
//
// Unlock the receiver if this is a synchronized method.
// Unlock any Java monitors from syncronized blocks.
//
// If there are locked Java monitors
// If throw_monitor_exception
// throws IllegalMonitorStateException
// Else if install_monitor_exception
// installs IllegalMonitorStateException
// Else
// no error processing
void InterpreterMacroAssembler::unlock_if_synchronized_method(TosState state,
bool throw_monitor_exception,
bool install_monitor_exception) {
{- -------------------------------------------
(1) (変数宣言など)
---------------------------------------- -}
Label unlocked, unlock, no_unlock;
{- -------------------------------------------
(1) コード生成:
「カレントスレッド内の JavaThread::do_not_unlock_if_synchronized フィールドの値を G1_scratch に取得.
(なお, JavaThread::do_not_unlock_if_synchronized フィールド自体は 0 に戻す)」
(このフィールドの意味については, メソッドエントリ部の処理を参照. (See: [here](no3059n2f.html) for details))
---------------------------------------- -}
// get the value of _do_not_unlock_if_synchronized into G1_scratch
const Address do_not_unlock_if_synchronized(G2_thread,
JavaThread::do_not_unlock_if_synchronized_offset());
ldbool(do_not_unlock_if_synchronized, G1_scratch);
stbool(G0, do_not_unlock_if_synchronized); // reset the flag
{- -------------------------------------------
(1) コード生成:
「呼び出したメソッドが synchronized 指定されているかどうかをチェック.
synchronized でない場合は, することはないので unlocked までジャンプ.
(なお, ついでに push() で TOS に入っている返値をスタック上に待避している)」
---------------------------------------- -}
// check if synchronized method
const Address access_flags(Lmethod, methodOopDesc::access_flags_offset());
interp_verify_oop(Otos_i, state, __FILE__, __LINE__);
push(state); // save tos
ld(access_flags, G3_scratch); // Load access flags.
btst(JVM_ACC_SYNCHRONIZED, G3_scratch);
br(zero, false, pt, unlocked);
delayed()->nop();
{- -------------------------------------------
(1) コード生成:
「取得してあった JavaThread::do_not_unlock_if_synchronized フィールドの値を確認する.
もし true だった場合には, 何もしなくてよいので no_unlock までジャンプ」
---------------------------------------- -}
// Don't unlock anything if the _do_not_unlock_if_synchronized flag
// is set.
tstbool(G1_scratch);
br(Assembler::notZero, false, pn, no_unlock);
delayed()->nop();
{- -------------------------------------------
(1) (synchronized method なので, 先頭の BasicObjectLock がアンロック対象になるはず.
ただし, モニターが変になっていないことのチェックが必要.
より具体的には, その BasicObjectLock が monitorexit によって既に解放されていないこと, をチェックしておく.)
---------------------------------------- -}
// BasicObjectLock will be first in list, since this is a synchronized method. However, need
// to check that the object has not been unlocked by an explicit monitorexit bytecode.
//Intel: if (throw_monitor_exception) ... else ...
// Entry already unlocked, need to throw exception
//...
{- -------------------------------------------
(1) コード生成:
「先頭の BasicObjectLock 内の obj フィールドを確認しておく.
NULL でなければ (= 解放済みでなければ), unlock ラベルにジャンプしてアンロック処理を行う.
逆に NULL の場合は (= 既に解放済みの場合は), このままフォールスルーして以下のどれかの処理を行う.
(なお, 以下の処理はコード生成時に引数に応じてどれかが生成される. 動的に条件判定で処理を分岐するわけではない)
* 引数の throw_monitor_exception が true の場合
InterpreterRuntime::throw_illegal_monitor_state_exception() を呼び出して
IllegalMonitorStateException を出す.
* (throw_monitor_exception は false だが) 引数の install_monitor_exception が true の場合
InterpreterRuntime::new_illegal_monitor_state_exception() を呼び出して
IllegalMonitorStateException を出す.
* それ以外の場合
アンロックできたことにして, unlocked ラベルにジャンプする. 」
---------------------------------------- -}
// pass top-most monitor elem
add( top_most_monitor(), O1 );
ld_ptr(O1, BasicObjectLock::obj_offset_in_bytes(), G3_scratch);
br_notnull(G3_scratch, false, pt, unlock);
delayed()->nop();
if (throw_monitor_exception) {
// Entry already unlocked need to throw an exception
MacroAssembler::call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_illegal_monitor_state_exception));
should_not_reach_here();
} else {
// Monitor already unlocked during a stack unroll.
// If requested, install an illegal_monitor_state_exception.
// Continue with stack unrolling.
if (install_monitor_exception) {
MacroAssembler::call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::new_illegal_monitor_state_exception));
}
ba(false, unlocked);
delayed()->nop();
}
{- -------------------------------------------
(1) コード生成:
「InterpreterMacroAssembler::unlock_object() が生成するコードで,
ロックの解放処理を行う」
---------------------------------------- -}
bind(unlock);
unlock_object(O1);
{- -------------------------------------------
(1) コード生成:
「(ここが unlocked ラベルの位置)」
---------------------------------------- -}
bind(unlocked);
{- -------------------------------------------
(1) (この段階では, I0 と I1 に返値が入っている可能性がある.)
---------------------------------------- -}
// I0, I1: Might contain return value
{- -------------------------------------------
(1) (以下で, 全てのモニターがアンロックされていることを確認する.
もしロックが取られたままのモニターがあれば, IllegalMonitorStateException)
(制御フローは少し混み合っていて, 以下のようになっている. 何でこんな書き方になってるのか?? #TODO
処理は (restart ラベルを経由して) entry ラベルから始まり,
その後 loop で全部の要素の処理が終わるまでループが繰り返される.
ただし, ロックが取られたままの要素が見つかれば, exception にジャンプして例外送出が行われる.
ただし, exception で例外送出が行われないケースもあり, その場合は
(restart ラベルを経由して) ループが再開される.)
---------------------------------------- -}
// Check that all monitors are unlocked
{- -------------------------------------------
(1.1) (変数宣言など)
---------------------------------------- -}
{ Label loop, exception, entry, restart;
Register Rmptr = O0;
Register Rtemp = O1;
Register Rlimit = Lmonitors;
const jint delta = frame::interpreter_frame_monitor_size() * wordSize;
assert( (delta & LongAlignmentMask) == 0,
"sizeof BasicObjectLock must be even number of doublewords");
{- -------------------------------------------
(1.1) (デバッグ用の処理) (#ifdef ASSERT 時にのみ実行)
コード生成: (デバッグ用の処理)
---------------------------------------- -}
#ifdef ASSERT
add(top_most_monitor(), Rmptr, delta);
{ Label L;
// ensure that Rmptr starts out above (or at) Rlimit
cmp(Rmptr, Rlimit);
brx(Assembler::greaterEqualUnsigned, false, pn, L);
delayed()->nop();
stop("monitor stack has negative size");
bind(L);
}
#endif
{- -------------------------------------------
(1.1) コード生成:
「(ここが restart ラベルの位置)」
---------------------------------------- -}
bind(restart);
{- -------------------------------------------
(1.1) コード生成:
「entry ラベルにジャンプして, 確認処理を開始する」
---------------------------------------- -}
ba(false, entry);
delayed()->
add(top_most_monitor(), Rmptr, delta); // points to current entry, starting with bottom-most entry
{- -------------------------------------------
(1.1) コード生成:
「(ここが exception ラベルの位置)
以下のどれかの処理を行う.
(なお, 以下の処理はコード生成時に引数に応じてどれかが生成される. 動的に条件判定で処理を分岐するわけではない)
* 引数の throw_monitor_exception が true の場合
InterpreterRuntime::throw_illegal_monitor_state_exception() を呼び出して
IllegalMonitorStateException を出す.
* (throw_monitor_exception は false だが) 引数の install_monitor_exception が true の場合
InterpreterRuntime::new_illegal_monitor_state_exception() を呼び出して
IllegalMonitorStateException を出す.
* それ以外の場合
何もしない. このまま restart ラベルにジャンプして次の要素の処理に進む.」
---------------------------------------- -}
// Entry is still locked, need to throw exception
bind(exception);
if (throw_monitor_exception) {
MacroAssembler::call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_illegal_monitor_state_exception));
should_not_reach_here();
} else {
// Stack unrolling. Unlock object and if requested, install illegal_monitor_exception.
// Unlock does not block, so don't have to worry about the frame
unlock_object(Rmptr);
if (install_monitor_exception) {
MacroAssembler::call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::new_illegal_monitor_state_exception));
}
ba(false, restart);
delayed()->nop();
}
{- -------------------------------------------
(1.1) コード生成:
「(ここが loop ラベルの位置)
もし obj フィールドが NULL であれば, exception ラベルにジャンプして例外送出を行う.
そうでなければ, Rmptr をデクリメントした後, このままフォールスルー.」
---------------------------------------- -}
bind(loop);
cmp(Rtemp, G0); // check if current entry is used
brx(Assembler::notEqual, false, pn, exception);
delayed()->
dec(Rmptr, delta); // otherwise advance to next entry
{- -------------------------------------------
(1.1) (デバッグ用の処理) (#ifdef ASSERT 時にのみ実行)
コード生成: (デバッグ用の処理)
---------------------------------------- -}
#ifdef ASSERT
{ Label L;
// ensure that Rmptr has not somehow stepped below Rlimit
cmp(Rmptr, Rlimit);
brx(Assembler::greaterEqualUnsigned, false, pn, L);
delayed()->nop();
stop("ran off the end of the monitor stack");
bind(L);
}
#endif
{- -------------------------------------------
(1.1) コード生成:
「(ここが entry ラベルの位置)
まだ全ての BasicObjectLock を処理し終えていなければ (= RLimit に達していなければ),
loop にジャンプして現在の BasicObjectLock オブジェクトの処理を行う.
逆に全ての BasicObjectLock を処理し終えたら, このままフォールスルーして終了」
---------------------------------------- -}
bind(entry);
cmp(Rmptr, Rlimit); // check if bottom reached
brx(Assembler::notEqual, true, pn, loop); // if not at bottom then check this entry
delayed()->
ld_ptr(Rmptr, BasicObjectLock::obj_offset_in_bytes() - delta, Rtemp);
}
{- -------------------------------------------
(1) (ここまでが, 全てのモニターがアンロックされていることを確認する処理)
---------------------------------------- -}
{- -------------------------------------------
(1) コード生成:
「(ここが no_unlock ラベルの位置)」
---------------------------------------- -}
bind(no_unlock);
{- -------------------------------------------
(1) コード生成:
「待避していた TOS を復帰させておく」
---------------------------------------- -}
pop(state);
{- -------------------------------------------
(1) コード生成: (verify)
---------------------------------------- -}
interp_verify_oop(Otos_i, state, __FILE__, __LINE__);
}
This document is available under the GNU GENERAL PUBLIC LICENSE Version 2.