summaryrefslogtreecommitdiff
path: root/vm_eval.c
diff options
context:
space:
mode:
authornobu <nobu@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2012-12-23 06:05:50 +0000
committernobu <nobu@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2012-12-23 06:05:50 +0000
commit0fe46ceae30eedb2d87f9e62992bf8803c9a4fa5 (patch)
tree6ec398f28d7909bd338fd611b68de828d305adf0 /vm_eval.c
parent450b9bb6cb46bcc64b3d593e060c4d69df8d95d9 (diff)
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
Diffstat (limited to 'vm_eval.c')
-rw-r--r--vm_eval.c90
1 files changed, 63 insertions, 27 deletions
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 *