オブジェクトID
先日の日記で、Fixnum のオブジェクトのオブジェクトIDと String のオブジェクトのオブジェクトIDを調べた。そのとき気になったことがあったので、少し調べてみた。気になったことというのは、Fixnum と String のオブジェクトIDがあまりにも違いすぎる、ということ。そのときの値は、Fixnum が 3 で String が 84070 だった。
理由は Rubyソースコード完全解説 第2章 オブジェクトで発見。基本はオブジェクトの実態へのポインタを VALUE 型の変数に入れておくのだが、Fixnum の場合は VALUE 型の変数に入っているのはポインタではなく、実際の値が入っている。で、オブジェクトIDはこのVALUEの値を表示しているみたい。
オブジェクトIDをどのようにして求めているかというと、rb_obj_id() という関数を使っていて、その中身はこうなっていた。
VALUE rb_obj_id(VALUE obj) { /* 中略 */ if (TYPE(obj) == T_SYMBOL) { return (SYM2ID(obj) * sizeof(RVALUE) + (4 << 2)) | FIXNUM_FLAG; } if (SPECIAL_CONST_P(obj)) { return LONG2NUM((long)obj); } return (VALUE)((long)obj|FIXNUM_FLAG); } (gc.c)
シンボルの場合と、特別な値(nil, true, false, Fixnum)の場合と、それ以外の場合の3通りあるようだ。String のオブジェクトはそれ以外の場合になる。ん...それ以外の場合は obj と FIXNUM_FLAG を OR 演算してる。FIXNUM_FLAG は 1 だから OR したら LSB は必ず 1 になるよね。でも、実際に表示させてみたら 84070 と表示されたぞ。〜見るところ間違ったかな。rb_obj_id() 内のコメントを見てもよくわからん。