summaryrefslogtreecommitdiffstats
path: root/vm_eval.c
diff options
context:
space:
mode:
authormatz <matz@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2009-10-31 15:32:22 +0000
committermatz <matz@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2009-10-31 15:32:22 +0000
commita190d2dc09aacd1422a8910b3b75947988da7775 (patch)
tree4ab24e6e350bd9444e0e3e8a86c7e33a88097eea /vm_eval.c
parentb18838379ee2a5078e03fda26fe4e4e69066e414 (diff)
downloadruby-a190d2dc09aacd1422a8910b3b75947988da7775.tar.gz
ruby-a190d2dc09aacd1422a8910b3b75947988da7775.tar.xz
ruby-a190d2dc09aacd1422a8910b3b75947988da7775.zip
* 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: http://svn.ruby-lang.org/repos/ruby/trunk@25601 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'vm_eval.c')
-rw-r--r--vm_eval.c72
1 files changed, 56 insertions, 16 deletions
diff --git a/vm_eval.c b/vm_eval.c
index c78d9e5fb..f5b36e3d8 100644
--- a/vm_eval.c
+++ b/vm_eval.c
@@ -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);