hotspot/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.cpp
bool ParallelCompactData::summarize(SplitInfo& split_info,
HeapWord* source_beg, HeapWord* source_end,
HeapWord** source_next,
HeapWord* target_beg, HeapWord* target_end,
HeapWord** target_next)
{
{- -------------------------------------------
(1) (トレース出力)
---------------------------------------- -}
if (TraceParallelOldGCSummaryPhase) {
HeapWord* const source_next_val = source_next == NULL ? NULL : *source_next;
tty->print_cr("sb=" PTR_FORMAT " se=" PTR_FORMAT " sn=" PTR_FORMAT
"tb=" PTR_FORMAT " te=" PTR_FORMAT " tn=" PTR_FORMAT,
source_beg, source_end, source_next_val,
target_beg, target_end, *target_next);
}
{- -------------------------------------------
(1) (変数宣言など)
(cur_region は, 現在処理している region (ループ中で更新していく)
end_region は, 処理範囲の終端を示す region.
dest_addr は, 次に処理するオブジェクトのためのコンパクション先のアドレス (ループ中で更新していく))
---------------------------------------- -}
size_t cur_region = addr_to_region_idx(source_beg);
const size_t end_region = addr_to_region_idx(region_align_up(source_end));
HeapWord *dest_addr = target_beg;
{- -------------------------------------------
(1) 移動元の全 region (引数の source_beg から source_end まで) に対して,
以下の while ループ内で処理を行う
このループ内では, 対象範囲に含まれる全ての region について
対応する ParallelCompactData::RegionData オブジェクトに (あるいは
処理対象の region がコンパクションされる先の ParallelCompactData::RegionData オブジェクトに)
以下の関数で情報を設定する.
* ParallelCompactData::RegionData::set_destination()
* ParallelCompactData::RegionData::set_destination_count()
* ParallelCompactData::RegionData::set_source_region()
* ParallelCompactData::RegionData::set_data_location()
---------------------------------------- -}
while (cur_region < end_region) {
{- -------------------------------------------
(1.1) ParallelCompactData::RegionData::set_destination() で,
コンパクション先のアドレスを dest_addr に設定する.
---------------------------------------- -}
// The destination must be set even if the region has no data.
_region_data[cur_region].set_destination(dest_addr);
{- -------------------------------------------
(1.1) もし, 処理対象の region に live オブジェクトが 1つもなければ,
この処理対象の region については特にすることはないので,
以下の if ブロック内の処理は省略する.
---------------------------------------- -}
size_t words = _region_data[cur_region].data_size();
if (words > 0) {
{- -------------------------------------------
(1.1.1) もし, 処理対象の region 内の live オブジェクトが
コンパクション先の Space には入りきらない場合,
これ以上の処理は出来ないので, ここでリターン.
(なお, リターンする前に
ParallelCompactData::summarize_split_space() を呼んで
適当な分割箇所を記録しておく)
---------------------------------------- -}
// If cur_region does not fit entirely into the target space, find a point
// at which the source space can be 'split' so that part is copied to the
// target space and the rest is copied elsewhere.
if (dest_addr + words > target_end) {
assert(source_next != NULL, "source_next is NULL when splitting");
*source_next = summarize_split_space(cur_region, split_info, dest_addr,
target_end, target_next);
return false;
}
{- -------------------------------------------
(1.1.1) 以下の関数を呼んで, ParallelCompactData::RegionData オブジェクトに情報を設定する.
* ParallelCompactData::RegionData::set_destination_count()
* ParallelCompactData::RegionData::set_source_region()
* ParallelCompactData::RegionData::set_data_location()
設定対象, および設定内容は以下の通り. ただし, 条件については以下のように省略する.
A -- 「処理対象の region が, (コンパクション先を別領域に切り替える)分割点を含んでいる.
(SplitInfo.is_split() が true)」
(なおこの条件は, コンパクション先の Space に入りきらないために一旦諦めた後に,
再度コンパクション先を変えて ParallelCompactData::summarize() が呼び出し直された場合にのみ成り立つ.
See: ParallelCompactData::summarize_split_space(),
SplitInfo::record(),
PSParallelCompact::summary_phase())
A′ -- A であり, かつコンパクション先が 2つの region にまたがる.
B -- 「コンパクション先の region (のうちの少なくとも1つ) は, 処理対象の region である.
(つまり cur_region == dest_region_2)」
C -- 「処理対象の region のコンパクション先が, 2つの region にまたがる.
(つまり dest_region_1 != dest_region_2)」
D -- 「コンパクション先の先頭のアドレスが region のちょうど境界部分にある.
(つまり, region_offset(dest_addr) == 0)」
* ParallelCompactData::RegionData::set_destination_count()
処理対象の region (cur_reigon) に対して設定を行う.
設定する値は以下の通り (詳細は, 以下の destination_count 参照).
* A の場合, ???
* not A && B && C の場合, 1
* not A && not B && C の場合, 2
* not A && not B && not C の場合, 1
* それ以外の場合, 0
(SplitInfo::is_split() が true の場合の destination_count はどうなる??
2 を超えることもありうる??? #TODO)
* ParallelCompactData::RegionData::set_source_region()
処理対象の region (cur_reigon) のコンパクション先の region に対して設定を行う.
設定する値(= コンパクション元)は cur_region.
設定対象となる ParallelCompactData::RegionData オブジェクトは以下のように選択する.
なお, ParallelCompactData::RegionData::set_source_region() については
条件を満たしているものが複数あれば, それら全てに対して呼ばれる.
(逆に, 条件を満たしているものが 1つもなければ 1度も呼ばれない)
* A′が成り立つ場合, 2つの region のうちの後ろの方 (以下の dest_idx) を対象として呼ばれる.
* C が成り立つ場合, 2つの region のうちの後ろの方 (以下の dest_region_2) を対象として呼ばれる.
* D が成り立つ場合, コンパクション先の region (以下の dest_region_1) を対象として呼ばれる.
(なお, C かつ D はない. コンパクション後の量が 1 region 分を超えることはあり得ないので)
* ParallelCompactData::RegionData::set_data_location()
処理対象の region (cur_reigon) に対して設定を行う.
設定する値(= 対応するアドレス)は,
(どの場合においても) 現在の自分自身のアドレス (以下の region_to_addr(cur_region)) とする.
---------------------------------------- -}
// Compute the destination_count for cur_region, and if necessary, update
// source_region for a destination region. The source_region field is
// updated if cur_region is the first (left-most) region to be copied to a
// destination region.
//
// The destination_count calculation is a bit subtle. A region that has
// data that compacts into itself does not count itself as a destination.
// This maintains the invariant that a zero count means the region is
// available and can be claimed and then filled.
uint destination_count = 0;
if (split_info.is_split(cur_region)) {
// The current region has been split: the partial object will be copied
// to one destination space and the remaining data will be copied to
// another destination space. Adjust the initial destination_count and,
// if necessary, set the source_region field if the partial object will
// cross a destination region boundary.
destination_count = split_info.destination_count();
if (destination_count == 2) {
size_t dest_idx = addr_to_region_idx(split_info.dest_region_addr());
_region_data[dest_idx].set_source_region(cur_region);
}
}
HeapWord* const last_addr = dest_addr + words - 1;
const size_t dest_region_1 = addr_to_region_idx(dest_addr);
const size_t dest_region_2 = addr_to_region_idx(last_addr);
// Initially assume that the destination regions will be the same and
// adjust the value below if necessary. Under this assumption, if
// cur_region == dest_region_2, then cur_region will be compacted
// completely into itself.
destination_count += cur_region == dest_region_2 ? 0 : 1;
if (dest_region_1 != dest_region_2) {
// Destination regions differ; adjust destination_count.
destination_count += 1;
// Data from cur_region will be copied to the start of dest_region_2.
_region_data[dest_region_2].set_source_region(cur_region);
} else if (region_offset(dest_addr) == 0) {
// Data from cur_region will be copied to the start of the destination
// region.
_region_data[dest_region_1].set_source_region(cur_region);
}
_region_data[cur_region].set_destination_count(destination_count);
_region_data[cur_region].set_data_location(region_to_addr(cur_region));
{- -------------------------------------------
(1.1.1) 今回処理したオブジェクトの大きさ分だけ dest_addr を進める.
---------------------------------------- -}
dest_addr += words;
}
{- -------------------------------------------
(1.1) 処理対象を次の region へ進める.
---------------------------------------- -}
++cur_region;
}
{- -------------------------------------------
(1) リターンする.
(なおリターンの直前に, 引数で渡された target_next に dest_addr を書き込んでおく)
---------------------------------------- -}
*target_next = dest_addr;
return true;
}
This document is available under the GNU GENERAL PUBLIC LICENSE Version 2.