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

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/

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