Next: トレーサ
Up: GC
Previous: copy_one_queue()
GC スタックの内容をコピーする。GCの心臓部分。
- 1.
- GC スタックトップを取りだす(addr)。
このaddrは今後書きかえられるが、常に「書き戻すべきアドレス」を指している
一段derefしたものをobjとする。
- 2.
- objのタグに応じて処理する。
- ATOMICの場合には、addr の先にobjを書き、1へ。
- REFの場合には、objの先をderefし、valueに入れる。 valueのタグに対応し、以下の処理を行う。
- REFの場合:
- 一重ループであり、かつ、addrが新領域にあれば、addr自身を一重ループ
にし、1にもどる。
- 一重ループであり、かつ、addrが新領域になければ、新領域に
一重ループを生成し、それへのREFをaddrに入れ、1にもどる。
- 二重ループであれば、その先はgeneratorかhook構造体であるのでコピーする。
- Generatorであれば、新領域に1ワードわりつけ、addrに書きこむ。
このワードは、二重ループのエントリになる。
objectの先頭を調べ、コピー済みでなければ、そっくり
そのままコピーする(Generator自身のコピーは、GC methodを呼びだす)。
先頭をコピー先に書きかえる。コピー済ならば、suspend構造までを作成し、
generatorのコピー先のアドレスをコピーする。
- 中断ゴールまたはconsumerであるならば、不要となったgoal(すでにscheduling
されたゴール)を避けつつ、コピーする。
- 一/二重ループでなく、かつ、valueが旧領域を指しているならば、
objをvalueとし、2へ(つまり、dereference loopを成す)。
- valueが旧領域以外(つまり、新領域 or ヒープ外)であれば、
この先はコピー済であることがわかったので、
addrの先にvalueを書きこみ1へ。
- CONSの場合には、valueが新領域であれば、これはCONS2ワードとも
すでにコピーされている
ことを意味する(
ページ、第7.3章参照)ので、それをaddrの先に書きこむ。
新領域でなければ、objにvalueをコピーし、一ループレベル上の
CONSの項2に飛ぶ。
- ATOMICであれば、addrの先にATOM値を書き1に。
- FUNCTORであれば、objにvalueをコピーし、一ループレベル上の
FUNCTORの項(
ページ、第2章参照)に飛ぶ。
- objがCONSであることが判明すれば、それが新領域を指しているか、
旧領域を指しているか判断する。新領域であれば、それはCONS2ワードとも
すでにコピーされていることを意味する(
ページ、第7.3章参照)ので、
それをaddrの先に書きこむ。
旧領域であれば、CDRを読み出す。
- CDRが構造体(実際に意味を持つのはCONS)タグを持ち、新領域を指していれば、
それは、CDRの示す先にCONS全体がコピーされていることを意味するので、
addrの先にCDRをコピーする。
- 上記以外であれば、まだそのCONSはコピーされていない。
- (a)
- 新領域ヒープ上に2ワードセルを確保する。
- (b)
- CAR部分をコピーするために、reserve_copyにより
スタックに積む。
- (c)
- 新しい2ワードセルへCONSポインタを、旧領域のコピー元の2ワードセルの
CDR部分、および、addrの先(追跡が開始されたセルで新領域にある)にコピーする。
- (d)
- CDR部分がATOMICであれば、そのままコピーし、2にジャンプする。
ATOMICでなければ、新しい2ワードセルのCDR部分のアドレスをaddrに、
objにCDRをコピーし、スタックに積まずに2にジャンプする。
つまり、このCDR処理部分は、末尾再帰処理の最適化をしている。
- ObjがFUNCTORタグであることがわかれば、それが旧領域を指すかどうか
検査する。旧領域でなければaddrの先にコピーしてそのまま終了。
旧領域であれば、第一ファンクタを読み出し、そのタグを調べる。
- 第一ファンクタが REFであれば、これはデータオブジェクトで
あることを意味するので、GC methodを呼びだし、
それへのポインタをFUNCTORタグ付きでコピーする。旧領域の第一ファンクタ部
も新領域のobjectへのFUNCTOR付きポインタとし、addrの先に書きこむ。
- 第一ファンクタがREFでなく、FUNCTORでもなければ、
これはFUNCTORであることがわかるので、
新領域にファンクタの領域を確保し、第一ファンクタへのポインタを
FUNCTORタグ付きでaddrの先、旧領域のオブジェクトの第一ファンクタ位置に
書きこむ。さらに全ての要素についてのコピーをスタックに積む
(reserve_copy())。
- 第一ファンクタがファンクタであれば、これはコピーされた
FUNCTORまたはオブジェクトであるので、その第一ファンクタの内容を
addrの先に書く。
以上の処理のあと、1にジャンプする。
- 3.
- スタックが空になれば、処理は終了する。
Sekita Daigo
1998-05-18