From: wanabe Date: 2007-03-13T14:36:16+09:00 Subject: [ruby-dev:30551] rb_rescue2 with vm はじめまして、ワナベと申します。 1.9 の rb_rescue2 を読んでいて xxx_TAG 系統の連続で読みにくかったので 実験的に VM を使った形にしてみました。 # あくまで実験なのでバックトレース等は考慮していません。 もともとの動機の、moriq さんの日記にあった Zlib::GzipReader の動作不良は ( http://moriq.tdiary.net/20070309.html ) 手元で確認した限りでは解消されています。 1.9 の方向性としてはこういうのはありなんでしょうか。 速度・メモリのコストを考えると現状のほうがよさそうですが、 保守の面からは VM を多用したほうが処理も分散せず、個人的には好きです。 Index: compile.c =================================================================== --- compile.c (revision 12030) +++ compile.c (working copy) @@ -3679,6 +3679,7 @@ VALUE argc; VALUE flag = 0; VALUE parent_block = iseq->compile_data->current_block; + int is_cfcall = (node->nd_tval == 0); iseq->compile_data->current_block = Qfalse; #if SUPPORT_JOKE @@ -3736,7 +3737,7 @@ if (type == NODE_CALL) { COMPILE(recv, "recv", node->nd_recv); } - else if (type == NODE_FCALL || type == NODE_VCALL) { + else if (!is_cfcall && (type == NODE_FCALL || type == NODE_VCALL)) { ADD_CALL_RECEIVER(recv, nd_line(node)); } @@ -3748,10 +3749,17 @@ argc = INT2FIX(0); } + debugp_param("call args argc", argc); + + if (is_cfcall) { + debugp_param("call cfunc", node->nd_cfnc); + ADD_SEQ(ret, args); + ADD_INSN1(ret, nd_line(node), cfcall, node->nd_cfnc); + break; + } ADD_SEQ(ret, recv); ADD_SEQ(ret, args); - debugp_param("call args argc", argc); debugp_param("call method", ID2SYM(mid)); switch (nd_type(node)) { Index: eval.c =================================================================== --- eval.c (revision 12030) +++ eval.c (working copy) @@ -1326,56 +1326,29 @@ rb_rescue2(VALUE (*b_proc) (ANYARGS), VALUE data1, VALUE (*r_proc) (ANYARGS), VALUE data2, ...) { - int state; - volatile VALUE result; - volatile VALUE e_info = GET_THREAD()->errinfo; va_list args; - - PUSH_TAG(PROT_NONE); - if ((state = EXEC_TAG()) == 0) { - retry_entry: - result = (*b_proc) (data1); + int len = 0; + VALUE eclass; + NODE *r_node = 0; + NODE *rb_node = 0; + NODE *e_node = 0; + NODE *b_node = NEW_CFCALL(INT2NUM(b_proc), NEW_ARRAY(NEW_LIT(data1))); + if(r_proc != 0) { + r_node = NEW_CFCALL(INT2NUM(r_proc), NEW_ARRAY(NEW_LIT(data2))); } - else if (state == TAG_RAISE) { - int handle = Qfalse; - VALUE eclass; - - va_init_list(args, data2); - while (eclass = va_arg(args, VALUE)) { - if (rb_obj_is_kind_of(GET_THREAD()->errinfo, eclass)) { - handle = Qtrue; - break; - } - } - va_end(args); - - if (handle) { - if (r_proc) { - PUSH_TAG(PROT_NONE); - if ((state = EXEC_TAG()) == 0) { - result = (*r_proc) (data2, GET_THREAD()->errinfo); - } - POP_TAG(); - if (state == TAG_RETRY) { - state = 0; - GET_THREAD()->errinfo = Qnil; - goto retry_entry; - } - } - else { - result = Qnil; - state = 0; - } - if (state == 0) { - GET_THREAD()->errinfo = e_info; - } - } + rb_node = NEW_RESBODY(0, r_node, 0); + + va_init_list(args, data2); + while (eclass = va_arg(args, VALUE)) { + NODE *n = NEW_ARRAY(NEW_LIT(eclass)); + n->nd_next = e_node; + n->nd_alen = ++len; + e_node = n; } - POP_TAG(); - if (state) - JUMP_TAG(state); + va_end(args); - return result; + rb_node->nd_args = e_node; + return yarvcore_eval_parsed(NEW_RESCUE(b_node, rb_node, 0), rb_str_new2("in rb_rescue")); } VALUE Index: insns.def =================================================================== --- insns.def (revision 12030) +++ insns.def (working copy) @@ -2425,3 +2425,18 @@ ret = INT2FIX(42); } +/** + @c call + @e call the function using function pointer + @j 関数ポインタが示す関数をコールする + */ +DEFINE_INSN +cfcall +(VALUE ptr) +(VALUE arg) +(VALUE ret) +{ + VALUE (*func)(ANYARGS) = NUM2INT(ptr); + ret = func(arg); +} + Index: node.h =================================================================== --- node.h (revision 12030) +++ node.h (working copy) @@ -316,6 +316,7 @@ #define NEW_EVSTR(n) NEW_NODE(NODE_EVSTR,0,(n),0) #define NEW_CALL(r,m,a) NEW_NODE(NODE_CALL,r,m,a) #define NEW_FCALL(m,a) NEW_NODE(NODE_FCALL,0,m,a) +#define NEW_CFCALL(p,a) NEW_NODE(NODE_FCALL,p,0,a) #define NEW_VCALL(m) NEW_NODE(NODE_VCALL,0,m,0) #define NEW_SUPER(a) NEW_NODE(NODE_SUPER,0,0,a) #define NEW_ZSUPER() NEW_NODE(NODE_ZSUPER,0,0,0) -- ワナベ