ruby-changes:39584
From: nobu <ko1@a...>
Date: Sat, 22 Aug 2015 15:43:34 +0900 (JST)
Subject: [ruby-changes:39584] nobu:r51665 (trunk): vm_eval.c: cache results
nobu 2015-08-22 15:43:14 +0900 (Sat, 22 Aug 2015) New Revision: 51665 http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=revision&revision=51665 Log: vm_eval.c: cache results * vm_eval.c (check_funcall_failed, check_funcall_missing): cache results of respond_to? and respond_to_missing?, and search a pulibc method only for compatibility with rb_respond_to. Modified files: trunk/ChangeLog trunk/vm_eval.c trunk/vm_method.c Index: ChangeLog =================================================================== --- ChangeLog (revision 51664) +++ ChangeLog (revision 51665) @@ -1,3 +1,9 @@ https://github.com/ruby/ruby/blob/trunk/ChangeLog#L1 +Sat Aug 22 15:43:12 2015 Nobuyoshi Nakada <nobu@r...> + + * vm_eval.c (check_funcall_failed, check_funcall_missing): cache + results of respond_to? and respond_to_missing?, and search a + pulibc method only for compatibility with rb_respond_to. + Sat Aug 22 08:23:32 2015 Koichi Sasada <ko1@a...> * ext/thread/thread.c: move definitions of Queue, SizedQueue Index: vm_eval.c =================================================================== --- vm_eval.c (revision 51664) +++ vm_eval.c (revision 51665) @@ -352,6 +352,8 @@ struct rescue_funcall_args { https://github.com/ruby/ruby/blob/trunk/vm_eval.c#L352 VALUE recv; ID mid; const rb_method_entry_t *me; + unsigned int respond: 1; + unsigned int respond_to_missing: 1; int argc; const VALUE *argv; }; @@ -364,10 +366,27 @@ check_funcall_exec(struct rescue_funcall https://github.com/ruby/ruby/blob/trunk/vm_eval.c#L366 args->me, args->argc, args->argv); } +#define PRIV Qfalse /* TODO: for rubyspec now, should be Qtrue */ + static VALUE check_funcall_failed(struct rescue_funcall_args *args, VALUE e) { - if (rb_respond_to(args->recv, args->mid)) { + int ret = args->respond; + if (!ret) { + switch (rb_method_boundp(args->defined_class, args->mid, + BOUND_PRIVATE|BOUND_RESPONDS)) { + case 2: + ret = TRUE; + break; + case 0: + ret = args->respond_to_missing; + break; + default: + ret = FALSE; + break; + } + } + if (ret) { rb_exc_raise(e); } return Qundef; @@ -376,7 +395,7 @@ check_funcall_failed(struct rescue_funca https://github.com/ruby/ruby/blob/trunk/vm_eval.c#L395 static int check_funcall_respond_to(rb_thread_t *th, VALUE klass, VALUE recv, ID mid) { - return vm_respond_to(th, klass, recv, mid, 1); + return vm_respond_to(th, klass, recv, mid, TRUE); } static int @@ -386,12 +405,19 @@ check_funcall_callable(rb_thread_t *th, https://github.com/ruby/ruby/blob/trunk/vm_eval.c#L405 } static VALUE -check_funcall_missing(rb_thread_t *th, VALUE klass, VALUE recv, ID mid, int argc, const VALUE *argv) +check_funcall_missing(rb_thread_t *th, VALUE klass, VALUE recv, ID mid, int argc, const VALUE *argv, int respond) { struct rescue_funcall_args args; + const rb_method_entry_t *me; VALUE ret = Qundef; - const rb_method_entry_t *const me = - method_entry_get(klass, idMethodMissing, &args.defined_class); + + ret = basic_obj_respond_to_missing(th, klass, recv, + ID2SYM(mid), PRIV); + if (!RTEST(ret)) return Qundef; + args.respond = respond > 0; + args.respond_to_missing = (ret != Qundef); + ret = Qundef; + me = method_entry_get(klass, idMethodMissing, &args.defined_class); if (me && !METHOD_ENTRY_BASIC(me)) { VALUE argbuf, *new_args = ALLOCV_N(VALUE, argbuf, argc+1); @@ -418,13 +444,14 @@ rb_check_funcall(VALUE recv, ID mid, int https://github.com/ruby/ruby/blob/trunk/vm_eval.c#L444 VALUE klass = CLASS_OF(recv); const rb_callable_method_entry_t *me; rb_thread_t *th = GET_THREAD(); + int respond = check_funcall_respond_to(th, klass, recv, mid); - if (!check_funcall_respond_to(th, klass, recv, mid)) + if (!respond) return Qundef; me = rb_search_method_entry(recv, mid); if (!check_funcall_callable(th, me)) { - return check_funcall_missing(th, klass, recv, mid, argc, argv); + return check_funcall_missing(th, klass, recv, mid, argc, argv, respond); } stack_check(); return vm_call0(th, recv, mid, argc, argv, me); @@ -437,14 +464,15 @@ rb_check_funcall_with_hook(VALUE recv, I https://github.com/ruby/ruby/blob/trunk/vm_eval.c#L464 VALUE klass = CLASS_OF(recv); const rb_callable_method_entry_t *me; rb_thread_t *th = GET_THREAD(); + int respond = check_funcall_respond_to(th, klass, recv, mid); - if (!check_funcall_respond_to(th, klass, recv, mid)) + if (!respond) return Qundef; me = rb_search_method_entry(recv, mid); if (!check_funcall_callable(th, me)) { (*hook)(FALSE, recv, mid, argc, argv, arg); - return check_funcall_missing(th, klass, recv, mid, argc, argv); + return check_funcall_missing(th, klass, recv, mid, argc, argv, respond); } stack_check(); (*hook)(TRUE, recv, mid, argc, argv, arg); Index: vm_method.c =================================================================== --- vm_method.c (revision 51664) +++ vm_method.c (revision 51665) @@ -1832,7 +1832,7 @@ basic_obj_respond_to_missing(rb_thread_t https://github.com/ruby/ruby/blob/trunk/vm_method.c#L1832 const rb_method_entry_t *const me = method_entry_get(klass, rtmid, &defined_class); - if (!me || METHOD_ENTRY_BASIC(me)) return Qfalse; + if (!me || METHOD_ENTRY_BASIC(me)) return Qundef; args[0] = mid; args[1] = priv; return call_method_entry(th, defined_class, obj, rtmid, me, 2, args); @@ -1842,13 +1842,15 @@ static inline int https://github.com/ruby/ruby/blob/trunk/vm_method.c#L1842 basic_obj_respond_to(rb_thread_t *th, VALUE obj, ID id, int pub) { VALUE klass = CLASS_OF(obj); + VALUE ret; switch (rb_method_boundp(klass, id, pub|BOUND_RESPONDS)) { case 2: return FALSE; case 0: - return RTEST(basic_obj_respond_to_missing(th, klass, obj, ID2SYM(id), - pub ? Qfalse : Qtrue)); + ret = basic_obj_respond_to_missing(th, klass, obj, ID2SYM(id), + pub ? Qfalse : Qtrue); + return RTEST(ret) && ret != Qundef; default: return TRUE; } @@ -1864,7 +1866,7 @@ vm_respond_to(rb_thread_t *th, VALUE kla https://github.com/ruby/ruby/blob/trunk/vm_method.c#L1866 if (!me) return TRUE; if (METHOD_ENTRY_BASIC(me)) { - return basic_obj_respond_to(th, obj, id, !priv); + return -1; } else { int argc = 1; @@ -1908,7 +1910,11 @@ vm_respond_to(rb_thread_t *th, VALUE kla https://github.com/ruby/ruby/blob/trunk/vm_method.c#L1910 int rb_obj_respond_to(VALUE obj, ID id, int priv) { - return vm_respond_to(GET_THREAD(), CLASS_OF(obj), obj, id, priv); + rb_thread_t *th = GET_THREAD(); + VALUE klass = CLASS_OF(obj); + int ret = vm_respond_to(th, klass, obj, id, priv); + if (ret == -1) ret = basic_obj_respond_to(th, obj, id, !priv); + return ret; } int @@ -1947,8 +1953,10 @@ obj_respond_to(int argc, VALUE *argv, VA https://github.com/ruby/ruby/blob/trunk/vm_method.c#L1953 rb_scan_args(argc, argv, "11", &mid, &priv); if (!(id = rb_check_id(&mid))) { - return basic_obj_respond_to_missing(th, CLASS_OF(obj), obj, - rb_to_symbol(mid), priv); + VALUE ret = basic_obj_respond_to_missing(th, CLASS_OF(obj), obj, + rb_to_symbol(mid), priv); + if (ret == Qundef) ret = Qfalse; + return ret; } if (basic_obj_respond_to(th, obj, id, !RTEST(priv))) return Qtrue; -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/