Scm_VMCallCC (12)

ちょっと今日も色々とばたばたしたので進捗は微妙だと思います (を

ブラウザの

履歴をよんどころのない事情にて検索中に_Gauche:YAGHG:VM:フレームのヒープへのコピー_という文書を発見。ちょっと URL のコピペが微妙なのでタイトルのみ、なのが自分的に微妙。
それは良いとして、この資料を見つつへろへろながらも_ひらメソド_方式で控え。

save_env

引用しつつコメントを。

static inline ScmEnvFrame *save_env(ScmVM *vm, ScmEnvFrame *env_begin)
{
    ScmEnvFrame *e = env_begin, *prev = NULL, *next, *head = NULL, *saved;
  • 変数をナニ
    • e : 処理対象になってる環境フレームを指す
      • up を手繰って処理が進む
      • スタックの中認定の限り処理続行
    • prev : 直前に退避された要素を指す
    • next : 環境フレームの次の処理対象の要素を指す
    • head : 保存されたフレームの先頭要素を指す (これが戻る)
    • saved : ヒープな領域を指すためのポインタ
      • 若干微妙なハンドル

で、env_begin が指すナニが既に退避済みかどうかを判定

    if (!IN_STACK_P((ScmObj*)e)) return e;

繰り返しの先頭でも退避済みかどうかをチェキ

    do {
        int esize = e->size, i;
        ScmObj *d, *s;

        if (e->size < 0) {
            /* forwaded frame */
            if (prev) prev->up = FORWARDED_ENV(e);
            return head;
        }

基本的に処理対象の e がスタックの中である限り処理が続行される仕様。ただし size 属性が負の値だった場合は既にヒープに退避されたものとなる。

if (prev)

の中の処理はマンガ描く必要あり。ここではスルー。ちょっと気持ち悪いのでざくっと見てみると

A -> B -> C -> end

な環境フレームなリストがあるとして
# 矢印は up なリンクです
ケツまで save_env したら

A -> A' ->
           B' ->
     B  ->       C' ->end
           C  ->

みたいなカンジになる?
# B' は A' と B の up で
# C' は B7 と C の up になる形?
save_env の戻りは A' になるはず。A, B, C の size は -1、info は #f になる?

むむ

_Gauche:YAGHG:VM:フレームのヒープへのコピー_な文書に以下の記述あり。

envレジスタやコンティニュエーションフレームが指す環境フレームを、新しく作られたそれを指すように設定し直すのはsave_envを呼び出す次の環境の仕事である。

  • get_env
  • save_cont

リンクの関係が微妙、と言いつつ上記の文書を見つつソースを確認。get_env 手続きにて以下なナニ。

static ScmEnvFrame *get_env(ScmVM *vm)
{
    ScmEnvFrame *e;
    ScmContFrame *c;
    
    e = save_env(vm, vm->env);
    if (e != vm->env) {
        vm->env = e;
        for (c = vm->cont; IN_STACK_P((ScmObj*)c); c = c->prev) {
            if (FORWARDED_ENV_P(c->env)) {
                c->env = FORWARDED_ENV(c->env);
            }
        }
    }
    return e;
}

なるほど。別な構造体が指してる可能性があるから残してるのか。

あら?

なんかもの凄く何かを端折ってる気がします。ちゃんと最後までヤッときます。

        d = SCM_NEW2(ScmObj*, ENV_SIZE(esize) * sizeof(ScmObj));
        for (i=ENV_SIZE(esize), s = (ScmObj*)e - esize; i>0; i--) {
            *d++ = *s++;
        }

あら? s にセットされてるナニは一体?
って微妙な思い込みが御座いました。環境フレームは引数が push されて最後に ScmEnvFrame なナニが最後に積まれるのか (FINISH_ENV)。なので始点が

s = (ScmObj*)e - esize;

なんですな。どうもデータ構造をきちんとイメージできてないな。参考になったのは gauche/vm.h の以下のコメント。

/*
 * Environment frame
 *
 *   :        :
 *   +--------+
 *   | size=N |
 *   |  info  |
 *   |...up...|<--- ScmEnvFrame* envp
 *   |arg[N-1]|
 *   |arg[N-2]|
 *   :        :
 *   | arg[0] |
 *   +--------+
 *   :        :
 */

で、

        saved = (ScmEnvFrame*)(d - ENV_HDR_SIZE);

なナニで saved は ScmEnvFrame の先頭を指してるはず。d は ScmObj なのでナニ。あとはコード引用略で以下。

  • prev が NULL でなければ prev->up に saved をセット
    • 直前に saved にセットされた次 (up) を saved に
    • A' -> B' というリンクを張ってます
  • head が NULL だったら saved をセット (先頭の保存
  • next に e->up をセット
    • 次、の保存
  • e->up と prev に saved をセット
    • A -> A' なリンクを直前に saved にセットされたナニの保存
  • 属性の設定
  • 次の要素の設定

微妙ですが、メモ、という事でそろそろ限界ッス。