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 --- marshal.c | 80 +++++++++++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 62 insertions(+), 18 deletions(-) (limited to 'marshal.c') diff --git a/marshal.c b/marshal.c index abc5546d71..c9bdfd3346 100644 --- a/marshal.c +++ b/marshal.c @@ -586,6 +586,15 @@ w_objivar(VALUE obj, struct dump_call_arg *arg) } } +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) { @@ -646,10 +655,8 @@ w_object(VALUE obj, struct dump_arg *arg, int limit) 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_t num, struct load_arg *arg); 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) 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, VALUE extmod) 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, VALUE extmod) 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, VALUE extmod) /* 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, VALUE extmod) 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); } -- cgit v1.2.3