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

ruby-changes:49509

From: ko1 <ko1@a...>
Date: Sat, 6 Jan 2018 02:51:17 +0900 (JST)
Subject: [ruby-changes:49509] ko1:r61624 (trunk): Speedup `Proc#call` [Feature #14318]

ko1	2018-01-06 02:51:10 +0900 (Sat, 06 Jan 2018)

  New Revision: 61624

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

  Log:
    Speedup `Proc#call` [Feature #14318]
    
    * vm_insnhelper.c (vm_call_opt_call): do same process of `yield` instead of
      invoking `Proc`.
    
    * vm_insnhelper.c (vm_invoke_block): invoke given block handler instead of
      using a block handler in the current frame.
      Also do not check blcok handler here (caller should check it).
    
    * insns.def (invokeblock): catch up this fix.

  Modified files:
    trunk/insns.def
    trunk/vm_insnhelper.c
Index: insns.def
===================================================================
--- insns.def	(revision 61623)
+++ insns.def	(revision 61624)
@@ -947,11 +947,18 @@ invokeblock https://github.com/ruby/ruby/blob/trunk/insns.def#L947
 (VALUE val)  // inc += 1 - ci->orig_argc;
 {
     struct rb_calling_info calling;
+    VALUE block_handler;
+
     calling.argc = ci->orig_argc;
     calling.block_handler = VM_BLOCK_HANDLER_NONE;
     calling.recv = Qundef; /* should not be used */
 
-    val = vm_invoke_block(ec, GET_CFP(), &calling, ci);
+    block_handler = VM_CF_BLOCK_HANDLER(GET_CFP());
+    if (block_handler == VM_BLOCK_HANDLER_NONE) {
+	rb_vm_localjump_error("no block given (yield)", Qnil, 0);
+    }
+
+    val = vm_invoke_block(ec, GET_CFP(), &calling, ci, block_handler);
     if (val == Qundef) {
 	RESTORE_REGS();
 	NEXT_INSN();
Index: vm_insnhelper.c
===================================================================
--- vm_insnhelper.c	(revision 61623)
+++ vm_insnhelper.c	(revision 61624)
@@ -2047,22 +2047,19 @@ vm_call_opt_send(rb_execution_context_t https://github.com/ruby/ruby/blob/trunk/vm_insnhelper.c#L2047
     return vm_call_method(ec, reg_cfp, calling, ci, cc);
 }
 
+static VALUE vm_invoke_block(rb_execution_context_t *ec, rb_control_frame_t *reg_cfp, struct rb_calling_info *calling, const struct rb_call_info *ci, VALUE block_handler);
+
 static VALUE
-vm_call_opt_call(rb_execution_context_t *ec, rb_control_frame_t *cfp, struct rb_calling_info *calling, const struct rb_call_info *ci, struct rb_call_cache *cc)
+vm_call_opt_call(rb_execution_context_t *ec, rb_control_frame_t *reg_cfp, struct rb_calling_info *calling, const struct rb_call_info *ci, struct rb_call_cache *cc)
 {
-    rb_proc_t *proc;
-    int argc;
-    VALUE *argv;
+    VALUE procval = calling->recv;
+    int argc = calling->argc;
 
-    CALLER_SETUP_ARG(cfp, calling, ci);
+    /* remove self */
+    if (argc > 0) MEMMOVE(&TOPN(argc), &TOPN(argc-1), VALUE, argc);
+    DEC_SP(1);
 
-    argc = calling->argc;
-    argv = ALLOCA_N(VALUE, argc);
-    GetProcPtr(calling->recv, proc);
-    MEMCPY(argv, cfp->sp - argc, VALUE, argc);
-    cfp->sp -= argc + 1;
-
-    return rb_vm_invoke_proc(ec, proc, argc, argv, calling->block_handler);
+    return vm_invoke_block(ec, reg_cfp, calling, ci, VM_BH_FROM_PROC(procval));
 }
 
 static VALUE
@@ -2654,7 +2651,7 @@ vm_invoke_symbol_block(rb_execution_cont https://github.com/ruby/ruby/blob/trunk/vm_insnhelper.c#L2651
     int argc;
     CALLER_SETUP_ARG(ec->cfp, calling, ci);
     argc = calling->argc;
-    val = vm_yield_with_symbol(ec, symbol, argc, STACK_ADDR_FROM_TOP(argc), VM_BLOCK_HANDLER_NONE);
+    val = vm_yield_with_symbol(ec, symbol, argc, STACK_ADDR_FROM_TOP(argc), calling->block_handler);
     POPN(argc);
     return val;
 }
@@ -2668,7 +2665,7 @@ vm_invoke_ifunc_block(rb_execution_conte https://github.com/ruby/ruby/blob/trunk/vm_insnhelper.c#L2665
     int argc;
     CALLER_SETUP_ARG(ec->cfp, calling, ci);
     argc = calling->argc;
-    val = vm_yield_with_cfunc(ec, captured, captured->self, argc, STACK_ADDR_FROM_TOP(argc), VM_BLOCK_HANDLER_NONE);
+    val = vm_yield_with_cfunc(ec, captured, captured->self, argc, STACK_ADDR_FROM_TOP(argc), calling->block_handler);
     POPN(argc); /* TODO: should put before C/yield? */
     return val;
 }
@@ -2693,17 +2690,10 @@ vm_proc_to_block_handler(VALUE procval) https://github.com/ruby/ruby/blob/trunk/vm_insnhelper.c#L2690
 }
 
 static VALUE
-vm_invoke_block(rb_execution_context_t *ec, rb_control_frame_t *reg_cfp, struct rb_calling_info *calling, const struct rb_call_info *ci)
+vm_invoke_block(rb_execution_context_t *ec, rb_control_frame_t *reg_cfp, struct rb_calling_info *calling, const struct rb_call_info *ci, VALUE block_handler)
 {
-    VALUE block_handler = VM_CF_BLOCK_HANDLER(reg_cfp);
-    VALUE type = GET_ISEQ()->body->local_iseq->body->type;
     int is_lambda = FALSE;
 
-    if ((type != ISEQ_TYPE_METHOD && type != ISEQ_TYPE_CLASS) ||
-	block_handler == VM_BLOCK_HANDLER_NONE) {
-	rb_vm_localjump_error("no block given (yield)", Qnil, 0);
-    }
-
   again:
     switch (vm_block_handler_type(block_handler)) {
       case block_handler_type_iseq:

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

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