なぜか変なところでエラーが出る。どうにもそのエラーの原因が掴めない。そもそも、実行するごとに結果が違うし。ウワーン。

ちょっと変えたら動いてしまった。さっぱりわからん。俺が ruby の状態管理を追えてないだけなんだけれど。

まぁ、動いたからいいかぁ？（いい加減）

さて、作業としては、

あさってのデモを作る

AOT コンパイラ（ruby -> C）を作る

があるんだけど、今日一日で終わるだろうか。コンパイラは正直すぐ出来そうな気はするんだよな。もちろん、厳密なものは無理だけど（例外とか）。

1 bug 去って、また 1 bug

考えてたんだけど、やっぱりVM状態カウンタ（VM状態バージョンっていう言葉はやっぱり変ですね、反省）の比較は、インラインキャッシュでは要らないですねぇ。でも、まぁ現状の実装のほうが楽だから、そのままで行くか。

理由は、キャッシュするための記憶域のセットを管理できるから。多分。でも、その管理、結構面倒くさいな。とくに、ファイナライザ、というか命令列が GC されるとき。

でも、管理はできるので、やっぱりそのようにする必要はあるな。

つまり、先日のはこうなる。

// 排他制御必要なし if(klass == mc->mc_klass){ mn = mc->mc_method; } else{ mn = rb_method_node(klass, id); // メソッド実体を検索 mc->mc_klass = klass; mc->mc_method = mn; } // 排他制御必要あり if(mc){ if(klass == mc->mc_klass){ mn = mc->mc_method; } else{ mn = rb_method_node(klass, id); if(mc->mc_rewrite_count++ > threshold){ // これ以上インラインメソッドキャッシュを利用しないようにする cancel_inline_method_cache(mc); SET_METHOD_CACHE_ENTRY_TO_OPERAND(GET_PC(), 0); } else{ cancel_inline_method_cache(mc); mc = NEW_METHOD_CACHE_ENTRY(); register_inline_method_cache(mc); mc->mc_klass = klass; mc->mc_method = mn; SET_METHOD_CACHE_ENTRY_TO_OPERAND(GET_PC(), mc); } } } else{ // もうメソッドキャッシュはしない mn = rb_method_node(klass, id); }

なんか、ほんとにこれでいいのかイマイチ疑問だが・・・（この処理の途中で再定義があったとき、正しく動くんだろうか？）

新しく登録するときに、ロックが必要な気がするな。

else{ cancel_inline_method_cache(mc); mc = register_inline_method_cache(klass, mn); SET_METHOD_CACHE_ENTRY_TO_OPERAND(GET_PC(), mc); }

こうするのがいいだろうか。

よろしくないなぁ。cancel したエントリを利用する可能性がある。

else{ cancel_inline_method_cache(mc); register_inline_method_cache(klass, mn, GET_PC()); }

ここまで必要ですねえ。

で、register_inline_method_cache で、適切なロックが必要。

って、これも2重に cancel して、ゴミが残る可能性があるのか。

else{ cancel_and_register_inline_method_cache(mc, klass, mn, GET_PC()); }

結局、この部分はアトミックに行なわないといけないってことで。

デスクトップでcygwin用に ruby/sdl をビルドして，ノートに持っていったら起動しない．dlopen のエラーと出る．問題はいろいろ思いつくけど，なんでだろう．cygwin が古いだけ，というのもありそう．

発表前なのに，プレゼンの準備をしないで AOT compiler を作り始める．ダメダメだ．

で，リテラルを C に落とすのがとても面倒そうだ．

i=0 while i<100000000 i+=1 end #=> ruby 81.203000 0.031000 81.234000 ( 81.446000) yarv 6.860000 0.047000 6.907000 ( 6.902000) aotc 0.796000 0.016000 0.812000 ( 0.843000)

というわけで，AOT compiler を作ってみた．2時間くらい．

100倍速くなる．まぁ，かなり限定したシチュエーションですが．もちろん，Ruby 全部が 100倍早くなるわけは無い．

でも，目算どおりで，良かった．

メソッド呼び出しを入れると，10倍くらい遅くなる予定．10倍で済むだろうか．

ちなみに，メソッド呼び出しはまだ実装していない．例外なども，なんにも考えてない．

せめて，tak くらいはできるようにしておかないと駄目だろうか．

うーん，きちんと作れば速いものができるような気がするな．とりあえず，aot compiled method を特別に扱う（rb_call0 みたいなところで扱う）ようにして，ごにょごにょと・・・．

NODE_CFUNC みたいなのは，かなり無駄が多かったり多くなかったりするから．

メソッドの起動がどれだけ速かったり遅かったりするかが勝負だなぁ．

ちなみにコンパイラは 100行くらいで ruby でガーーっと書いたので，ダメダメ．グローバル変数とか使ってるし．コミットしたくもないけど，どうしようかなあ．

ちなみに，上記 Ruby プログラムに対して，こんなコードを吐く．

/* * == disasm: <ISeq:main@../aotctest.rb>=================================== * local scope table (size: 5, argc: 0) * [ 5] file [ 4] parsed [ 3] idx [ 2] i * 0000 putobject_opopt_INT2FIX_OP_0_CP__SC_xx_ax ( 2) * 0001 setlocal_opopt_2_SC_ax_xx * 0002 getlocal_opopt_2_SC_xx_ax ( 3) * 0003 putobject_SC_ax_ab100000000 * 0005 opt_lt_SC_ab_ax * 0006 unless_SC_ax_xx 14 * 0008 getlocal_opopt_2_SC_xx_ax ( 4) * 0009 putobject_opopt_INT2FIX_OP_1_CP__SC_ax_ab * 0010 opt_plus_SC_ab_ax * 0011 setlocal_opopt_2_SC_ax_xx * 0012 jump_SC_xx_xx 2 ( 3) * 0014 putnil_SC_xx_ax * 0015 end_SC_ax_ax 6 */ INSN_LABEL_0: { INSN_ENTRY(putobject_opopt_INT2FIX_OP_0_CP__SC_xx_ax){ /* prepare stack status */ { /* declare stack push val */ /* declare and initialize default opes */ #define val INT2FIX(0) /* declare and get from iseq */ /* declare and pop from stack */ /* for debug */ DEBUG_ENTER_INSN("putobject_opopt_INT2FIX_OP_0_CP__SC_xx_ax"); USAGE_ANALYSIS_INSN(BIN(putobject_opopt_INT2FIX_OP_0_CP__SC_xx_ax)); /* management */ ADD_PC(1+0); #define CURRENT_INSN_putobject_opopt_INT2FIX_OP_0_CP__SC_xx_ax 1 #define INSN_IS_SC() 1 #define INSN_LABEL(lab) LABEL_putobject_opopt_INT2FIX_OP_0_CP__SC_xx_ax_##lab #define LABEL_IS_SC(lab) LABEL_##lab##_##f { /* */ /* push stack val */ SCREG(a) = val; #undef val #undef CURRENT_INSN_putobject_opopt_INT2FIX_OP_0_CP__SC_xx_ax #undef INSN_IS_SC #undef INSN_LABEL #undef LABEL_IS_SC END_INSN(); }} } } INSN_LABEL_1: { INSN_ENTRY(setlocal_opopt_2_SC_ax_xx){ /* prepare stack status */ { /* declare stack push val */ /* declare and initialize default opes */ #define idx 2 /* declare and get from iseq */ /* declare and pop from stack */ VALUE val = SCREG(a); /* for debug */ DEBUG_ENTER_INSN("setlocal_opopt_2_SC_ax_xx"); USAGE_ANALYSIS_INSN(BIN(setlocal_opopt_2_SC_ax_xx)); /* management */ ADD_PC(1+0); #define CURRENT_INSN_setlocal_opopt_2_SC_ax_xx 1 #define INSN_IS_SC() 1 #define INSN_LABEL(lab) LABEL_setlocal_opopt_2_SC_ax_xx_##lab #define LABEL_IS_SC(lab) LABEL_##lab##_##f { (*(GET_LFP() - idx)) = val; /* push stack val */ #undef idx #undef CURRENT_INSN_setlocal_opopt_2_SC_ax_xx #undef INSN_IS_SC #undef INSN_LABEL #undef LABEL_IS_SC END_INSN(); }} } } INSN_LABEL_2: { INSN_ENTRY(getlocal_opopt_2_SC_xx_ax){ /* prepare stack status */ { /* declare stack push val */ VALUE val; /* declare and initialize default opes */ #define idx 2 /* declare and get from iseq */ /* declare and pop from stack */ /* for debug */ DEBUG_ENTER_INSN("getlocal_opopt_2_SC_xx_ax"); USAGE_ANALYSIS_INSN(BIN(getlocal_opopt_2_SC_xx_ax)); /* management */ ADD_PC(1+0); #define CURRENT_INSN_getlocal_opopt_2_SC_xx_ax 1 #define INSN_IS_SC() 1 #define INSN_LABEL(lab) LABEL_getlocal_opopt_2_SC_xx_ax_##lab #define LABEL_IS_SC(lab) LABEL_##lab##_##f { val = *(GET_LFP() - idx); /* push stack val */ SCREG(a) = val; #undef idx #undef CURRENT_INSN_getlocal_opopt_2_SC_xx_ax #undef INSN_IS_SC #undef INSN_LABEL #undef LABEL_IS_SC END_INSN(); }} } } INSN_LABEL_3: { VALUE aot_insn_operands[] = { INT2FIX(100000000)}; INSN_ENTRY(putobject_SC_ax_ab){ /* prepare stack status */ { /* declare stack push val */ /* declare and initialize default opes */ /* declare and get from iseq */ VALUE val = (VALUE)GET_OPERAND(1); /* declare and pop from stack */ /* for debug */ DEBUG_ENTER_INSN("putobject_SC_ax_ab"); USAGE_ANALYSIS_INSN(BIN(putobject_SC_ax_ab)); /* management */ ADD_PC(1+1); #define CURRENT_INSN_putobject_SC_ax_ab 1 #define INSN_IS_SC() 1 #define INSN_LABEL(lab) LABEL_putobject_SC_ax_ab_##lab #define LABEL_IS_SC(lab) LABEL_##lab##_##f USAGE_ANALYSIS_OPERAND(BIN(putobject_SC_ax_ab), 0, val); { /* */ /* push stack val */ SCREG(b) = val; #undef CURRENT_INSN_putobject_SC_ax_ab #undef INSN_IS_SC #undef INSN_LABEL #undef LABEL_IS_SC END_INSN(); }} } } INSN_LABEL_5: { INSN_ENTRY(opt_lt_SC_ab_ax){ /* prepare stack status */ { /* declare stack push val */ VALUE val; /* declare and initialize default opes */ /* declare and get from iseq */ /* declare and pop from stack */ VALUE recv = SCREG(a); VALUE obj = SCREG(b); /* for debug */ DEBUG_ENTER_INSN("opt_lt_SC_ab_ax"); USAGE_ANALYSIS_INSN(BIN(opt_lt_SC_ab_ax)); /* management */ ADD_PC(1+0); #define CURRENT_INSN_opt_lt_SC_ab_ax 1 #define INSN_IS_SC() 1 #define INSN_LABEL(lab) LABEL_opt_lt_SC_ab_ax_##lab #define LABEL_IS_SC(lab) LABEL_##lab##_##f { if(FIXNUM_2_P(recv, obj) && BASIC_OP_UNREDEFINED(FIXNUM_LT)){ long a = FIX2LONG(recv), b = FIX2LONG(obj); if (a < b){ val = Qtrue; } else{ val = Qfalse; } } else{ /* other */ #ifdef YARV_AOT_COMPILED rb_funcall(recv, idLT, 1, obj); #else PUSH(recv); PUSH(obj); tmp_id = idLT; goto LABEL_IS_SC(start_init_in_send_for_opt_1); #endif } /* push stack val */ SCREG(a) = val; #undef CURRENT_INSN_opt_lt_SC_ab_ax #undef INSN_IS_SC #undef INSN_LABEL #undef LABEL_IS_SC END_INSN(); }} } } INSN_LABEL_6: { VALUE aot_insn_operands[] = { 0}; INSN_ENTRY(unless_SC_ax_xx){ /* prepare stack status */ { /* declare stack push val */ /* declare and initialize default opes */ /* declare and get from iseq */ #define dst INSN_LABEL_14 /* declare and pop from stack */ VALUE val = SCREG(a); /* for debug */ DEBUG_ENTER_INSN("unless_SC_ax_xx"); USAGE_ANALYSIS_INSN(BIN(unless_SC_ax_xx)); /* management */ ADD_PC(1+1); #define CURRENT_INSN_unless_SC_ax_xx 1 #define INSN_IS_SC() 1 #define INSN_LABEL(lab) LABEL_unless_SC_ax_xx_##lab #define LABEL_IS_SC(lab) LABEL_##lab##_##f USAGE_ANALYSIS_OPERAND(BIN(unless_SC_ax_xx), 0, dst); { if(!RTEST(val)){ JUMP(dst); } /* push stack val */ #undef CURRENT_INSN_unless_SC_ax_xx #undef INSN_IS_SC #undef INSN_LABEL #undef LABEL_IS_SC END_INSN(); }} } } INSN_LABEL_8: { INSN_ENTRY(getlocal_opopt_2_SC_xx_ax){ /* prepare stack status */ { /* declare stack push val */ VALUE val; /* declare and initialize default opes */ #define idx 2 /* declare and get from iseq */ /* declare and pop from stack */ /* for debug */ DEBUG_ENTER_INSN("getlocal_opopt_2_SC_xx_ax"); USAGE_ANALYSIS_INSN(BIN(getlocal_opopt_2_SC_xx_ax)); /* management */ ADD_PC(1+0); #define CURRENT_INSN_getlocal_opopt_2_SC_xx_ax 1 #define INSN_IS_SC() 1 #define INSN_LABEL(lab) LABEL_getlocal_opopt_2_SC_xx_ax_##lab #define LABEL_IS_SC(lab) LABEL_##lab##_##f { val = *(GET_LFP() - idx); /* push stack val */ SCREG(a) = val; #undef idx #undef CURRENT_INSN_getlocal_opopt_2_SC_xx_ax #undef INSN_IS_SC #undef INSN_LABEL #undef LABEL_IS_SC END_INSN(); }} } } INSN_LABEL_9: { INSN_ENTRY(putobject_opopt_INT2FIX_OP_1_CP__SC_ax_ab){ /* prepare stack status */ { /* declare stack push val */ /* declare and initialize default opes */ #define val INT2FIX(1) /* declare and get from iseq */ /* declare and pop from stack */ /* for debug */ DEBUG_ENTER_INSN("putobject_opopt_INT2FIX_OP_1_CP__SC_ax_ab"); USAGE_ANALYSIS_INSN(BIN(putobject_opopt_INT2FIX_OP_1_CP__SC_ax_ab)); /* management */ ADD_PC(1+0); #define CURRENT_INSN_putobject_opopt_INT2FIX_OP_1_CP__SC_ax_ab 1 #define INSN_IS_SC() 1 #define INSN_LABEL(lab) LABEL_putobject_opopt_INT2FIX_OP_1_CP__SC_ax_ab_##lab #define LABEL_IS_SC(lab) LABEL_##lab##_##f { /* */ /* push stack val */ SCREG(b) = val; #undef val #undef CURRENT_INSN_putobject_opopt_INT2FIX_OP_1_CP__SC_ax_ab #undef INSN_IS_SC #undef INSN_LABEL #undef LABEL_IS_SC END_INSN(); }} } } INSN_LABEL_10: { INSN_ENTRY(opt_plus_SC_ab_ax){ /* prepare stack status */ { /* declare stack push val */ VALUE val; /* declare and initialize default opes */ /* declare and get from iseq */ /* declare and pop from stack */ VALUE recv = SCREG(a); VALUE obj = SCREG(b); /* for debug */ DEBUG_ENTER_INSN("opt_plus_SC_ab_ax"); USAGE_ANALYSIS_INSN(BIN(opt_plus_SC_ab_ax)); /* management */ ADD_PC(1+0); #define CURRENT_INSN_opt_plus_SC_ab_ax 1 #define INSN_IS_SC() 1 #define INSN_LABEL(lab) LABEL_opt_plus_SC_ab_ax_##lab #define LABEL_IS_SC(lab) LABEL_##lab##_##f { if(FIXNUM_2_P(recv, obj) && BASIC_OP_UNREDEFINED(FIXNUM_PLUS)){ /* fixnum + fixnum */ val = (recv + (obj & (~1))); if((~(recv^obj)&(recv^val))&0x80000000){ val = rb_big_plus(rb_int2big(INT2FIX(recv)), rb_int2big(INT2FIX(obj))); } } else{ #ifdef YARV_AOT_COMPILED rb_funcall(recv, idPLUS, 1, obj); #else PUSH(recv); PUSH(obj); tmp_id = idPLUS; goto LABEL_IS_SC(start_init_in_send_for_opt_1); #endif } /* push stack val */ SCREG(a) = val; #undef CURRENT_INSN_opt_plus_SC_ab_ax #undef INSN_IS_SC #undef INSN_LABEL #undef LABEL_IS_SC END_INSN(); }} } } INSN_LABEL_11: { INSN_ENTRY(setlocal_opopt_2_SC_ax_xx){ /* prepare stack status */ { /* declare stack push val */ /* declare and initialize default opes */ #define idx 2 /* declare and get from iseq */ /* declare and pop from stack */ VALUE val = SCREG(a); /* for debug */ DEBUG_ENTER_INSN("setlocal_opopt_2_SC_ax_xx"); USAGE_ANALYSIS_INSN(BIN(setlocal_opopt_2_SC_ax_xx)); /* management */ ADD_PC(1+0); #define CURRENT_INSN_setlocal_opopt_2_SC_ax_xx 1 #define INSN_IS_SC() 1 #define INSN_LABEL(lab) LABEL_setlocal_opopt_2_SC_ax_xx_##lab #define LABEL_IS_SC(lab) LABEL_##lab##_##f { (*(GET_LFP() - idx)) = val; /* push stack val */ #undef idx #undef CURRENT_INSN_setlocal_opopt_2_SC_ax_xx #undef INSN_IS_SC #undef INSN_LABEL #undef LABEL_IS_SC END_INSN(); }} } } INSN_LABEL_12: { VALUE aot_insn_operands[] = { 0}; INSN_ENTRY(jump_SC_xx_xx){ /* prepare stack status */ { /* declare stack push val */ /* declare and initialize default opes */ /* declare and get from iseq */ #define dst INSN_LABEL_2 /* declare and pop from stack */ /* for debug */ DEBUG_ENTER_INSN("jump_SC_xx_xx"); USAGE_ANALYSIS_INSN(BIN(jump_SC_xx_xx)); /* management */ ADD_PC(1+1); #define CURRENT_INSN_jump_SC_xx_xx 1 #define INSN_IS_SC() 1 #define INSN_LABEL(lab) LABEL_jump_SC_xx_xx_##lab #define LABEL_IS_SC(lab) LABEL_##lab##_##f USAGE_ANALYSIS_OPERAND(BIN(jump_SC_xx_xx), 0, dst); { JUMP(dst); /* push stack val */ #undef CURRENT_INSN_jump_SC_xx_xx #undef INSN_IS_SC #undef INSN_LABEL #undef LABEL_IS_SC END_INSN(); }} } } INSN_LABEL_14: { INSN_ENTRY(putnil_SC_xx_ax){ /* prepare stack status */ { /* declare stack push val */ VALUE val; /* declare and initialize default opes */ /* declare and get from iseq */ /* declare and pop from stack */ /* for debug */ DEBUG_ENTER_INSN("putnil_SC_xx_ax"); USAGE_ANALYSIS_INSN(BIN(putnil_SC_xx_ax)); /* management */ ADD_PC(1+0); #define CURRENT_INSN_putnil_SC_xx_ax 1 #define INSN_IS_SC() 1 #define INSN_LABEL(lab) LABEL_putnil_SC_xx_ax_##lab #define LABEL_IS_SC(lab) LABEL_##lab##_##f { val = Qnil; /* push stack val */ SCREG(a) = val; #undef CURRENT_INSN_putnil_SC_xx_ax #undef INSN_IS_SC #undef INSN_LABEL #undef LABEL_IS_SC END_INSN(); }} } } INSN_LABEL_15: { VALUE aot_insn_operands[] = { INT2FIX(6)}; INSN_ENTRY(end_SC_ax_ax){ /* prepare stack status */ { /* declare stack push val */ /* declare and initialize default opes */ /* declare and get from iseq */ ulong idx = (ulong)GET_OPERAND(1); /* declare and pop from stack */ VALUE val = SCREG(a); /* for debug */ DEBUG_ENTER_INSN("end_SC_ax_ax"); USAGE_ANALYSIS_INSN(BIN(end_SC_ax_ax)); /* management */ ADD_PC(1+1); #define CURRENT_INSN_end_SC_ax_ax 1 #define INSN_IS_SC() 1 #define INSN_LABEL(lab) LABEL_end_SC_ax_ax_##lab #define LABEL_IS_SC(lab) LABEL_##lab##_##f USAGE_ANALYSIS_OPERAND(BIN(end_SC_ax_ax), 0, idx); { #ifdef YARV_AOT_COMPILED throwed = val; #else struct continuation_frame *cf; cf = GET_CONTINUATION_FRAME_PTR(GET_CFP()); CHECK_FRAME_MAGIC(cf->magic); // STACKDUMP(); /* clear environment */ CLEAR_ENV(GET_DFP()); SET_SP ((GET_CFP() - idx)); SET_PC (cf->pc ); SET_LFP(cf->lfp); SET_DFP(cf->dfp); SET_CFP(cf->cfp); if(GET_PC() == 0){ throwed = val; goto finish; } #endif /* push stack val */ SCREG(a) = val; #undef CURRENT_INSN_end_SC_ax_ax #undef INSN_IS_SC #undef INSN_LABEL #undef LABEL_IS_SC END_INSN(); }} } }

コメントとか自動生成するの，やめたほうがいいかなぁ．