SPECIAL_CONST_P 実装

さて、SPECIAL_CONST_P の実装の話。

#define RB_SPECIAL_CONST_P(x) (RB_IMMEDIATE_P(x) || !RB_TEST(x))
#define SPECIAL_CONST_P(x) RB_SPECIAL_CONST_P(x)

この条件で、メモリへのポインタか、そうでないかを分けることができる、といっている。どうやるのか。

ポインタの場合、MRI では必ず word aliment するようにしている。つまり、64bit CPU では 8 byte alignment。つまり、8 の倍数。そうすると、下位 3 bit は 0 である。RB_IMMEDIATE_P(x) の実装は、まさに下位 3 bit が 0 かどうかのチェックをしているので、IMMEDIATE_P だった場合、ポインタではない。

次、RB_TEST(x) では何をしているかというと、x が 0 か 8 という値か(64bit CPU の場合)、というチェックになっている。下位 3 bit は 0 だが、この2値だけは、絶対に Ruby オブジェクトじゃない、という前提で動いている。

ということで、この二つの条件にあてはまれば、オブジェクトが割り当てられたポインタではなく、あてはまらなければポインタだ、というように判断できる。

ちなみに、このチェックは大量に行うことになるので、効率的だとありがたい。

int
sp_const_p(VALUE x)
{
    return RB_SPECIAL_CONST_P(x);
}

こういう関数にしてみると、

# gcc
   0:   40 f6 c7 07             test   $0x7,%dil
   4:   b8 01 00 00 00          mov    $0x1,%eax
   9:   75 0c                   jne    17 <sp_const_p+0x17>
   b:   31 c0                   xor    %eax,%eax
   d:   48 f7 c7 f7 ff ff ff    test   $0xfffffffffffffff7,%rdi
  14:   0f 94 c0                sete   %al
  17:   f3 c3                   repz retq
# clang
  90:   40 f6 c7 07             test   $0x7,%dil
  94:   0f 95 c0                setne  %al
  97:   48 f7 c7 f7 ff ff ff    test   $0xfffffffffffffff7,%rdi
  9e:   0f 94 c1                sete   %cl
  a1:   08 c1                   or     %al,%cl
  a3:   0f b6 c1                movzbl %cl,%eax
  a6:   c3                      retq

このような結果になる。もうちょっと効率よくなるようにできるといいですねえ。