[前][次][番号順一覧][スレッド一覧]

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/

[前][次][番号順一覧][スレッド一覧]