ruby-changes:26517
From: nobu <ko1@a...>
Date: Sun, 23 Dec 2012 15:07:41 +0900 (JST)
Subject: [ruby-changes:26517] nobu:r38568 (trunk): marshal.c: rb_check_funcall_with_hook
nobu 2012-12-23 15:05:50 +0900 (Sun, 23 Dec 2012) New Revision: 38568 http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=rev&revision=38568 Log: marshal.c: rb_check_funcall_with_hook * vm_eval.c (rb_check_funcall_with_hook): rb_check_funcall with hook which is called before calling method_missing or target method. * marshal.c (w_object, r_object0): use rb_check_funcall_with_hook instead of respond_to? and call. Modified files: trunk/ChangeLog trunk/internal.h trunk/marshal.c trunk/vm_eval.c Index: ChangeLog =================================================================== --- ChangeLog (revision 38567) +++ ChangeLog (revision 38568) @@ -1,3 +1,11 @@ https://github.com/ruby/ruby/blob/trunk/ChangeLog#L1 +Sun Dec 23 15:05:48 2012 Nobuyoshi Nakada <nobu@r...> + + * vm_eval.c (rb_check_funcall_with_hook): rb_check_funcall with hook + which is called before calling method_missing or target method. + + * marshal.c (w_object, r_object0): use rb_check_funcall_with_hook + instead of respond_to? and call. + Sun Dec 23 14:52:00 2012 Zachary Scott <zachary@z...> * re.c (rb_reg_eqq): doc: #=== is not a synonym for #=~, added example Index: vm_eval.c =================================================================== --- vm_eval.c (revision 38567) +++ vm_eval.c (revision 38568) @@ -338,16 +338,12 @@ check_funcall_failed(struct rescue_funca https://github.com/ruby/ruby/blob/trunk/vm_eval.c#L338 return Qundef; } -static VALUE -check_funcall(VALUE recv, ID mid, int argc, VALUE *argv) +static int +check_funcall_respond_to(rb_thread_t *th, VALUE klass, VALUE recv, ID mid) { - VALUE klass = CLASS_OF(recv); - const rb_method_entry_t *me; - rb_thread_t *th = GET_THREAD(); - int call_status; VALUE defined_class; + const rb_method_entry_t *me = rb_method_entry(klass, idRespond_to, &defined_class); - me = rb_method_entry(klass, idRespond_to, &defined_class); if (me && !(me->flag & NOEX_BASIC)) { VALUE args[2]; int arity = rb_method_entry_arity(me); @@ -360,37 +356,77 @@ check_funcall(VALUE recv, ID mid, int ar https://github.com/ruby/ruby/blob/trunk/vm_eval.c#L356 args[0] = ID2SYM(mid); args[1] = Qtrue; if (!RTEST(vm_call0(th, recv, idRespond_to, arity, args, me, defined_class))) { - return Qundef; + return FALSE; } } + return TRUE; +} - me = rb_search_method_entry(recv, mid, &defined_class); - call_status = rb_method_call_status(th, me, CALL_FCALL, th->cfp->self); - if (call_status != NOEX_OK) { - if (rb_method_basic_definition_p(klass, idMethodMissing)) { - return Qundef; - } - else { - struct rescue_funcall_args args; +static int +check_funcall_callable(rb_thread_t *th, const rb_method_entry_t *me) +{ + return rb_method_call_status(th, me, CALL_FCALL, th->cfp->self) == NOEX_OK; +} - th->method_missing_reason = 0; - args.recv = recv; - args.sym = ID2SYM(mid); - args.argc = argc; - args.argv = argv; - return rb_rescue2(check_funcall_exec, (VALUE)&args, - check_funcall_failed, (VALUE)&args, - rb_eNoMethodError, (VALUE)0); - } +static VALUE +check_funcall_missing(rb_thread_t *th, VALUE klass, VALUE recv, ID mid, int argc, VALUE *argv) +{ + if (rb_method_basic_definition_p(klass, idMethodMissing)) { + return Qundef; + } + else { + struct rescue_funcall_args args; + + th->method_missing_reason = 0; + args.recv = recv; + args.sym = ID2SYM(mid); + args.argc = argc; + args.argv = argv; + return rb_rescue2(check_funcall_exec, (VALUE)&args, + check_funcall_failed, (VALUE)&args, + rb_eNoMethodError, (VALUE)0); + } +} + +VALUE +rb_check_funcall(VALUE recv, ID mid, int argc, VALUE *argv) +{ + VALUE klass = CLASS_OF(recv); + const rb_method_entry_t *me; + rb_thread_t *th = GET_THREAD(); + VALUE defined_class; + + if (!check_funcall_respond_to(th, klass, recv, mid)) + return Qundef; + + me = rb_search_method_entry(recv, mid, &defined_class); + if (check_funcall_callable(th, me) != NOEX_OK) { + return check_funcall_missing(th, klass, recv, mid, argc, argv); } stack_check(); return vm_call0(th, recv, mid, argc, argv, me, defined_class); } VALUE -rb_check_funcall(VALUE recv, ID mid, int argc, VALUE *argv) +rb_check_funcall_with_hook(VALUE recv, ID mid, int argc, VALUE *argv, + rb_check_funcall_hook *hook, VALUE arg) { - return check_funcall(recv, mid, argc, argv); + VALUE klass = CLASS_OF(recv); + const rb_method_entry_t *me; + rb_thread_t *th = GET_THREAD(); + VALUE defined_class; + + if (!check_funcall_respond_to(th, klass, recv, mid)) + return Qundef; + + me = rb_search_method_entry(recv, mid, &defined_class); + if (check_funcall_callable(th, me) != NOEX_OK) { + (*hook)(FALSE, recv, mid, argc, argv, arg); + return check_funcall_missing(th, klass, recv, mid, argc, argv); + } + stack_check(); + (*hook)(TRUE, recv, mid, argc, argv, arg); + return vm_call0(th, recv, mid, argc, argv, me, defined_class); } static const char * Index: internal.h =================================================================== --- internal.h (revision 38567) +++ internal.h (revision 38568) @@ -312,6 +312,9 @@ void rb_vm_bugreport(void); https://github.com/ruby/ruby/blob/trunk/internal.h#L312 void Init_vm_eval(void); VALUE rb_current_realfilepath(void); VALUE rb_check_block_call(VALUE, ID, int, VALUE *, VALUE (*)(ANYARGS), VALUE); +typedef void rb_check_funcall_hook(int, VALUE, ID, int, VALUE *, VALUE); +VALUE rb_check_funcall_with_hook(VALUE recv, ID mid, int argc, VALUE *argv, + rb_check_funcall_hook *hook, VALUE arg); /* vm_method.c */ void Init_eval_method(void); Index: marshal.c =================================================================== --- marshal.c (revision 38567) +++ marshal.c (revision 38568) @@ -587,6 +587,15 @@ w_objivar(VALUE obj, struct dump_call_ar https://github.com/ruby/ruby/blob/trunk/marshal.c#L587 } static void +push_dump_object(int found, VALUE recv, ID mid, int argc, VALUE *argv, VALUE data) +{ + if (found) { + struct dump_arg *arg = (struct dump_arg *)data; + st_add_direct(arg->data, recv, arg->data->num_entries); + } +} + +static void w_object(VALUE obj, struct dump_arg *arg, int limit) { struct dump_call_arg c_arg; @@ -646,10 +655,8 @@ w_object(VALUE obj, struct dump_arg *arg https://github.com/ruby/ruby/blob/trunk/marshal.c#L655 arg->infection |= (int)FL_TEST(obj, MARSHAL_INFECTION); - if (rb_obj_respond_to(obj, s_mdump, TRUE)) { - st_add_direct(arg->data, obj, arg->data->num_entries); - - v = rb_funcall2(obj, s_mdump, 0, 0); + v = rb_check_funcall_with_hook(obj, s_mdump, 0, 0, push_dump_object, (VALUE)arg); + if (v != Qundef) { check_dump_arg(arg, s_mdump); hasiv = has_ivars(obj, ivtbl); if (hasiv) w_byte(TYPE_IVAR, arg); @@ -1026,6 +1033,7 @@ static VALUE r_entry0(VALUE v, st_index_ https://github.com/ruby/ruby/blob/trunk/marshal.c#L1033 static VALUE r_object(struct load_arg *arg); static ID r_symbol(struct load_arg *arg); static VALUE path2class(VALUE path); +static VALUE r_object0(struct load_arg *arg, int *ivp, VALUE extmod); NORETURN(static void too_short(void)); static void @@ -1434,6 +1442,42 @@ append_extmod(VALUE obj, VALUE extmod) https://github.com/ruby/ruby/blob/trunk/marshal.c#L1442 return obj; } +static void +load_data_hook(int found, VALUE recv, ID mid, int argc, VALUE *argv, VALUE data) +{ + if (found) { + struct load_arg *arg = (struct load_arg *)((VALUE *)data)[0]; + VALUE extmod = ((VALUE *)data)[1]; + *argv = r_object0(arg, 0, extmod); + } +} + +static void +load_userdef_hook(int found, VALUE recv, ID mid, int argc, VALUE *argv, VALUE data) +{ + if (found) { + struct load_arg *arg = (struct load_arg *)((VALUE *)data)[0]; + int *ivp = (int *)((VALUE *)data)[1]; + VALUE r = r_string(arg); + if (ivp) { + r_ivar(r, NULL, arg); + *ivp = FALSE; + } + *argv = r; + } +} + +static void +mload_hook(int found, VALUE recv, ID mid, int argc, VALUE *argv, VALUE data) +{ + if (found) { + struct load_arg *arg = (struct load_arg *)((VALUE *)data)[0]; + VALUE v = ((VALUE *)data)[1]; + r_entry(v, arg); + *argv = r_object(arg); + } +} + static VALUE r_object0(struct load_arg *arg, int *ivp, VALUE extmod) { @@ -1441,6 +1485,7 @@ r_object0(struct load_arg *arg, int *ivp https://github.com/ruby/ruby/blob/trunk/marshal.c#L1485 int type = r_byte(arg); long id; st_data_t link; + VALUE args[2]; switch (type) { case TYPE_LINK: @@ -1718,16 +1763,14 @@ r_object0(struct load_arg *arg, int *ivp https://github.com/ruby/ruby/blob/trunk/marshal.c#L1763 VALUE klass = path2class(r_unique(arg)); VALUE data; - if (!rb_obj_respond_to(klass, s_load, TRUE)) { + args[0] = (VALUE)arg; + args[1] = (VALUE)ivp; + v = rb_check_funcall_with_hook(klass, s_load, 1, &data, + load_userdef_hook, (VALUE)args); + if (v == Qundef) { rb_raise(rb_eTypeError, "class %s needs to have method `_load'", rb_class2name(klass)); } - data = r_string(arg); - if (ivp) { - r_ivar(data, NULL, arg); - *ivp = FALSE; - } - v = rb_funcall2(klass, s_load, 1, &data); check_load_arg(arg, s_load); v = r_entry(v, arg); v = r_leave(v, arg); @@ -1745,13 +1788,13 @@ r_object0(struct load_arg *arg, int *ivp https://github.com/ruby/ruby/blob/trunk/marshal.c#L1788 /* for the case marshal_load is overridden */ append_extmod(v, extmod); } - if (!rb_obj_respond_to(v, s_mload, TRUE)) { + args[0] = (VALUE)arg; + args[1] = v; + data = rb_check_funcall_with_hook(v, s_mload, 1, &data, mload_hook, (VALUE)args); + if (data == Qundef) { rb_raise(rb_eTypeError, "instance of %s needs to have method `marshal_load'", rb_class2name(klass)); } - v = r_entry(v, arg); - data = r_object(arg); - rb_funcall2(v, s_mload, 1, &data); check_load_arg(arg, s_mload); v = r_leave(v, arg); if (!NIL_P(extmod)) { @@ -1785,13 +1828,14 @@ r_object0(struct load_arg *arg, int *ivp https://github.com/ruby/ruby/blob/trunk/marshal.c#L1828 rb_raise(rb_eArgError, "dump format error"); } v = r_entry(v, arg); - if (!rb_obj_respond_to(v, s_load_data, TRUE)) { + args[0] = (VALUE)arg; + args[1] = extmod; + r = rb_check_funcall_with_hook(v, s_load_data, 1, &r, load_data_hook, (VALUE)args); + if (r == Qundef) { rb_raise(rb_eTypeError, "class %s needs to have instance method `_load_data'", rb_class2name(klass)); } - r = r_object0(arg, 0, extmod); - rb_funcall2(v, s_load_data, 1, &r); check_load_arg(arg, s_load_data); v = r_leave(v, arg); } -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/