[ PHPに独自のオペレータを追加する

一歩進んだ。Y!のPHPエンジニア問題の $users ||= ‘john’;
やっぱりgdb便利ですねー。

zend_exedute.c
#define _CONST_CODE  0
#define _TMP_CODE    1
#define _VAR_CODE    2
#define _UNUSED_CODE 3
#define _CV_CODE     4
zend_vm_executer.h
void zend_init_opcodes_handlers()
{
    static const opcode_handler_t labels[] = {
        ZEND_NOP_SPEC_HANDLER,
        ZEND_NOP_SPEC_HANDLER,
        :
        :
    };
    zend_opcode_handlers = (opcode_handler_t*)labels;
}

static opcode_handler_t zend_vm_get_opcode_handler(zend_uchar opcode, zend_op* op)
{
    static const int zend_vm_decode[] = {
        _UNUSED_CODE, /* 0              */
        _CONST_CODE,  /* 1 = IS_CONST   */
        _TMP_CODE,    /* 2 = IS_TMP_VAR */
        _UNUSED_CODE, /* 3              */
        _VAR_CODE,    /* 4 = IS_VAR     */
        _UNUSED_CODE, /* 5              */
        _UNUSED_CODE, /* 6              */
        _UNUSED_CODE, /* 7              */
        _UNUSED_CODE, /* 8 = IS_UNUSED  */
        _UNUSED_CODE, /* 9              */
        _UNUSED_CODE, /* 10             */
        _UNUSED_CODE, /* 11             */
        _UNUSED_CODE, /* 12             */
        _UNUSED_CODE, /* 13             */
        _UNUSED_CODE, /* 14             */
        _UNUSED_CODE, /* 15             */
        _CV_CODE      /* 16 = IS_CV     */
        };
       return zend_opcode_handlers[opcode * 25 + zend_vm_decode[op->op1.op_type] * 5 + \                                                      
                      zend_vm_decode[op->op2.op_type]];
}

昨日はこの辺りをちゃんと読んでなかった。
opcode_handler_t labels[] にオペーレータの動作を登録するみたいですが、
zend_opcode_handlers[opcode * 25 + zend_vm_decode[op->op1.op_type] * 5 + zend_vm_decode[op->op2.op_type] ];
という計算式があったのね。昨日はここの計算式と合ってなくてハンドラが変なアドレスを指してしまいSegmentation faultが出てた。

$a + 1000;

例えば上記のようなコードは、*1

1 * 25 + zend_vm_decode[16] * 5 + zend_vm_decode[1] // = 45

となり、labels[45]に登録されているZEND_ADD_SPEC_CV_CONST_HANDLERが呼ばれる。

とりあえず自分で定義した「||=」のopcodeを元にlabels[]に関数を追加する。
pushじゃないけど、仮として「+=」 と同じような機能を追加して動作確認。

 $  php -r '$a = 1000; $a ||= 1000; print $a ."\n";'
2000

ktkr!実に気持ちわるいです!

*1:+のopcodeは1, =は38とか