hotspot/src/cpu/x86/vm/assembler_x86.cpp
void MacroAssembler::g1_write_barrier_post(Register store_addr,
Register new_val,
Register thread,
Register tmp,
Register tmp2) {
{- -------------------------------------------
(1) (assert)
---------------------------------------- -}
#ifdef _LP64
assert(thread == r15_thread, "must be");
#endif // _LP64
{- -------------------------------------------
(1) (変数宣言など)
---------------------------------------- -}
Address queue_index(thread, in_bytes(JavaThread::dirty_card_queue_offset() +
PtrQueue::byte_offset_of_index()));
Address buffer(thread, in_bytes(JavaThread::dirty_card_queue_offset() +
PtrQueue::byte_offset_of_buf()));
BarrierSet* bs = Universe::heap()->barrier_set();
CardTableModRefBS* ct = (CardTableModRefBS*)bs;
Label done;
Label runtime;
{- -------------------------------------------
(1) コード生成:
「書き込まれる値が同一 HeapRegion 内を指している場合は
(記録する必要が無いので) done ラベルまでジャンプ.」
(あるオブジェクトのフィールドに同じ HeapRegion 内のオブジェクトへのポインタが代入された場合.
HeapRegion 間の参照関係を追うための記録処理なので, 同一 HeapRegion 内での参照は無視していい.)
(なお具体的な検査処理は, 書き込み先のアドレス(store_addr)と書き込まれる値(new_val)の xor を取り,
それを HeapRegion の大きさ(のlog2)分だけシフトして 0 かどうか調べる, というもの.
二つの値の違いが HeapRegion 未満(= 同一 HeapRegion 内)であれば結果は 0 になる)
(sparc 版では, このコードは G1RSBarrierRegionFilter オプションで生成するかどうかを制御できるようだが... #TODO)
---------------------------------------- -}
// Does store cross heap regions?
movptr(tmp, store_addr);
xorptr(tmp, new_val);
shrptr(tmp, HeapRegion::LogOfHRGrainBytes);
jcc(Assembler::equal, done);
{- -------------------------------------------
(1) コード生成:
「書き込まれる値が 0 かどうかチェックする.
0 であれば, 記録する必要は無いので, done ラベルまでジャンプ.」
---------------------------------------- -}
// crosses regions, storing NULL?
cmpptr(new_val, (int32_t) NULL_WORD);
jcc(Assembler::equal, done);
{- -------------------------------------------
(1) コード生成:
「書き込み先のアドレスに対応する card table 中の値を確認する.
既に dirty (= 0) になっている場合は, もう記録処理は必要無いので, done ラベルまでジャンプ.」
(より具体的には,
まず, 書き込み先のアドレス(card_addr)の値を CardTableModRefBS::card_shift 分だけ右シフトさせて,
対応する card table 内の index を計算する.
次に, それに card table のアドレス(byte_map_base 引数の値)を足し込んだアドレスから
1byte ロードし, 0 と比較する)
(なお, 0 が dirty を示す (See: dirty_card))
---------------------------------------- -}
// storing region crossing non-NULL, is card already dirty?
ExternalAddress cardtable((address) ct->byte_map_base);
assert(sizeof(*ct->byte_map_base) == sizeof(jbyte), "adjust this code");
#ifdef _LP64
const Register card_addr = tmp;
movq(card_addr, store_addr);
shrq(card_addr, CardTableModRefBS::card_shift);
lea(tmp2, cardtable);
// get the address of the card
addq(card_addr, tmp2);
#else
const Register card_index = tmp;
movl(card_index, store_addr);
shrl(card_index, CardTableModRefBS::card_shift);
Address index(noreg, card_index, Address::times_1);
const Register card_addr = tmp;
lea(card_addr, as_Address(ArrayAddress(cardtable, index)));
#endif
cmpb(Address(card_addr, 0), 0);
jcc(Assembler::equal, done);
{- -------------------------------------------
(1) コード生成:
「card table 中の該当箇所に 0 を書き込んで dirty 化する」
---------------------------------------- -}
// storing a region crossing, non-NULL oop, card is clean.
// dirty card and log.
movb(Address(card_addr, 0), 0);
{- -------------------------------------------
(1) コード生成:
「JavaThread::_dirty_card_queue フィールドの DirtyCardQueue オブジェクト内の
_index フィールドの値をチェックする.
もし値が 0 の場合は, 次のバッファを用意する必要があるので, runtime ラベルにジャンプする.」
(なお, _index がバッファ中の現在の終端位置を示す. 値が 0 であればもう空き領域はない)
---------------------------------------- -}
cmpl(queue_index, 0);
jcc(Assembler::equal, runtime);
{- -------------------------------------------
(1) コード生成:
「JavaThread::_dirty_card_queue フィールドの DirtyCardQueue オブジェクト内の
_index フィールドの値を
wordSize 分だけ小さくし, _index フィールドに書き戻す.」
---------------------------------------- -}
subl(queue_index, wordSize);
{- -------------------------------------------
(1) コード生成:
「JavaThread::_satb_mark_queue フィールドの ObjPtrQueue オブジェクト内の
_buf 内の _index の位置に保存対象の値(以下の card_addr または card_index)を書き込む.」
---------------------------------------- -}
movptr(tmp2, buffer);
#ifdef _LP64
movslq(rscratch1, queue_index);
addq(tmp2, rscratch1);
movq(Address(tmp2, 0), card_addr);
#else
addl(tmp2, queue_index);
movl(Address(tmp2, 0), card_index);
#endif
{- -------------------------------------------
(1) コード生成:
「done ラベルにジャンプする (これで write barrier 処理は終了)」
---------------------------------------- -}
jmp(done);
{- -------------------------------------------
(1) (以降が runtime ラベルに飛んだ場合の処理)
---------------------------------------- -}
bind(runtime);
{- -------------------------------------------
(1) 生きているレジスタを待避するコードを生成しておく.
---------------------------------------- -}
// save the live input values
push(store_addr);
push(new_val);
{- -------------------------------------------
(1) コード生成:
「SharedRuntime::g1_wb_post() を呼び出し, バッファの確保及び write barrier 処理を行う.」
(また, NOT_LP64 の場合には, 呼び出しの前後で thread 引数が示すレジスタの待避/復帰も行う)
---------------------------------------- -}
#ifdef _LP64
call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::g1_wb_post), card_addr, r15_thread);
#else
push(thread);
call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::g1_wb_post), card_addr, thread);
pop(thread);
#endif
{- -------------------------------------------
(1) 待避したレジスタを復帰させるコードを生成しておく.
---------------------------------------- -}
pop(new_val);
pop(store_addr);
{- -------------------------------------------
(1) (ここが done ラベルの位置)
---------------------------------------- -}
bind(done);
}
This document is available under the GNU GENERAL PUBLIC LICENSE Version 2.