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
このような結果になる。もうちょっと効率よくなるようにできるといいですねえ。