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/