From 0fe46ceae30eedb2d87f9e62992bf8803c9a4fa5 Mon Sep 17 00:00:00 2001 From: nobu Date: Sun, 23 Dec 2012 06:05:50 +0000 Subject: 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. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@38568 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- vm_eval.c | 90 ++++++++++++++++++++++++++++++++++++++++++++------------------- 1 file changed, 63 insertions(+), 27 deletions(-) (limited to 'vm_eval.c') diff --git a/vm_eval.c b/vm_eval.c index 628c76a1b1..649cb73086 100644 --- a/vm_eval.c +++ b/vm_eval.c @@ -338,16 +338,12 @@ check_funcall_failed(struct rescue_funcall_args *args, VALUE e) 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 argc, VALUE *argv) 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; +} + +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; +} + +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); - 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; - - 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); - } + 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 * -- cgit v1.2.3