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

ruby-changes:24048

From: ko1 <ko1@a...>
Date: Fri, 15 Jun 2012 19:22:44 +0900 (JST)
Subject: [ruby-changes:24048] ko1:r36099 (trunk): * vm_core.h: remove VM_FRAME_MAGIC_FINISH (finish frame type).

ko1	2012-06-15 19:22:34 +0900 (Fri, 15 Jun 2012)

  New Revision: 36099

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

  Log:
    * vm_core.h: remove VM_FRAME_MAGIC_FINISH (finish frame type).
      Before this commit:
      `finish frame' was place holder which indicates that VM loop
      needs to return function.
      If a C method calls a Ruby methods (a method written by Ruby),
      then VM loop will be (re-)invoked.  When the Ruby method returns,
      then also VM loop should be escaped.  `finish frame' has only
      one instruction `finish', which returns VM loop function.
      VM loop function executes `finish' instruction, then VM loop
      function returns itself.
      With such mechanism, `leave' instruction (which returns one
      frame from current scope) doesn't need to check that this `leave'
      should also return from VM loop function.
      Strictly, one branch can be removed from `leave' instructon.
      Consideration:
      However, pushing the `finish frame' needs costs because
      it needs several memory accesses.  The number of pushing
      `finish frame' is greater than I had assumed.  Of course,
      pushing `finish frame' consumes additional control frame.
      Moreover, recent processors has good branch prediction,
      with which we can ignore such trivial checking.
      After this commit:
      Finally, I decide to remove `finish frame' and `finish'
      instruction.  Some parts of VM depend on `finish frame',
      so the new frame flag VM_FRAME_FLAG_FINISH is introduced.
      If this frame should escape from VM function loop, then
      the result of VM_FRAME_TYPE_FINISH_P(cfp) is true.
      `leave' instruction checks this flag every time.
      I measured performance on it.  However on my environments,
      it improves some benchmarks and slows some benchmarks down.
      Maybe it is because of C compiler optimization parameters.
      I'll re-visit here if this cause problems.
    * insns.def (leave, finish): remove finish instruction.
    * vm.c, vm_eval.c, vm_exec.c, vm_backtrace.c, vm_dump.c:
      apply above changes.

  Modified files:
    trunk/ChangeLog
    trunk/insns.def
    trunk/vm.c
    trunk/vm_backtrace.c
    trunk/vm_core.h
    trunk/vm_dump.c
    trunk/vm_eval.c
    trunk/vm_exec.c

Index: ChangeLog
===================================================================
--- ChangeLog	(revision 36098)
+++ ChangeLog	(revision 36099)
@@ -1,3 +1,43 @@
+Fri Jun 15 19:22:13 2012  Koichi Sasada  <ko1@a...>
+
+	* vm_core.h: remove VM_FRAME_MAGIC_FINISH (finish frame type).
+	  Before this commit:
+	    `finish frame' was place holder which indicates that VM loop
+	    needs to return function.
+	    If a C method calls a Ruby methods (a method written by Ruby),
+	    then VM loop will be (re-)invoked.  When the Ruby method returns,
+	    then also VM loop should be escaped.  `finish frame' has only
+	    one instruction `finish', which returns VM loop function.
+	    VM loop function executes `finish' instruction, then VM loop
+	    function returns itself.
+	    With such mechanism, `leave' instruction (which returns one
+	    frame from current scope) doesn't need to check that this `leave'
+	    should also return from VM loop function.
+	    Strictly, one branch can be removed from `leave' instructon.
+	  Consideration:
+	    However, pushing the `finish frame' needs costs because
+	    it needs several memory accesses.  The number of pushing
+	    `finish frame' is greater than I had assumed.  Of course,
+	    pushing `finish frame' consumes additional control frame.
+	    Moreover, recent processors has good branch prediction,
+	    with which we can ignore such trivial checking.
+	  After this commit:
+	    Finally, I decide to remove `finish frame' and `finish'
+	    instruction.  Some parts of VM depend on `finish frame',
+	    so the new frame flag VM_FRAME_FLAG_FINISH is introduced.
+	    If this frame should escape from VM function loop, then
+	    the result of VM_FRAME_TYPE_FINISH_P(cfp) is true.
+	    `leave' instruction checks this flag every time.
+	    I measured performance on it.  However on my environments,
+	    it improves some benchmarks and slows some benchmarks down.
+	    Maybe it is because of C compiler optimization parameters.
+	    I'll re-visit here if this cause problems.
+
+	* insns.def (leave, finish): remove finish instruction.
+
+	* vm.c, vm_eval.c, vm_exec.c, vm_backtrace.c, vm_dump.c:
+	  apply above changes.
+
 Fri Jun 15 19:11:23 2012  Nobuyoshi Nakada  <nobu@r...>
 
 	* lib/test/unit.rb (Test::Unit::Runner#puke): always add skipped
Index: insns.def
===================================================================
--- insns.def	(revision 36098)
+++ insns.def	(revision 36099)
@@ -1092,27 +1092,19 @@
     }
 
     RUBY_VM_CHECK_INTS();
-    vm_pop_frame(th);
-    RESTORE_REGS();
-}
 
-/**
-  @c method/iterator
-  @e return from this vm loop
-  @j VM loop 
- */
-DEFINE_INSN
-finish
-()
-(VALUE val)
-(VALUE val)
-{
+    if (UNLIKELY(VM_FRAME_TYPE_FINISH_P(GET_CFP()))) {
 #if OPT_CALL_THREADED_CODE
-    rb_bug("unused instruction on OPT_CALL_THREADED_CODE");
+	rb_bug("unused instruction on OPT_CALL_THREADED_CODE");
 #else
-    th->cfp++;
-    return val;
+	vm_pop_frame(th);
+	return val;
 #endif
+    }
+    else {
+	vm_pop_frame(th);
+	RESTORE_REGS();
+    }
 }
 
 /**********************************************************/
Index: vm_core.h
===================================================================
--- vm_core.h	(revision 36098)
+++ vm_core.h	(revision 36099)
@@ -596,7 +596,6 @@
 #define VM_FRAME_MAGIC_BLOCK  0x21
 #define VM_FRAME_MAGIC_CLASS  0x31
 #define VM_FRAME_MAGIC_TOP    0x41
-#define VM_FRAME_MAGIC_FINISH 0x51
 #define VM_FRAME_MAGIC_CFUNC  0x61
 #define VM_FRAME_MAGIC_PROC   0x71
 #define VM_FRAME_MAGIC_IFUNC  0x81
@@ -609,6 +608,8 @@
 
 /* other frame flag */
 #define VM_FRAME_FLAG_PASSED 0x0100
+#define VM_FRAME_FLAG_FINISH 0x0200
+#define VM_FRAME_TYPE_FINISH_P(cfp) ((cfp)->flag & VM_FRAME_FLAG_FINISH)
 
 #define RUBYVM_CFUNC_FRAME_P(cfp) \
   (VM_FRAME_TYPE(cfp) == VM_FRAME_MAGIC_CFUNC)
Index: vm_eval.c
===================================================================
--- vm_eval.c	(revision 36098)
+++ vm_eval.c	(revision 36099)
@@ -12,7 +12,6 @@
 **********************************************************************/
 
 static inline VALUE method_missing(VALUE obj, ID id, int argc, const VALUE *argv, int call_status);
-static inline VALUE rb_vm_set_finish_env(rb_thread_t * th);
 static inline VALUE vm_yield_with_cref(rb_thread_t *th, int argc, const VALUE *argv, const NODE *cref);
 static inline VALUE vm_yield(rb_thread_t *th, int argc, const VALUE *argv);
 static NODE *vm_cref_push(rb_thread_t *th, VALUE klass, int noex, rb_block_t *blockptr);
@@ -50,12 +49,9 @@
   again:
     switch (def->type) {
       case VM_METHOD_TYPE_ISEQ: {
-	rb_control_frame_t *reg_cfp;
+	rb_control_frame_t *reg_cfp = th->cfp;
 	int i;
 
-	rb_vm_set_finish_env(th);
-	reg_cfp = th->cfp;
-
 	CHECK_STACK_OVERFLOW(reg_cfp, argc + 1);
 
 	*reg_cfp->sp++ = recv;
@@ -64,6 +60,7 @@
 	}
 
 	vm_setup_method(th, reg_cfp, recv, argc, blockptr, 0 /* flag */, me);
+	th->cfp->flag |= VM_FRAME_FLAG_FINISH;
 	val = vm_exec(th);
 	break;
       }
Index: vm_backtrace.c
===================================================================
--- vm_backtrace.c	(revision 36098)
+++ vm_backtrace.c	(revision 36099)
@@ -379,8 +379,7 @@
 
     start_cfp =
       RUBY_VM_NEXT_CONTROL_FRAME(
-	  RUBY_VM_NEXT_CONTROL_FRAME(
-	      RUBY_VM_NEXT_CONTROL_FRAME(start_cfp))); /* skip top frames */
+	  RUBY_VM_NEXT_CONTROL_FRAME(start_cfp)); /* skip top frames */
 
     if (start_cfp < last_cfp) {
 	size = 0;
Index: vm_exec.c
===================================================================
--- vm_exec.c	(revision 36098)
+++ vm_exec.c	(revision 36099)
@@ -25,14 +25,6 @@
 #endif
 /* #define DECL_SC_REG(r, reg) VALUE reg_##r */
 
-#if OPT_STACK_CACHING
-static VALUE finish_insn_seq[1] = { BIN(finish_SC_ax_ax) };
-#elif OPT_CALL_THREADED_CODE
-static VALUE const finish_insn_seq[1] = { 0 };
-#else
-static VALUE finish_insn_seq[1] = { BIN(finish) };
-#endif
-
 #if !OPT_CALL_THREADED_CODE
 static VALUE
 vm_exec_core(rb_thread_t *th, VALUE initial)
@@ -84,11 +76,6 @@
 #if OPT_TOKEN_THREADED_CODE || OPT_DIRECT_THREADED_CODE
 #include "vmtc.inc"
     if (UNLIKELY(th == 0)) {
-#if OPT_STACK_CACHING
-	finish_insn_seq[0] = (VALUE)&&LABEL (finish_SC_ax_ax);
-#else
-	finish_insn_seq[0] = (VALUE)&&LABEL (finish);
-#endif
 	return (VALUE)insns_address_table;
     }
 #endif
@@ -145,7 +132,7 @@
 	}
     }
 
-    if (VM_FRAME_TYPE(th->cfp) != VM_FRAME_MAGIC_FINISH) {
+    if (VM_FRAME_TYPE_FINISH_P(th->cfp)) {
 	rb_bug("cfp consistency error");
     }
 
Index: vm.c
===================================================================
--- vm.c	(revision 36098)
+++ vm.c	(revision 36099)
@@ -123,16 +123,6 @@
 
 /* control stack frame */
 
-static inline VALUE
-rb_vm_set_finish_env(rb_thread_t * th)
-{
-    vm_push_frame(th, 0, VM_FRAME_MAGIC_FINISH,
-		  Qnil, VM_ENVVAL_BLOCK_PTR(VM_CF_BLOCK_PTR(th->cfp)), 0,
-		  th->cfp->sp, 1);
-    th->cfp->pc = (VALUE *)&finish_insn_seq[0];
-    return Qtrue;
-}
-
 static void
 vm_set_top_stack(rb_thread_t * th, VALUE iseqval)
 {
@@ -144,10 +134,8 @@
     }
 
     /* for return */
-    rb_vm_set_finish_env(th);
-
     CHECK_STACK_OVERFLOW(th->cfp, iseq->local_size + iseq->stack_max);
-    vm_push_frame(th, iseq, VM_FRAME_MAGIC_TOP,
+    vm_push_frame(th, iseq, VM_FRAME_MAGIC_TOP | VM_FRAME_FLAG_FINISH,
 		  th->top_self, VM_ENVVAL_BLOCK_PTR(0), iseq->iseq_encoded,
 		  th->cfp->sp, iseq->local_size);
 }
@@ -159,11 +147,8 @@
     rb_block_t * const block = th->base_block;
     GetISeqPtr(iseqval, iseq);
 
-    /* for return */
-    rb_vm_set_finish_env(th);
-
     CHECK_STACK_OVERFLOW(th->cfp, iseq->local_size + iseq->stack_max);
-    vm_push_frame(th, iseq, VM_FRAME_MAGIC_EVAL, block->self,
+    vm_push_frame(th, iseq, VM_FRAME_MAGIC_EVAL | VM_FRAME_FLAG_FINISH, block->self,
 		  VM_ENVVAL_PREV_EP_PTR(block->ep), iseq->iseq_encoded,
 		  th->cfp->sp, iseq->local_size);
 
@@ -490,11 +475,6 @@
 {
     VALUE envval;
 
-    if (VM_FRAME_TYPE(cfp) == VM_FRAME_MAGIC_FINISH) {
-	/* for method_missing */
-	cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp);
-    }
-
     envval = vm_make_env_each(th, cfp, cfp->ep, VM_CF_LEP(cfp));
 
     if (PROCDEBUG) {
@@ -609,8 +589,6 @@
 	int type = block_proc_is_lambda(block->proc) ?
 	  VM_FRAME_MAGIC_LAMBDA : VM_FRAME_MAGIC_BLOCK;
 
-	rb_vm_set_finish_env(th);
-
 	cfp = th->cfp;
 	CHECK_STACK_OVERFLOW(cfp, argc + iseq->stack_max);
 
@@ -621,7 +599,7 @@
 	opt_pc = vm_yield_setup_args(th, iseq, argc, cfp->sp, blockptr,
 				     type == VM_FRAME_MAGIC_LAMBDA);
 
-	ncfp = vm_push_frame(th, iseq, type,
+	ncfp = vm_push_frame(th, iseq, type | VM_FRAME_FLAG_FINISH,
 			     self, VM_ENVVAL_PREV_EP_PTR(block->ep),
 			     iseq->iseq_encoded + opt_pc, cfp->sp + arg_size, iseq->local_size - arg_size);
 	ncfp->me = th->passed_me;
@@ -1027,7 +1005,6 @@
       case VM_FRAME_MAGIC_BLOCK:  return "block";
       case VM_FRAME_MAGIC_CLASS:  return "class";
       case VM_FRAME_MAGIC_TOP:    return "top";
-      case VM_FRAME_MAGIC_FINISH: return "finish";
       case VM_FRAME_MAGIC_CFUNC:  return "cfunc";
       case VM_FRAME_MAGIC_PROC:   return "proc";
       case VM_FRAME_MAGIC_IFUNC:  return "ifunc";
@@ -1186,7 +1163,7 @@
 
 	    if (cfp->ep == escape_ep) {
 		if (state == TAG_RETURN) {
-		    if ((cfp + 1)->pc != &finish_insn_seq[0]) {
+		    if (!VM_FRAME_TYPE_FINISH_P(cfp)) {
 			SET_THROWOBJ_CATCH_POINT(err, (VALUE)(cfp + 1)->ep);
 			SET_THROWOBJ_STATE(err, state = TAG_BREAK);
 		    }
@@ -1205,7 +1182,7 @@
 			if (!catch_iseqval) {
 			    result = GET_THROWOBJ_VAL(err);
 			    th->errinfo = Qnil;
-			    th->cfp += 2;
+			    vm_pop_frame(th);
 			    goto finish_vme;
 			}
 		    }
@@ -1349,17 +1326,16 @@
 		break;
 	    }
 
-	    th->cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(th->cfp);
-
-	    if (VM_FRAME_TYPE(th->cfp) != VM_FRAME_MAGIC_FINISH) {
-		goto exception_handler;
-	    }
-	    else {
+	    if (VM_FRAME_TYPE_FINISH_P(th->cfp)) {
 		vm_pop_frame(th);
 		th->errinfo = err;
 		TH_POP_TAG2();
 		JUMP_TAG(state);
 	    }
+	    else {
+		th->cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(th->cfp);
+		goto exception_handler;
+	    }
 	}
     }
   finish_vme:
@@ -1464,7 +1440,7 @@
     volatile VALUE iseqval = rb_iseq_new(0, filename, filename, Qnil, 0, ISEQ_TYPE_TOP);
     VALUE val;
 
-    vm_push_frame(th, DATA_PTR(iseqval), VM_FRAME_MAGIC_TOP,
+    vm_push_frame(th, DATA_PTR(iseqval), VM_FRAME_MAGIC_TOP | VM_FRAME_FLAG_FINISH,
 		  recv, VM_ENVVAL_BLOCK_PTR(blockptr), 0, reg_cfp->sp, 1);
 
     val = (*func)(arg);
@@ -1808,8 +1784,8 @@
 
     th->cfp = (void *)(th->stack + th->stack_size);
 
-    vm_push_frame(th, 0 /* dummy iseq */, VM_FRAME_MAGIC_TOP, Qnil /* dummy self */,
-		  VM_ENVVAL_BLOCK_PTR(0), 0 /* dummy pc */, th->stack, 1);
+    vm_push_frame(th, 0 /* dummy iseq */, VM_FRAME_MAGIC_TOP | VM_FRAME_FLAG_FINISH,
+		  Qnil /* dummy self */, VM_ENVVAL_BLOCK_PTR(0), 0 /* dummy pc */, th->stack, 1);
 
     th->status = THREAD_RUNNABLE;
     th->errinfo = Qnil;
Index: vm_dump.c
===================================================================
--- vm_dump.c	(revision 36098)
+++ vm_dump.c	(revision 36099)
@@ -32,7 +32,6 @@
     char ep_in_heap = ' ';
     char posbuf[MAX_POSBUF+1];
     int line = 0;
-    int nopos = 0;
 
     const char *magic, *iseq_name = "-", *selfstr = "-", *biseq_name = "-";
     VALUE tmp;
@@ -62,10 +61,6 @@
       case VM_FRAME_MAGIC_BLOCK:
 	magic = "BLOCK";
 	break;
-      case VM_FRAME_MAGIC_FINISH:
-	magic = "FINISH";
-	nopos = 1;
-	break;
       case VM_FRAME_MAGIC_CFUNC:
 	magic = "CFUNC";
 	break;
@@ -97,10 +92,7 @@
 	selfstr = "";
     }
 
-    if (nopos) {
-	/* no name */
-    }
-    else if (cfp->iseq != 0) {
+    if (cfp->iseq != 0) {
 	if (RUBY_VM_IFUNC_P(cfp->iseq)) {
 	    iseq_name = "<ifunc>";
 	}
@@ -130,9 +122,12 @@
     fprintf(stderr, "s:%04"PRIdPTRDIFF" b:%04"PRIdPTRDIFF" ", (cfp->sp - th->stack), bp);
     fprintf(stderr, ep_in_heap == ' ' ? "e:%06"PRIdPTRDIFF" " : "e:%06"PRIxPTRDIFF" ", ep % 10000);
     fprintf(stderr, "%-6s", magic);
-    if (line && !nopos) {
+    if (line) {
 	fprintf(stderr, " %s", posbuf);
     }
+    if (VM_FRAME_TYPE_FINISH_P(cfp)) {
+	fprintf(stderr, " [FINISH]");
+    }
     if (0) {
 	fprintf(stderr, "              \t");
 	fprintf(stderr, "iseq: %-24s ", iseq_name);
@@ -302,8 +297,8 @@
 		    (ptr - th->stack));
 	}
     }
-    else if (VM_FRAME_TYPE(cfp) == VM_FRAME_MAGIC_FINISH) {
-	if ((th)->stack + (th)->stack_size > (VALUE *)(cfp + 2)) {
+    else if (VM_FRAME_TYPE_FINISH_P(VM_FRAME_TYPE(cfp))) {
+	if ((th)->stack + (th)->stack_size > (VALUE *)(cfp + 1)) {
 	    vm_stack_dump_each(th, cfp + 1);
 	}
 	else {
@@ -350,7 +345,7 @@
 {
     rb_iseq_t *iseq = cfp->iseq;
 
-    if (iseq != 0 && VM_FRAME_TYPE(cfp) != VM_FRAME_MAGIC_FINISH) {
+    if (iseq != 0 && !VM_FRAME_TYPE_FINISH_P(cfp)) {
 	VALUE *seq = iseq->iseq;
 	ptrdiff_t pc = cfp->pc - iseq->iseq_encoded;
 	int i;

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

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