hotspot/src/cpu/sparc/vm/assembler_sparc.cpp
void MacroAssembler::g1_write_barrier_post(Register store_addr, Register new_val, Register tmp) {
{- -------------------------------------------
(1) (変数宣言など)
---------------------------------------- -}
Label filtered;
MacroAssembler* post_filter_masm = this;
{- -------------------------------------------
(1) 書き込まれる値が G0 レジスタ (= 0) であれば,
記録用のコードを生成する必要は無いので, ここでリターン.
---------------------------------------- -}
if (new_val == G0) return;
{- -------------------------------------------
(1) (変数宣言など)
---------------------------------------- -}
G1SATBCardTableModRefBS* bs = (G1SATBCardTableModRefBS*) Universe::heap()->barrier_set();
{- -------------------------------------------
(1) (assert)
---------------------------------------- -}
assert(bs->kind() == BarrierSet::G1SATBCT ||
bs->kind() == BarrierSet::G1SATBCTLogging, "wrong barrier");
{- -------------------------------------------
(1) コード生成: (ただし, G1RSBarrierRegionFilter オプションが指定されていない場合は生成しない)
「書き込まれる値が同一 HeapRegion 内を指している場合は
(記録する必要が無いので) filtered ラベルまでジャンプ.
(なお, G1PrintCTFilterStats オプションが指定されている場合は(トレース出力)も行う).」
(あるオブジェクトのフィールドに同じ HeapRegion 内のオブジェクトへのポインタが代入された場合.
HeapRegion 間の参照関係を追うための記録処理なので, 同一 HeapRegion 内での参照は無視していい.)
(なお具体的な検査処理は, 書き込み先のアドレス(store_addr)と書き込まれる値(new_val)の xor を取り,
それを HeapRegion の大きさ(のlog2)分だけシフトして 0 かどうか調べる, というもの.
二つの値の違いが HeapRegion 未満(= 同一 HeapRegion 内)であれば結果は 0 になる)
---------------------------------------- -}
if (G1RSBarrierRegionFilter) {
xor3(store_addr, new_val, tmp);
#ifdef _LP64
srlx(tmp, HeapRegion::LogOfHRGrainBytes, tmp);
#else
srl(tmp, HeapRegion::LogOfHRGrainBytes, tmp);
#endif
if (G1PrintCTFilterStats) {
guarantee(tmp->is_global(), "Or stats won't work...");
// This is a sleazy hack: I'm temporarily hijacking G2, which I
// promise to restore.
mov(new_val, G2);
save_frame(0);
mov(tmp, O0);
mov(G2, O1);
// Save G-regs that target may use.
mov(G1, L1);
mov(G2, L2);
mov(G3, L3);
mov(G4, L4);
mov(G5, L5);
call(CAST_FROM_FN_PTR(address, &count_ct_writes));
delayed()->nop();
mov(O0, G2);
// Restore G-regs that target may have used.
mov(L1, G1);
mov(L3, G3);
mov(L4, G4);
mov(L5, G5);
restore(G0, G0, G0);
}
// XXX Should I predict this taken or not? Does it mattern?
br_on_reg_cond(rc_z, /*annul*/false, Assembler::pt, tmp, filtered);
delayed()->nop();
}
{- -------------------------------------------
(1) (変数宣言など)
(もしも, 書き込み先のアドレス("store_addr" レジスタ)が I レジスタや L レジスタの場合には
引数として渡せるようにスクラッチレジスタに移しておく必要がある.
その場合には, 以下の scr 変数のレジスタを使用する. scr は tmp と同じにならないように選んでいる.)
---------------------------------------- -}
// If the "store_addr" register is an "in" or "local" register, move it to
// a scratch reg so we can pass it as an argument.
bool use_scr = !(store_addr->is_global() || store_addr->is_out());
// Pick a scratch register different from "tmp".
Register scr = (tmp == G1_scratch ? G3_scratch : G1_scratch);
{- -------------------------------------------
(1) コード生成:
* 書き込み先のアドレス("store_addr" レジスタ)が I レジスタや L レジスタの場合:
「"store_addr" の値を scr 変数が指すレジスタにコピーしておく」
* それ以外の場合
「何もしない(nop)」
(なぜ nop を生成している?? ここのコードが delay slot に入るパスがある?? #TODO)
---------------------------------------- -}
// Make sure we use up the delay slot!
if (use_scr) {
post_filter_masm->mov(store_addr, scr);
} else {
post_filter_masm->nop();
}
{- -------------------------------------------
(1) コード生成:
「call 命令で dirty_card_log_enqueue 大域変数が指すアドレスにジャンプする.
(ついでに, 遅延スロットで書き込み先のアドレスを O0 レジスタにコピーしておく).
(なお, 呼び出しの前後で save/restore も行っている).」
(なお, この中で使用される dirty_card_log_enqueue 大域変数の値は遅延初期化される.
遅延初期化処理は, 直前で呼び出している generate_dirty_card_log_enqueue_if_necessary() が行う.)
---------------------------------------- -}
generate_dirty_card_log_enqueue_if_necessary(bs->byte_map_base);
save_frame(0);
call(dirty_card_log_enqueue);
if (use_scr) {
delayed()->mov(scr, O0);
} else {
delayed()->mov(store_addr->after_save(), O0);
}
restore();
{- -------------------------------------------
(1) (ここが filtered ラベルの位置)
---------------------------------------- -}
bind(filtered);
}
This document is available under the GNU GENERAL PUBLIC LICENSE Version 2.