hotspot/src/share/vm/code/nmethod.cpp
// An nmethod is "marked" if its _mark_link is set non-null.
// Even if it is the end of the linked list, it will have a non-null link value,
// as long as it is on the list.
// This code must be MP safe, because it is used from parallel GC passes.
bool nmethod::test_set_oops_do_mark() {
{- -------------------------------------------
(1) (assert)
---------------------------------------- -}
assert(nmethod::oops_do_marking_is_active(), "oops_do_marking_prologue must be called");
{- -------------------------------------------
(1) (変数宣言など) (なお _oops_do_mark_link は volatile)
---------------------------------------- -}
nmethod* observed_mark_link = _oops_do_mark_link;
{- -------------------------------------------
(1) 以下でこの nmethod オブジェクトの mark 処理を行う.
処理は, カレントスレッドが _oops_do_mark_link の書き換えに成功するかどうかで 2通りに分かれる.
* カレントスレッドが _oops_do_mark_link の書き換えを行った場合
(= この時点でまだ _oops_do_mark_link フィールドが NULL であり, かつ
_oops_do_mark_link フィールドの書き換えにも成功した場合)
=> この nmethod オブジェクトを _oops_do_mark_nmethods リストにつなぎ, false をリターン.
* 他のスレッドによって _oops_do_mark_link が書き換えられた場合
(= この時点で _oops_do_mark_link フィールドが NULL ではない場合 or
_oops_do_mark_link フィールドの書き換えに失敗した場合)
=> 何もせずに true をリターン.
---------------------------------------- -}
if (observed_mark_link == NULL) {
{- -------------------------------------------
(1.1) (以下は, この時点でまだ _oops_do_mark_link フィールドが NULL の場合)
---------------------------------------- -}
{- -------------------------------------------
(1.1) Atomic::cmpxchg_ptr() で _oops_do_mark_link を non-null な値(NMETHOD_SENTINEL)に書き換える.
(なお, 書き換えが失敗した場合は, 他のスレッドが先に書き換えたということなので,
残りの処理はそのスレッドに任せればいい.
このままフォールスルーして true をリターンするだけ.)
---------------------------------------- -}
// Claim this nmethod for this thread to mark.
observed_mark_link = (nmethod*)
Atomic::cmpxchg_ptr(NMETHOD_SENTINEL, &_oops_do_mark_link, NULL);
if (observed_mark_link == NULL) {
{- -------------------------------------------
(1.1.1) (以下は, カレントスレッドが _oops_do_mark_link の書き換えを行った場合)
---------------------------------------- -}
{- -------------------------------------------
(1.1.1) この nmethod オブジェクトを, _oops_do_mark_nmethods フィールドに格納されているリストの先頭に追加する.
他のスレッドと競合する恐れがあるので, 成功するまで以下の for ループで Atomic::cmpxchg_ptr() を繰り返す.
追加が完了したら false をリターン.
---------------------------------------- -}
// Atomically append this nmethod (now claimed) to the head of the list:
nmethod* observed_mark_nmethods = _oops_do_mark_nmethods;
for (;;) {
nmethod* required_mark_nmethods = observed_mark_nmethods;
_oops_do_mark_link = required_mark_nmethods;
observed_mark_nmethods = (nmethod*)
Atomic::cmpxchg_ptr(this, &_oops_do_mark_nmethods, required_mark_nmethods);
if (observed_mark_nmethods == required_mark_nmethods)
break;
}
// Mark was clear when we first saw this guy.
NOT_PRODUCT(if (TraceScavenge) print_on(tty, "oops_do, mark"));
return false;
}
}
{- -------------------------------------------
(1) (以下は, 他のスレッドによって _oops_do_mark_link が書き換えられた場合
= _oops_do_mark_link フィールドが NULL ではなかった場合 or Atomic::cmpxchg_ptr() に失敗した場合)
true をリターンするだけ.
---------------------------------------- -}
// On fall through, another racing thread marked this nmethod before we did.
return true;
}
This document is available under the GNU GENERAL PUBLIC LICENSE Version 2.