diff options
author | matz <matz@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2009-10-31 15:32:22 +0000 |
---|---|---|
committer | matz <matz@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2009-10-31 15:32:22 +0000 |
commit | ab32fe26d9c9c4aad7a8953e3c83cb3b29e935d6 (patch) | |
tree | 4ab24e6e350bd9444e0e3e8a86c7e33a88097eea /vm_eval.c | |
parent | a28cd28c043b0b4357d7658ed0ed78c4c8ffaff8 (diff) | |
download | ruby-ab32fe26d9c9c4aad7a8953e3c83cb3b29e935d6.tar.gz |
* vm_eval.c (check_funcall): logic updated according to
[ruby-dev:39594]. search method entry, call if it exists;
otherwise check method_missing, call if it was overridden,
protecting exceptions; if NoMethodError happens, check method
name.
* vm_eval.c (vm_call0): use idMethodMissing.
* vm_eval.c (rb_search_method_entry): typo fixed.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@25601 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'vm_eval.c')
-rw-r--r-- | vm_eval.c | 72 |
1 files changed, 56 insertions, 16 deletions
@@ -117,7 +117,7 @@ vm_call0(rb_thread_t* th, VALUE recv, VALUE id, int argc, const VALUE *argv, RB_GC_GUARD(new_args); rb_ary_unshift(new_args, ID2SYM(id)); - return rb_funcall2(recv, rb_intern("method_missing"), + return rb_funcall2(recv, idMethodMissing, argc+1, RARRAY_PTR(new_args)); } case VM_METHOD_TYPE_OPTIMIZED: { @@ -201,7 +201,7 @@ stack_check(void) } } -static inline rb_method_entry_t *rb_search_method_emtry(VALUE recv, ID mid); +static inline rb_method_entry_t *rb_search_method_entry(VALUE recv, ID mid); static inline int rb_method_call_status(rb_thread_t *th, rb_method_entry_t *me, call_type scope, VALUE self); #define NOEX_OK NOEX_NOSUPER @@ -223,7 +223,7 @@ static inline VALUE rb_call0(VALUE recv, ID mid, int argc, const VALUE *argv, call_type scope, VALUE self) { - rb_method_entry_t *me = rb_search_method_emtry(recv, mid); + rb_method_entry_t *me = rb_search_method_entry(recv, mid); rb_thread_t *th = GET_THREAD(); int call_status = rb_method_call_status(th, me, scope, self); @@ -234,41 +234,81 @@ rb_call0(VALUE recv, ID mid, int argc, const VALUE *argv, return vm_call0(th, recv, mid, argc, argv, me); } -VALUE -rb_check_funcall(VALUE recv, ID mid, int argc, VALUE *argv) +struct rescue_funcall_args { + VALUE recv; + VALUE sym; + int argc; + VALUE *argv; +}; + +static VALUE +check_funcall_exec(struct rescue_funcall_args *args) +{ + VALUE new_args = rb_ary_new4(args->argc, args->argv); + + RB_GC_GUARD(new_args); + rb_ary_unshift(new_args, args->sym); + return rb_funcall2(args->recv, idMethodMissing, + args->argc+1, RARRAY_PTR(new_args)); +} + +static VALUE +check_funcall_failed(struct rescue_funcall_args *args, VALUE e) +{ + VALUE sym = rb_funcall(e, rb_intern("name"), 0, 0); + + if (args->sym != sym) + rb_exc_raise(e); + return Qundef; +} + +static VALUE +check_funcall(rb_method_entry_t *me, VALUE recv, ID mid, int argc, VALUE *argv) { - rb_method_entry_t *me = rb_search_method_emtry(recv, mid); rb_thread_t *th = GET_THREAD(); int call_status = rb_method_call_status(th, me, CALL_FCALL, Qundef); if (call_status != NOEX_OK) { - return Qundef; + if (rb_method_basic_definition_p(CLASS_OF(recv), idMethodMissing)) { + return Qundef; + } + else { + struct rescue_funcall_args args; + + 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); + } } stack_check(); return vm_call0(th, recv, mid, argc, argv, me); } VALUE +rb_check_funcall(VALUE recv, ID mid, int argc, VALUE *argv) +{ + return check_funcall(rb_search_method_entry(recv, mid), recv, mid, argc, argv); +} + +VALUE rb_funcall_no_recursive(VALUE recv, ID mid, int argc, VALUE *argv, VALUE (*func)()) { - rb_method_entry_t *me = rb_search_method_emtry(recv, mid); - rb_thread_t *th = GET_THREAD(); + rb_method_entry_t *me = rb_search_method_entry(recv, mid); int call_status; if (!me) return Qundef; if (me->def && me->def->type == VM_METHOD_TYPE_CFUNC && me->def->body.cfunc.func == func) return Qundef; - call_status = rb_method_call_status(th, me, CALL_FCALL, Qundef); - if (call_status != NOEX_OK) { - return Qundef; - } - stack_check(); - return vm_call0(th, recv, mid, argc, argv, me); + return check_funcall(me, recv, mid, argc, argv); } static inline rb_method_entry_t * -rb_search_method_emtry(VALUE recv, ID mid) +rb_search_method_entry(VALUE recv, ID mid) { VALUE klass = CLASS_OF(recv); |