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

ruby-changes:25216

From: ko1 <ko1@a...>
Date: Fri, 19 Oct 2012 19:38:42 +0900 (JST)
Subject: [ruby-changes:25216] ko1:r37268 (trunk): * method.h (rb_method_cfunc_t::invoker): add new field (func ptr)

ko1	2012-10-19 19:38:30 +0900 (Fri, 19 Oct 2012)

  New Revision: 37268

  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=rev&revision=37268

  Log:
    * method.h (rb_method_cfunc_t::invoker): add new field (func ptr)
      `invoker'. `invoker' function invoke cfunc body
      (rb_method_cfunc_t::func).
      `invoker' is set at method definition timing.
      With this change, the big `switch' (branch) in `call_cfunc()'
      is no longer needed.
      However, the performance benefit is only a bit.
    * vm_core.h (rb_call_info_t::aux::func): add a new field to store
      cfunc body function pointer.
    * vm_method.c (call_cfunc_invoker_func): add a new function which
      returns a suitable invoke function.
    * vm_method.c (setup_method_cfunc_struct): added.
    * vm_method.c (rb_add_method): fix to set `invoker'.
    * vm_eval.c (vm_call0_body): catch up above changes.
    * vm_insnhelper.c (call_cfunc): removed.
    * vm_insnhelper.c (vm_call_cfunc): fix to call cfunc body
      with `invoker' function.

  Modified files:
    trunk/ChangeLog
    trunk/method.h
    trunk/vm_core.h
    trunk/vm_eval.c
    trunk/vm_insnhelper.c
    trunk/vm_method.c

Index: method.h
===================================================================
--- method.h	(revision 37267)
+++ method.h	(revision 37268)
@@ -45,8 +45,11 @@
     VM_METHOD_TYPE_CFUNC_FRAMELESS
 } rb_method_type_t;
 
+struct rb_call_info_struct;
+
 typedef struct rb_method_cfunc_struct {
     VALUE (*func)(ANYARGS);
+    VALUE (*invoker)(const struct rb_call_info_struct *ci, const VALUE *argv);
     int argc;
 } rb_method_cfunc_t;
 
Index: ChangeLog
===================================================================
--- ChangeLog	(revision 37267)
+++ ChangeLog	(revision 37268)
@@ -1,3 +1,30 @@
+Fri Oct 19 19:29:11 2012  Koichi Sasada  <ko1@a...>
+
+	* method.h (rb_method_cfunc_t::invoker): add new field (func ptr)
+	  `invoker'. `invoker' function invoke cfunc body
+	  (rb_method_cfunc_t::func).
+	  `invoker' is set at method definition timing.
+	  With this change, the big `switch' (branch) in `call_cfunc()'
+	  is no longer needed.
+	  However, the performance benefit is only a bit.
+
+	* vm_core.h (rb_call_info_t::aux::func): add a new field to store
+	  cfunc body function pointer.
+
+	* vm_method.c (call_cfunc_invoker_func): add a new function which
+	  returns a suitable invoke function.
+
+	* vm_method.c (setup_method_cfunc_struct): added.
+
+	* vm_method.c (rb_add_method): fix to set `invoker'.
+
+	* vm_eval.c (vm_call0_body): catch up above changes.
+
+	* vm_insnhelper.c (call_cfunc): removed.
+
+	* vm_insnhelper.c (vm_call_cfunc): fix to call cfunc body
+	  with `invoker' function.
+
 Fri Oct 19 16:55:58 2012  Koichi Sasada  <ko1@a...>
 
 	* eval.c, vm_eval.c: use TH_PUSH_TAG() instead of PUSH_TAG().
Index: vm_core.h
===================================================================
--- vm_core.h	(revision 37267)
+++ vm_core.h	(revision 37268)
@@ -166,6 +166,7 @@
 	int opt_pc; /* used by iseq */
 	long index; /* used by ivar */
 	int missing_reason; /* used by method_missing */
+	VALUE (*func)(ANYARGS); /* used by cfunc */
     } aux;
 
     VALUE (*call)(struct rb_thread_struct *th, struct rb_control_frame_struct *cfp, struct rb_call_info_struct *ci);
Index: vm_eval.c
===================================================================
--- vm_eval.c	(revision 37267)
+++ vm_eval.c	(revision 37268)
@@ -93,9 +93,18 @@
 						    0, reg_cfp->sp, 1, ci->me);
 
 	    cfp->me = ci->me;
-	    val = call_cfunc(ci->me->def->body.cfunc.func, ci->recv,
-			     ci->me->def->body.cfunc.argc, ci->argc, argv);
 
+	    {
+		const rb_method_entry_t *me = ci->me;
+		const rb_method_definition_t *def = me->def;
+		int len = def->body.cfunc.argc;
+
+		if (len >= 0) rb_check_arity(ci->argc, len, len);
+
+		ci->aux.func = def->body.cfunc.func;
+		val = (*def->body.cfunc.invoker)(ci, argv);
+	    }
+
 	    if (reg_cfp != th->cfp + 1) {
 		rb_bug("cfp consistency error - call0");
 	    }
Index: vm_method.c
===================================================================
--- vm_method.c	(revision 37267)
+++ vm_method.c	(revision 37268)
@@ -303,6 +303,41 @@
     }
 }
 
+static VALUE
+(*call_cfunc_invoker_func(int argc))(const rb_call_info_t *, const VALUE *)
+{
+    switch (argc) {
+      case -2: return call_cfunc_m2;
+      case -1: return call_cfunc_m1;
+      case 0: return call_cfunc_0;
+      case 1: return call_cfunc_1;
+      case 2: return call_cfunc_2;
+      case 3: return call_cfunc_3;
+      case 4: return call_cfunc_4;
+      case 5: return call_cfunc_5;
+      case 6: return call_cfunc_6;
+      case 7: return call_cfunc_7;
+      case 8: return call_cfunc_8;
+      case 9: return call_cfunc_9;
+      case 10: return call_cfunc_10;
+      case 11: return call_cfunc_11;
+      case 12: return call_cfunc_12;
+      case 13: return call_cfunc_13;
+      case 14: return call_cfunc_14;
+      case 15: return call_cfunc_15;
+      default:
+	rb_bug("call_cfunc_func: unsupported length: %d", argc);
+    }
+}
+
+static void
+setup_method_cfunc_struct(rb_method_cfunc_t *cfunc, VALUE (*func)(), int argc)
+{
+    cfunc->func = func;
+    cfunc->argc = argc;
+    cfunc->invoker = call_cfunc_invoker_func(argc);
+}
+
 rb_method_entry_t *
 rb_add_method(VALUE klass, ID mid, rb_method_type_t type, void *opts, rb_method_flag_t noex)
 {
@@ -321,7 +356,10 @@
 	break;
       case VM_METHOD_TYPE_CFUNC:
       case VM_METHOD_TYPE_CFUNC_FRAMELESS:
-	def->body.cfunc = *(rb_method_cfunc_t *)opts;
+	{
+	    rb_method_cfunc_t *cfunc = (rb_method_cfunc_t *)opts;
+	    setup_method_cfunc_struct(&def->body.cfunc, cfunc->func, cfunc->argc);
+	}
 	break;
       case VM_METHOD_TYPE_ATTRSET:
       case VM_METHOD_TYPE_IVAR:
@@ -338,8 +376,7 @@
 	def->body.proc = (VALUE)opts;
 	break;
       case VM_METHOD_TYPE_NOTIMPLEMENTED:
-	def->body.cfunc.func = rb_f_notimplement;
-	def->body.cfunc.argc = -1;
+	setup_method_cfunc_struct(&def->body.cfunc, rb_f_notimplement, -1);
 	break;
       case VM_METHOD_TYPE_OPTIMIZED:
 	def->body.optimize_type = (enum method_optimized_type)opts;
Index: vm_insnhelper.c
===================================================================
--- vm_insnhelper.c	(revision 37267)
+++ vm_insnhelper.c	(revision 37268)
@@ -1293,108 +1293,141 @@
     return Qundef;
 }
 
-static inline VALUE
-call_cfunc(VALUE (*func)(), VALUE recv,
-	   int len, int argc, const VALUE *argv)
+static VALUE
+call_cfunc_m2(const rb_call_info_t *ci, const VALUE *argv)
 {
-    /* printf("len: %d, argc: %d\n", len, argc); */
+    return (ci->aux.func)(ci->recv, rb_ary_new4(ci->argc, argv));
+}
 
-    if (len >= 0) rb_check_arity(argc, len, len);
+static VALUE
+call_cfunc_m1(const rb_call_info_t *ci, const VALUE *argv)
+{
+    return (ci->aux.func)(ci->argc, argv, ci->recv);
+}
 
-    switch (len) {
-      case -2:
-	return (*func) (recv, rb_ary_new4(argc, argv));
-	break;
-      case -1:
-	return (*func) (argc, argv, recv);
-	break;
-      case 0:
-	return (*func) (recv);
-	break;
-      case 1:
-	return (*func) (recv, argv[0]);
-	break;
-      case 2:
-	return (*func) (recv, argv[0], argv[1]);
-	break;
-      case 3:
-	return (*func) (recv, argv[0], argv[1], argv[2]);
-	break;
-      case 4:
-	return (*func) (recv, argv[0], argv[1], argv[2], argv[3]);
-	break;
-      case 5:
-	return (*func) (recv, argv[0], argv[1], argv[2], argv[3], argv[4]);
-	break;
-      case 6:
-	return (*func) (recv, argv[0], argv[1], argv[2], argv[3], argv[4],
-			argv[5]);
-	break;
-      case 7:
-	return (*func) (recv, argv[0], argv[1], argv[2], argv[3], argv[4],
-			argv[5], argv[6]);
-	break;
-      case 8:
-	return (*func) (recv, argv[0], argv[1], argv[2], argv[3], argv[4],
-			argv[5], argv[6], argv[7]);
-	break;
-      case 9:
-	return (*func) (recv, argv[0], argv[1], argv[2], argv[3], argv[4],
-			argv[5], argv[6], argv[7], argv[8]);
-	break;
-      case 10:
-	return (*func) (recv, argv[0], argv[1], argv[2], argv[3], argv[4],
-			argv[5], argv[6], argv[7], argv[8], argv[9]);
-	break;
-      case 11:
-	return (*func) (recv, argv[0], argv[1], argv[2], argv[3], argv[4],
-			argv[5], argv[6], argv[7], argv[8], argv[9],
-			argv[10]);
-	break;
-      case 12:
-	return (*func) (recv, argv[0], argv[1], argv[2], argv[3], argv[4],
-			argv[5], argv[6], argv[7], argv[8], argv[9],
-			argv[10], argv[11]);
-	break;
-      case 13:
-	return (*func) (recv, argv[0], argv[1], argv[2], argv[3], argv[4],
-			argv[5], argv[6], argv[7], argv[8], argv[9], argv[10],
-			argv[11], argv[12]);
-	break;
-      case 14:
-	return (*func) (recv, argv[0], argv[1], argv[2], argv[3], argv[4],
-			argv[5], argv[6], argv[7], argv[8], argv[9], argv[10],
-			argv[11], argv[12], argv[13]);
-	break;
-      case 15:
-	return (*func) (recv, argv[0], argv[1], argv[2], argv[3], argv[4],
-			argv[5], argv[6], argv[7], argv[8], argv[9], argv[10],
-			argv[11], argv[12], argv[13], argv[14]);
-	break;
-      default:
-	rb_raise(rb_eArgError, "too many arguments(%d)", len);
-	UNREACHABLE;
-    }
+static VALUE
+call_cfunc_0(const rb_call_info_t *ci, const VALUE *argv)
+{
+    return (ci->aux.func)(ci->recv);
 }
 
 static VALUE
+call_cfunc_1(const rb_call_info_t *ci, const VALUE *argv)
+{
+    return (ci->aux.func)(ci->recv, argv[0]);
+}
+
+static VALUE
+call_cfunc_2(const rb_call_info_t *ci, const VALUE *argv)
+{
+    return (ci->aux.func)(ci->recv, argv[0], argv[1]);
+}
+
+static VALUE
+call_cfunc_3(const rb_call_info_t *ci, const VALUE *argv)
+{
+    return (ci->aux.func)(ci->recv, argv[0], argv[1], argv[2]);
+}
+
+static VALUE
+call_cfunc_4(const rb_call_info_t *ci, const VALUE *argv)
+{
+    return (ci->aux.func)(ci->recv, argv[0], argv[1], argv[2], argv[3]);
+}
+
+static VALUE
+call_cfunc_5(const rb_call_info_t *ci, const VALUE *argv)
+{
+    return (ci->aux.func)(ci->recv, argv[0], argv[1], argv[2], argv[3], argv[4]);
+}
+
+static VALUE
+call_cfunc_6(const rb_call_info_t *ci, const VALUE *argv)
+{
+    return (ci->aux.func)(ci->recv, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5]);
+}
+
+static VALUE
+call_cfunc_7(const rb_call_info_t *ci, const VALUE *argv)
+{
+    return (ci->aux.func)(ci->recv, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6]);
+}
+
+static VALUE
+call_cfunc_8(const rb_call_info_t *ci, const VALUE *argv)
+{
+    return (ci->aux.func)(ci->recv, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7]);
+}
+
+static VALUE
+call_cfunc_9(const rb_call_info_t *ci, const VALUE *argv)
+{
+    return (ci->aux.func)(ci->recv, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8]);
+}
+
+static VALUE
+call_cfunc_10(const rb_call_info_t *ci, const VALUE *argv)
+{
+    return (ci->aux.func)(ci->recv, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9]);
+}
+
+static VALUE
+call_cfunc_11(const rb_call_info_t *ci, const VALUE *argv)
+{
+    return (ci->aux.func)(ci->recv, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9], argv[10]);
+}
+
+static VALUE
+call_cfunc_12(const rb_call_info_t *ci, const VALUE *argv)
+{
+    return (ci->aux.func)(ci->recv, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9], argv[10], argv[11]);
+}
+
+static VALUE
+call_cfunc_13(const rb_call_info_t *ci, const VALUE *argv)
+{
+    return (ci->aux.func)(ci->recv, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9], argv[10], argv[11], argv[12]);
+}
+
+static VALUE
+call_cfunc_14(const rb_call_info_t *ci, const VALUE *argv)
+{
+    return (ci->aux.func)(ci->recv, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9], argv[10], argv[11], argv[12], argv[13]);
+}
+
+static VALUE
+call_cfunc_15(const rb_call_info_t *ci, const VALUE *argv)
+{
+    return (ci->aux.func)(ci->recv, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9], argv[10], argv[11], argv[12], argv[13], argv[14]);
+}
+
+static VALUE
+vm_call_cfunc_call(rb_thread_t *th, rb_control_frame_t *reg_cfp, rb_call_info_t *ci)
+{
+    reg_cfp->sp -= ci->argc + 1;
+    return (*ci->me->def->body.cfunc.invoker)(ci, reg_cfp->sp + 1);
+}
+
+static VALUE
 vm_call_cfunc(rb_thread_t *th, rb_control_frame_t *reg_cfp, rb_call_info_t *ci)
 {
     volatile VALUE val = 0;
     const rb_method_entry_t *me = ci->me;
     const rb_method_definition_t *def = me->def;
+    int len = def->body.cfunc.argc;
 
     EXEC_EVENT_HOOK(th, RUBY_EVENT_C_CALL, ci->recv, me->called_id, me->klass);
 
     vm_push_frame(th, 0, VM_FRAME_MAGIC_CFUNC, ci->recv, ci->defined_class,
 		  VM_ENVVAL_BLOCK_PTR(ci->blockptr), 0, th->cfp->sp, 1, me);
 
-    reg_cfp->sp -= ci->argc + 1;
+    if (len >= 0) rb_check_arity(ci->argc, len, len);
 
-    val = call_cfunc(def->body.cfunc.func, ci->recv, (int)def->body.cfunc.argc, ci->argc, reg_cfp->sp + 1);
+    ci->aux.func = def->body.cfunc.func;
+    val = vm_call_cfunc_call(th, reg_cfp, ci);
 
     if (reg_cfp != th->cfp + 1) {
-	rb_bug("cfp consistency error - send");
+	rb_bug("vm_call_cfunc - cfp consistency error");
     }
 
     vm_pop_frame(th);

--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

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