概要


引数がブロックならば、ブロックを旧世代に移動する。

引数

  • v: OCamlの値
  • p: vへのポインタ

戻り値


なし

実装



/* Note that the tests on the tag depend on the fact that Infix_tag,
   Forward_tag, and No_scan_tag are contiguous. */

タグに関する検査は、Infix_tagForward_tag, No_scan_tagが連続しているという事実に依存する。


void caml_oldify_one (value v, value *p)
{
  value result;
  header_t hd;
  mlsize_t sz, i;
  tag_t tag;

 tail_call:
  if (Is_block (v) && Is_young (v)){

新世代のブロックの場合

    Assert (Hp_val (v) >= caml_young_ptr);
    hd = Hd_val (v);

    if (hd == 0){         /* If already forwarded */
      *p = Field (v, 0);  /*  then forward pointer is first field. */

ヘッダが0の場合、最初のフィールドに移動先のアドレスが書き込まれている。

    }else{
      tag = Tag_hd (hd);
      if (tag < Infix_tag){

        value field0;
        sz = Wosize_hd (hd);

        result = caml_alloc_shr (sz, tag);

新たにメモリを確保し、

        *p = result;
        field0 = Field (v, 0);
        Hd_val (v) = 0;            /* Set forward flag */
        Field (v, 0) = result;     /*  and forward pointer. */

移動先のアドレスを書き込む。

        if (sz > 1){
          Field (result, 0) = field0;
          Field (result, 1) = oldify_todo_list;    /* Add this block */
          oldify_todo_list = v;                    /*  to the "to do" list. */

オブジェクトが複数のフィールドから構成される場合、オブジェクト(の移動前のポインタ)を、oldify_todo_listに追加する。リストの次の要素は、リストにある移動前のポインタ->移動後のポインタ->2番目のフィールドの順で参照できる。子のリストは、caml_oldify_mopupで参照される。

        }else{
          Assert (sz == 1);
          p = &Field (result, 0);
          v = field0;
          goto tail_call;
        }
      }else if (tag >= No_scan_tag){
        sz = Wosize_hd (hd);
        result = caml_alloc_shr (sz, tag);
        for (i = 0; i < sz; i++) Field (result, i) = Field (v, i);
        Hd_val (v) = 0;            /* Set forward flag */
        Field (v, 0) = result;     /*  and forward pointer. */
        *p = result;
      }else if (tag == Infix_tag){
        mlsize_t offset = Infix_offset_hd (hd);

        caml_oldify_one (v - offset, p);   /* Cannot recurse deeper than 1. */
        *p += offset;
      }else{
        value f = Forward_val (v);

        tag_t ft = 0;
        int vv = 1;

        Assert (tag == Forward_tag);
        if (Is_block (f)){
          vv = Is_in_value_area(f);

          if (vv) {
            ft = Tag_val (Hd_val (f) == 0 ? Field (f, 0) : f);

          }
        }
        if (!vv || ft == Forward_tag || ft == Lazy_tag || ft == Double_tag){

          /* Do not short-circuit the pointer.  Copy as a normal block. */
          Assert (Wosize_hd (hd) == 1);
          result = caml_alloc_shr (1, Forward_tag);
          *p = result;
          Hd_val (v) = 0;             /* Set (GC) forward flag */
          Field (v, 0) = result;      /*  and forward pointer. */
          p = &Field (result, 0);
          v = f;
          goto tail_call;
        }else{
          v = f;                        /* Follow the forwarding */
          goto tail_call;               /*  then oldify. */
        }
      }
    }
  }else{
    *p = v;
  }
}
タグ

コメントをかく


「http://」を含む投稿は禁止されています。

利用規約をご確認のうえご記入下さい

Wiki内検索

管理人/副管理人のみ編集できます