iv の格納ら辺まとめ

インスタンス変数は,先頭に"@"(アットマーク)が付いている
インスタンススコープの変数.
例えば,こんな感じ.

irb(main):001:0> a = 1
=> 1
irb(main):002:0> class Fixnum
irb(main):003:1> def hoge; @hoge; end
irb(main):004:1> def hoge=(hoge); @hoge = hoge; end
irb(main):005:1> end
=> nil
irb(main):006:0> a.hoge
=> nil
irb(main):007:0> a.hoge = "fuga"
=> "fuga"
irb(main):008:0> a.hoge
=> "fuga"


準備

関数 rb_obj_class(obj) ROBJECT(obj)->basic->klass
マクロ ROBJECT_IV_INDEX_TBL(obj) ROBJECT(obj)->iv_index_tbl EMBED の場合は,RCLASS_IV_INDEX_TBL(rb_obj_class(obj))
マクロ RCLASS_IV_INDEX_TBL(klass) RCLASS(klass)->iv_index_tbl
関数 st_lookup(st_table, key, *value) key のindex をiv_index_tbl から探す
マクロ ROJBECT_NUMIV(obj) ROBJECT(obj)->as.heap.numiv 今入るIV の最大値を返す
マクロ ROBJECT_IVPTR(obj) ROBJECT(obj)->as.heap.ivptr IV のテーブル
ROBJECT_EMBED RObject.ary に埋め込むというフラグ
ROBJECT_EMBED_LEN_MAX RObject.ary に入れる最大値
変数 generic_iv_tbl obj -> tbl(symbol と値のテーブル)を保持するテーブル
マクロ RCLASS_IV_TBL RCLASS(c)->ptr->iv_tbl

variable.c:1005:rb_ivar_set() を見るとわかるらしい.
最初のif は例外処理なので飛ばして,
switch で,TYPE(obj) にて分岐してる.

  • 1016:T_OBJECT
  • 1066-1067:T_CLASS or T_MODULE
  • 1071:default

(VALUE埋め込みオブジェクトでない)オブジェクトの場合

  • iv_index_tbl (iv のsymbol と位置を関係付けるテーブル)を取得する
    • 無かったらclass 上に作る
  • iv_index_tbl の中に今回のid がsymbol としてあるかどうか探す
    • 無かったら追加
  • index(保持する値の位置) が決定する
  • ivar_extended(新しいsymbol) かどうかのフラグ
  • len(今保持しているIV の最大値)を取得
  • 保持する位置がlen 以上ならば
    • ptr (値を保持する配列) を取得
    • len <= index < ROBJECT_EMBED_LEN_MAX ならば埋め込みにする*1
    • new_size((index+1)*1.25) と num_entries(現在のサイズ) からptr を決定する
  • 値を保持する

クラス(モジュール)の場合

  • RCLASS_IV_TBL(obj) を見て,値を保持する

その他

  • generic_ivar_set(obj, id, val) する

もうちょっと言うと,

  • *iv_tbl は,key(symbol), value で値を保持する(RClass とか その他の場合)
  • RObject は,RObject.as.ary or RObject.as.heap の形態がある(union)
    • RBASIC(o)->flags & ROBJECT_EMBD の場合
      • 値は ROBJECT(o)->as.ary
      • key(symbol) => index のテーブルは,RCLASS_IV_INDEX_TBL(rb_obj_class(o)) -> これは,大体 RBASIC(o)->klass->iv_index_tbl
    • そうでなければ
      • 値は,ROBJECT(o)->as.heap.ivptr
      • key(symbol) => index のテーブルは,ROBJECT(o)->as.heap.iv_index_tbl
  • ROBJECT_EMBD になる境目は,ROBJECT_EMBED_LEN_MAX 個(=3)
egrep -n -B1 -A71 \^rb_ivar_set *.c
variable.c-1004-VALUE
variable.c:1005:rb_ivar_set(VALUE obj, ID id, VALUE val)
variable.c-1006-{
variable.c-1007-    struct st_table *iv_index_tbl;
variable.c-1008-    st_data_t index;
variable.c-1009-    long i, len;
variable.c-1010-    int ivar_extended;
variable.c-1011-
variable.c-1012-    if (!OBJ_UNTRUSTED(obj) && rb_safe_level() >= 4)
variable.c-1013-	rb_raise(rb_eSecurityError, "Insecure: can't modify instance variable");
variable.c-1014-    if (OBJ_FROZEN(obj)) rb_error_frozen("object");
variable.c-1015-    switch (TYPE(obj)) {
variable.c-1016-      case T_OBJECT:
variable.c-1017-        iv_index_tbl = ROBJECT_IV_INDEX_TBL(obj);
variable.c-1018-        if (!iv_index_tbl) {
variable.c-1019-            VALUE klass = rb_obj_class(obj);
variable.c-1020-            iv_index_tbl = RCLASS_IV_INDEX_TBL(klass);
variable.c-1021-            if (!iv_index_tbl) {
variable.c-1022-                iv_index_tbl = RCLASS_IV_INDEX_TBL(klass) = st_init_numtable();
variable.c-1023-            }
variable.c-1024-        }
variable.c-1025-        ivar_extended = 0;
variable.c-1026-        if (!st_lookup(iv_index_tbl, id, &index)) {
variable.c-1027-            index = iv_index_tbl->num_entries;
variable.c-1028-            st_add_direct(iv_index_tbl, id, index);
variable.c-1029-            ivar_extended = 1;
variable.c-1030-        }
variable.c-1031-        len = ROBJECT_NUMIV(obj);
variable.c-1032-        if (len <= index) {
variable.c-1033-            VALUE *ptr = ROBJECT_IVPTR(obj);
variable.c-1034-            if (index < ROBJECT_EMBED_LEN_MAX) {
variable.c-1035-                RBASIC(obj)->flags |= ROBJECT_EMBED;
variable.c-1036-                ptr = ROBJECT(obj)->as.ary;
variable.c-1037-                for (i = 0; i < ROBJECT_EMBED_LEN_MAX; i++) {
variable.c-1038-                    ptr[i] = Qundef;
variable.c-1039-                }
variable.c-1040-            }
variable.c-1041-            else {
variable.c-1042-                VALUE *newptr;
variable.c-1043-                long newsize = (index+1) + (index+1)/4; /* (index+1)*1.25 */
variable.c-1044-                if (!ivar_extended &&
variable.c-1045-                    iv_index_tbl->num_entries < newsize) {
variable.c-1046-                    newsize = iv_index_tbl->num_entries;
variable.c-1047-                }
variable.c-1048-                if (RBASIC(obj)->flags & ROBJECT_EMBED) {
variable.c-1049-                    newptr = ALLOC_N(VALUE, newsize);
variable.c-1050-                    MEMCPY(newptr, ptr, VALUE, len);
variable.c-1051-                    RBASIC(obj)->flags &= ~ROBJECT_EMBED;
variable.c-1052-                    ROBJECT(obj)->as.heap.ivptr = newptr;
variable.c-1053-                }
variable.c-1054-                else {
variable.c-1055-                    REALLOC_N(ROBJECT(obj)->as.heap.ivptr, VALUE, newsize);
variable.c-1056-                    newptr = ROBJECT(obj)->as.heap.ivptr;
variable.c-1057-                }
variable.c-1058-                for (; len < newsize; len++)
variable.c-1059-                    newptr[len] = Qundef;
variable.c-1060-                ROBJECT(obj)->as.heap.numiv = newsize;
variable.c-1061-                ROBJECT(obj)->as.heap.iv_index_tbl = iv_index_tbl;
variable.c-1062-            }
variable.c-1063-        }
variable.c-1064-        ROBJECT_IVPTR(obj)[index] = val;
variable.c-1065-	break;
variable.c-1066-      case T_CLASS:
variable.c-1067-      case T_MODULE:
variable.c-1068-	if (!RCLASS_IV_TBL(obj)) RCLASS_IV_TBL(obj) = st_init_numtable();
variable.c-1069-	st_insert(RCLASS_IV_TBL(obj), id, val);
variable.c-1070-        break;
variable.c-1071-      default:
variable.c-1072-	generic_ivar_set(obj, id, val);
variable.c-1073-	break;
variable.c-1074-    }
variable.c-1075-    return val;
variable.c-1076-}

*1:これは,埋め込みでなくなるときにしか起きない