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

ruby-changes:39968

From: ko1 <ko1@a...>
Date: Tue, 6 Oct 2015 04:44:32 +0900 (JST)
Subject: [ruby-changes:39968] ko1:r52049 (trunk): * vm_insnhelper.c: solve goto spaghetti.

ko1	2015-10-06 04:44:05 +0900 (Tue, 06 Oct 2015)

  New Revision: 52049

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

  Log:
    * vm_insnhelper.c: solve goto spaghetti.
      Change all goto statement across blocks to tail call functions.

  Modified files:
    trunk/ChangeLog
    trunk/vm_insnhelper.c
Index: ChangeLog
===================================================================
--- ChangeLog	(revision 52048)
+++ ChangeLog	(revision 52049)
@@ -1,3 +1,9 @@ https://github.com/ruby/ruby/blob/trunk/ChangeLog#L1
+Tue Oct  6 04:41:03 2015  Koichi Sasada  <ko1@a...>
+
+	* vm_insnhelper.c: solve goto spaghetti.
+
+	  Change all goto statement across blocks to tail call functions.
+
 Tue Oct  6 02:29:38 2015  Nobuyoshi Nakada  <nobu@r...>
 
 	* string.c (rb_str_resurrect): optimize by short circuit to copy
Index: vm_insnhelper.c
===================================================================
--- vm_insnhelper.c	(revision 52048)
+++ vm_insnhelper.c	(revision 52049)
@@ -1237,6 +1237,16 @@ static inline VALUE vm_call_iseq_setup_n https://github.com/ruby/ruby/blob/trunk/vm_insnhelper.c#L1237
 static inline VALUE vm_call_iseq_setup_tailcall(rb_thread_t *th, rb_control_frame_t *cfp, struct rb_calling_info *calling, const struct rb_call_info *ci, struct rb_call_cache *cc, int opt_pc);
 static VALUE vm_call_iseq_setup_normal_0start(rb_thread_t *th, rb_control_frame_t *cfp, struct rb_calling_info *calling, const struct rb_call_info *ci, struct rb_call_cache *cc);
 static VALUE vm_call_iseq_setup_tailcall_0start(rb_thread_t *th, rb_control_frame_t *cfp, struct rb_calling_info *calling, const struct rb_call_info *ci, struct rb_call_cache *cc);
+static VALUE vm_call_super_method(rb_thread_t *th, rb_control_frame_t *reg_cfp, struct rb_calling_info *calling, const struct rb_call_info *ci, struct rb_call_cache *cc);
+static VALUE vm_call_method_nome(rb_thread_t *th, rb_control_frame_t *cfp, struct rb_calling_info *calling, const struct rb_call_info *ci, struct rb_call_cache *cc);
+static VALUE vm_call_method0(rb_thread_t *th, rb_control_frame_t *cfp, struct rb_calling_info *calling, const struct rb_call_info *ci, struct rb_call_cache *cc,
+			     const int enable_fastpath);
+static VALUE vm_call_method_each_type(rb_thread_t *th, rb_control_frame_t *cfp, struct rb_calling_info *calling, const struct rb_call_info *ci, struct rb_call_cache *cc,
+				      const int enable_fastpath);
+
+static rb_method_definition_t *method_definition_create(rb_method_type_t type, ID mid);
+static void method_definition_set(const rb_method_entry_t *me, rb_method_definition_t *def, void *opts);
+static int rb_method_definition_eq(const rb_method_definition_t *d1, const rb_method_definition_t *d2);
 
 static inline VALUE
 vm_callee_setup_block_arg_arg0_check(VALUE *argv)
@@ -1772,14 +1782,6 @@ ci_missing_reason(const struct rb_call_i https://github.com/ruby/ruby/blob/trunk/vm_insnhelper.c#L1782
     return stat;
 }
 
-static
-#ifdef _MSC_VER
-__forceinline
-#else
-inline
-#endif
-VALUE vm_call_method(rb_thread_t *th, rb_control_frame_t *cfp, struct rb_calling_info *calling, const struct rb_call_info *ci, struct rb_call_cache *cc);
-
 static VALUE
 vm_call_opt_send(rb_thread_t *th, rb_control_frame_t *reg_cfp, struct rb_calling_info *calling, const struct rb_call_info *orig_ci, struct rb_call_cache *orig_cc)
 {
@@ -1834,7 +1836,7 @@ vm_call_opt_send(rb_thread_t *th, rb_con https://github.com/ruby/ruby/blob/trunk/vm_insnhelper.c#L1836
 
     cc->me = rb_callable_method_entry_without_refinements(CLASS_OF(calling->recv), ci->mid);
     ci->flag = VM_CALL_FCALL | VM_CALL_OPT_SEND;
-    return vm_call_method(th, reg_cfp, calling, ci, cc);
+    return vm_call_method0(th, reg_cfp, calling, ci, cc, FALSE);
 }
 
 static VALUE
@@ -1887,7 +1889,21 @@ vm_call_method_missing(rb_thread_t *th, https://github.com/ruby/ruby/blob/trunk/vm_insnhelper.c#L1889
     INC_SP(1);
 
     th->method_missing_reason = orig_cc->aux.method_missing_reason;
-    return vm_call_method(th, reg_cfp, calling, ci, cc);
+    return vm_call_method0(th, reg_cfp, calling, ci, cc, FALSE);
+}
+
+static VALUE
+vm_call_zsuper(rb_thread_t *th, rb_control_frame_t *cfp, struct rb_calling_info *calling, const struct rb_call_info *ci, struct rb_call_cache *cc, const int enable_fastpath, VALUE klass)
+{
+    klass = RCLASS_SUPER(klass);
+    cc->me = klass ? rb_callable_method_entry(klass, ci->mid) : NULL;
+
+    if (cc->me != NULL) {
+	return vm_call_method_each_type(th, cfp, calling, ci, cc, enable_fastpath);
+    }
+    else {
+	return vm_call_method_nome(th, cfp, calling, ci, cc);
+    }
 }
 
 static inline VALUE
@@ -1899,9 +1915,6 @@ find_refinement(VALUE refinements, VALUE https://github.com/ruby/ruby/blob/trunk/vm_insnhelper.c#L1915
     return rb_hash_lookup(refinements, klass);
 }
 
-static int rb_method_definition_eq(const rb_method_definition_t *d1, const rb_method_definition_t *d2);
-static VALUE vm_call_super_method(rb_thread_t *th, rb_control_frame_t *reg_cfp, struct rb_calling_info *calling, const struct rb_call_info *ci, struct rb_call_cache *cc);
-
 static rb_control_frame_t *
 current_method_entry(rb_thread_t *th, rb_control_frame_t *cfp)
 {
@@ -1940,9 +1953,6 @@ find_defined_class_by_owner(VALUE curren https://github.com/ruby/ruby/blob/trunk/vm_insnhelper.c#L1953
     return current_class; /* maybe module function */
 }
 
-static rb_method_definition_t *method_definition_create(rb_method_type_t type, ID mid);
-static void method_definition_set(const rb_method_entry_t *me, rb_method_definition_t *def, void *opts);
-
 static const rb_callable_method_entry_t *
 aliased_callable_method_entry(const rb_callable_method_entry_t *me)
 {
@@ -1989,162 +1999,128 @@ refined_method_callable_without_refineme https://github.com/ruby/ruby/blob/trunk/vm_insnhelper.c#L1999
     return cme;
 }
 
-static
-#ifdef _MSC_VER
-__forceinline
-#else
-inline
-#endif
-VALUE
-vm_call_method(rb_thread_t *th, rb_control_frame_t *cfp, struct rb_calling_info *calling, const struct rb_call_info *ci, struct rb_call_cache *cc)
+static VALUE
+vm_call_method_each_type(rb_thread_t *th, rb_control_frame_t *cfp, struct rb_calling_info *calling, const struct rb_call_info *ci, struct rb_call_cache *cc, const int enable_fastpath)
 {
-    int enable_fastpath = 1;
-    struct rb_call_info_with_kwarg ci_temp;
-    struct rb_call_cache cc_temp;
+    switch (cc->me->def->type) {
+      case VM_METHOD_TYPE_ISEQ:
+	CI_SET_FASTPATH(cc, vm_call_iseq_setup, enable_fastpath);
+	return vm_call_iseq_setup(th, cfp, calling, ci, cc);
 
-  start_method_dispatch:
-    VM_ASSERT(callable_method_entry_p(cc->me));
+      case VM_METHOD_TYPE_NOTIMPLEMENTED:
+      case VM_METHOD_TYPE_CFUNC:
+	CI_SET_FASTPATH(cc, vm_call_cfunc, enable_fastpath);
+	return vm_call_cfunc(th, cfp, calling, ci, cc);
 
-    if (cc->me != NULL) {
-	if (LIKELY(METHOD_ENTRY_VISI(cc->me) == METHOD_VISI_PUBLIC && METHOD_ENTRY_SAFE(cc->me) == 0)) {
-	    VALUE klass;
+      case VM_METHOD_TYPE_ATTRSET:
+	CALLER_SETUP_ARG(cfp, calling, ci);
+	rb_check_arity(calling->argc, 1, 1);
+	cc->aux.index = 0;
+	CI_SET_FASTPATH(cc, vm_call_attrset, enable_fastpath && !(ci->flag & VM_CALL_ARGS_SPLAT));
+	return vm_call_attrset(th, cfp, calling, ci, cc);
+
+      case VM_METHOD_TYPE_IVAR:
+	CALLER_SETUP_ARG(cfp, calling, ci);
+	rb_check_arity(calling->argc, 0, 0);
+	cc->aux.index = 0;
+	CI_SET_FASTPATH(cc, vm_call_ivar, enable_fastpath && !(ci->flag & VM_CALL_ARGS_SPLAT));
+	return vm_call_ivar(th, cfp, calling, ci, cc);
+
+      case VM_METHOD_TYPE_MISSING:
+	cc->aux.method_missing_reason = 0;
+	CI_SET_FASTPATH(cc, vm_call_method_missing, enable_fastpath);
+	return vm_call_method_missing(th, cfp, calling, ci, cc);
+
+      case VM_METHOD_TYPE_BMETHOD:
+	CI_SET_FASTPATH(cc, vm_call_bmethod, enable_fastpath);
+	return vm_call_bmethod(th, cfp, calling, ci, cc);
+
+      case VM_METHOD_TYPE_ALIAS:
+	cc->me = aliased_callable_method_entry(cc->me);
+	VM_ASSERT(cc->me != NULL);
+	return vm_call_method_each_type(th, cfp, calling, ci, cc, enable_fastpath);
+
+      case VM_METHOD_TYPE_OPTIMIZED:
+	switch (cc->me->def->body.optimize_type) {
+	  case OPTIMIZED_METHOD_TYPE_SEND:
+	    CI_SET_FASTPATH(cc, vm_call_opt_send, enable_fastpath);
+	    return vm_call_opt_send(th, cfp, calling, ci, cc);
+	  case OPTIMIZED_METHOD_TYPE_CALL:
+	    CI_SET_FASTPATH(cc, vm_call_opt_call, enable_fastpath);
+	    return vm_call_opt_call(th, cfp, calling, ci, cc);
+	  default:
+	    rb_bug("vm_call_method: unsupported optimized method type (%d)",
+		   cc->me->def->body.optimize_type);
+	}
 
-	  normal_method_dispatch:
-	    VM_ASSERT(callable_method_entry_p(cc->me));
+      case VM_METHOD_TYPE_UNDEF:
+	break;
 
-	    switch (cc->me->def->type) {
-	      case VM_METHOD_TYPE_ISEQ:{
-		CI_SET_FASTPATH(cc, vm_call_iseq_setup, enable_fastpath);
-		return vm_call_iseq_setup(th, cfp, calling, ci, cc);
-	      }
-	      case VM_METHOD_TYPE_NOTIMPLEMENTED:
-	      case VM_METHOD_TYPE_CFUNC:
-		CI_SET_FASTPATH(cc, vm_call_cfunc, enable_fastpath);
-		return vm_call_cfunc(th, cfp, calling, ci, cc);
-	      case VM_METHOD_TYPE_ATTRSET:{
-		CALLER_SETUP_ARG(cfp, calling, ci);
-		rb_check_arity(calling->argc, 1, 1);
-		cc->aux.index = 0;
-		CI_SET_FASTPATH(cc, vm_call_attrset, enable_fastpath && !(ci->flag & VM_CALL_ARGS_SPLAT));
-		return vm_call_attrset(th, cfp, calling, ci, cc);
-	      }
-	      case VM_METHOD_TYPE_IVAR:{
-		CALLER_SETUP_ARG(cfp, calling, ci);
-		rb_check_arity(calling->argc, 0, 0);
-		cc->aux.index = 0;
-		CI_SET_FASTPATH(cc, vm_call_ivar, enable_fastpath && !(ci->flag & VM_CALL_ARGS_SPLAT));
-		return vm_call_ivar(th, cfp, calling, ci, cc);
-	      }
-	      case VM_METHOD_TYPE_MISSING:{
-		cc->aux.method_missing_reason = 0;
-		CI_SET_FASTPATH(cc, vm_call_method_missing, enable_fastpath);
-		return vm_call_method_missing(th, cfp, calling, ci, cc);
+      case VM_METHOD_TYPE_ZSUPER:
+	return vm_call_zsuper(th, cfp, calling, ci, cc, enable_fastpath, RCLASS_ORIGIN(cc->me->owner));
+
+      case VM_METHOD_TYPE_REFINED: {
+	  const rb_cref_t *cref = rb_vm_get_cref(cfp->ep);
+	  VALUE refinements = cref ? CREF_REFINEMENTS(cref) : Qnil;
+	  VALUE refinement;
+	  const rb_callable_method_entry_t *ref_me;
+
+	  refinement = find_refinement(refinements, cc->me->owner);
+
+	  if (NIL_P(refinement)) {
+	      goto no_refinement_dispatch;
+	  }
+	  ref_me = rb_callable_method_entry(refinement, ci->mid);
+
+	  if (ref_me) {
+	      if (cc->call == vm_call_super_method) {
+		  const rb_control_frame_t *top_cfp = current_method_entry(th, cfp);
+		  const rb_callable_method_entry_t *top_me = rb_vm_frame_method_entry(top_cfp);
+		  if (top_me && rb_method_definition_eq(ref_me->def, top_me->def)) {
+		      goto no_refinement_dispatch;
+		  }
 	      }
-	      case VM_METHOD_TYPE_BMETHOD:{
-		CI_SET_FASTPATH(cc, vm_call_bmethod, enable_fastpath);
-		return vm_call_bmethod(th, cfp, calling, ci, cc);
+	      cc->me = ref_me;
+	      if (ref_me->def->type != VM_METHOD_TYPE_REFINED) {
+		  return vm_call_method0(th, cfp, calling, ci, cc, enable_fastpath);
 	      }
-	      case VM_METHOD_TYPE_ZSUPER:
-		{
-		    klass = cc->me->owner;
-		    klass = RCLASS_ORIGIN(klass);
-
-		  zsuper_method_dispatch:
-		    klass = RCLASS_SUPER(klass);
-		    if (!klass) {
-			cc->me = NULL;
-			goto start_method_dispatch;
-		    }
-		    else {
-			if (ci->flag & VM_CALL_KWARG) {
-			    ci_temp = *(struct rb_call_info_with_kwarg *)ci;
-			}
-			else {
-			    ci_temp.ci = *ci;
-			}
-
-			ci = &ci_temp.ci;
-			cc_temp = *cc;
-			cc = &cc_temp;
-			cc->me = rb_callable_method_entry(klass, ci->mid);
-
-			if (cc->me != NULL) {
-			    goto normal_method_dispatch;
-			}
-			else {
-			    goto start_method_dispatch;
-			}
-		    }
-		}
-	      case VM_METHOD_TYPE_ALIAS:
-		cc->me = aliased_callable_method_entry(cc->me);
-		VM_ASSERT(cc->me != NULL);
-		goto normal_method_dispatch;
-	      case VM_METHOD_TYPE_OPTIMIZED:{
-		switch (cc->me->def->body.optimize_type) {
-		  case OPTIMIZED_METHOD_TYPE_SEND:
-		    CI_SET_FASTPATH(cc, vm_call_opt_send, enable_fastpath);
-		    return vm_call_opt_send(th, cfp, calling, ci, cc);
-		  case OPTIMIZED_METHOD_TYPE_CALL:
-		    CI_SET_FASTPATH(cc, vm_call_opt_call, enable_fastpath);
-		    return vm_call_opt_call(th, cfp, calling, ci, cc);
-		  default:
-		    rb_bug("vm_call_method: unsupported optimized method type (%d)",
-			   cc->me->def->body.optimize_type);
-		}
-		break;
-	      }
-	      case VM_METHOD_TYPE_UNDEF:
-		break;
-	      case VM_METHOD_TYPE_REFINED:{
-		const rb_cref_t *cref = rb_vm_get_cref(cfp->ep);
-		VALUE refinements = cref ? CREF_REFINEMENTS(cref) : Qnil;
-		VALUE refinement;
-		const rb_callable_method_entry_t *ref_me;
-
-		refinement = find_refinement(refinements, cc->me->owner);
-		if (NIL_P(refinement)) {
-		    goto no_refinement_dispatch;
-		}
-		ref_me = rb_callable_method_entry(refinement, ci->mid);
-		if (ref_me) {
-		    if (cc->call == vm_call_super_method) {
-			const rb_control_frame_t *top_cfp = current_method_entry(th, cfp);
-			const rb_callable_method_entry_t *top_me = rb_vm_frame_method_entry(top_cfp);
-
-			if (top_me && rb_method_definition_eq(ref_me->def, top_me->def)) {
-			    goto no_refinement_dispatch;
-			}
-		    }
-		    cc->me = ref_me;
-		    if (ref_me->def->type != VM_METHOD_TYPE_REFINED) {
-			goto start_method_dispatch;
-		    }
-		}
-		else {
-		    cc->me = 0;
-		    goto start_method_dispatch;
-		}
+	  }
+	  else {
+	      cc->me = NULL;
+	      return vm_call_method_nome(th, cfp, calling, ci, cc);
+	  }
+
+	no_refinement_dispatch:
+	  if (cc->me->def->body.refined.orig_me) {
+	      cc->me = refined_method_callable_without_refinement(cc->me);
 
-	      no_refinement_dispatch:
-		if (cc->me->def->body.refined.orig_me) {
-		    cc->me = refined_method_callable_without_refinement(cc->me);
-
-		    if (UNDEFINED_METHOD_ENTRY_P(cc->me)) {
-			cc->me = 0;
-		    }
-		    goto start_method_dispatch;
-		}
-		else {
-		    klass = cc->me->owner;
-		    goto zsuper_method_dispatch;
-		}
+	      if (UNDEFINED_METHOD_ENTRY_P(cc->me)) {
+		  cc->me = NULL;
 	      }
-	    }
-	    rb_bug("vm_call_method: unsupported method type (%d)", cc->me->def->type);
+	      return vm_call_method0(th, cfp, calling, ci, cc, enable_fastpath);
+	  }
+	  else {
+	      return vm_call_zsuper(th, cfp, calling, ci, cc, enable_fastpath, cc->me->owner);
+	  }
+      }
+    }
+
+    rb_bug("vm_call_method: unsupported method type (%d)", cc->me->def->type);
+}
+
+static VALUE
+vm_call_method0(rb_thread_t *th, rb_control_frame_t *cfp, struct rb_calling_info *calling, const struct rb_call_info *ci, struct rb_call_cache *cc, const int enable_fastpath)
+{
+    VM_ASSERT(callable_method_entry_p(cc->me));
+
+    if (cc->me != NULL) {
+	if (LIKELY(METHOD_ENTRY_VISI(cc->me) == METHOD_VISI_PUBLIC && METHOD_ENTRY_SAFE(cc->me) == 0)) {
+	    VM_ASSERT(callable_method_entry_p(cc->me));
+	    return vm_call_method_each_type(th, cfp, calling, ci, cc, enable_fastpath);
 	}
 	else {
 	    int safe;
+
 	    if (!(ci->flag & VM_CALL_FCALL) && (METHOD_ENTRY_VISI(cc->me) == METHOD_VISI_PRIVATE)) {
 		enum method_missing_reason stat = MISSING_PRIVATE;
 		if (ci->flag & VM_CALL_VCALL) stat |= MISSING_VCALL;
@@ -2159,38 +2135,50 @@ vm_call_method(rb_thread_t *th, rb_contr https://github.com/ruby/ruby/blob/trunk/vm_insnhelper.c#L2135
 		    return vm_call_method_missing(th, cfp, calling, ci, cc);
 		}
 		else {
-		    enable_fastpath = 0;
 		    VM_ASSERT(cc->me != NULL);
-		    goto normal_method_dispatch;
+		    return vm_call_method_each_type(th, cfp, calling, ci, cc, FALSE);
 		}
 	    }
 	    else if ((safe = METHOD_ENTRY_SAFE(cc->me)) > th->safe_level && safe > 2) {
 		rb_raise(rb_eSecurityError, "calling insecure method: %"PRIsVALUE, rb_id2str(ci->mid));
 	    }
 	    else {
-		goto normal_method_dispatch;
+		return vm_call_method_each_type(th, cfp, calling, ci, cc, enable_fastpath);
 	    }
 	}
     }
     else {
-	/* method missing */
-	const int stat = ci_missing_reason(ci);
-	if (ci->mid == idMethodMissing) {
-	    rb_control_frame_t *reg_cfp = cfp;
-	    VALUE *argv = STACK_ADDR_FROM_TOP(calling->argc);
-	    rb_raise_method_missing(th, calling->argc, argv, calling->recv, stat);
-	}
-	else {
-	    cc->aux.method_missing_reason = stat;
-	    CI_SET_FASTPATH(cc, vm_call_method_missing, 1);
-	    return vm_call_method_missing(th, cfp, calling, ci, cc);
-	}
+	return vm_call_method_nome(th, cfp, calling, ci, cc);
     }
 
     rb_bug("vm_call_method: unreachable");
 }
 
 static VALUE
+vm_call_method_nome(rb_thread_t *th, rb_control_frame_t *cfp, struct rb_calling_info *calling, const struct rb_call_info *ci, struct rb_call_cache *cc)
+{
+    /* method missing */
+    const int stat = ci_missing_reason(ci);
+
+    if (ci->mid == idMethodMissing) {
+	rb_control_frame_t *reg_cfp = cfp;
+	VALUE *argv = STACK_ADDR_FROM_TOP(calling->argc);
+	rb_raise_method_missing(th, calling->argc, argv, calling->recv, stat);
+    }
+    else {
+	cc->aux.method_missing_reason = stat;
+	CI_SET_FASTPATH(cc, vm_call_method_missing, 1);
+	return vm_call_method_missing(th, cfp, calling, ci, cc);
+    }
+}
+
+static inline VALUE
+vm_call_method(rb_thread_t *th, rb_control_frame_t *cfp, struct rb_calling_info *calling, const struct rb_call_info *ci, struct rb_call_cache *cc)
+{
+    return vm_call_method0(th, cfp, calling, ci, cc, TRUE);
+}
+
+static VALUE
 vm_call_general(rb_thread_t *th, rb_control_frame_t *reg_cfp, struct rb_calling_info *calling, const struct rb_call_info *ci, struct rb_call_cache *cc)
 {
     return vm_call_method(th, reg_cfp, calling, ci, cc);
@@ -2199,6 +2187,8 @@ vm_call_general(rb_thread_t *th, rb_cont https://github.com/ruby/ruby/blob/trunk/vm_insnhelper.c#L2187
 static VALUE
 vm_call_super_method(rb_thread_t *th, rb_control_frame_t *reg_cfp, struct rb_calling_info *calling, const struct rb_call_info *ci, struct rb_call_cache *cc)
 {
+    /* this check is required to distinguish with other functions. */
+    if (cc->call != vm_call_super_method) rb_bug("bug");
     return vm_call_method(th, reg_cfp, calling, ci, cc);
 }
 

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

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