ruby-changes:61464
From: =E5=8D=9C=E9=83=A8=E6=98=8C=E5=B9=B3 <ko1@a...>
Date: Wed, 3 Jun 2020 16:14:13 +0900 (JST)
Subject: [ruby-changes:61464] 054c2fdfdf (master): vm_invoke_symbol_block: reduce MEMCPY
https://git.ruby-lang.org/ruby.git/commit/?id=054c2fdfdf From 054c2fdfdfe9d43c3ae4ba508bb419c3e9db015f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=8D=9C=E9=83=A8=E6=98=8C=E5=B9=B3?= <shyouhei@r...> Date: Thu, 28 May 2020 12:33:53 +0900 Subject: vm_invoke_symbol_block: reduce MEMCPY This commit changes the number of calls of MEMCPY from... | send | &:sym -------------------------|-------|------- Symbol already interned | once | twice Symbol not pinned yet | none | once to: | send | &:sym -------------------------|-------|------- Symbol already interned | once | none Symbol not pinned yet | twice | once So it sacrifices exceptional situation for normal path. diff --git a/vm_insnhelper.c b/vm_insnhelper.c index 3a19a45..a60ac2e 100644 --- a/vm_insnhelper.c +++ b/vm_insnhelper.c @@ -2672,15 +2672,74 @@ ci_missing_reason(const struct rb_callinfo *ci) https://github.com/ruby/ruby/blob/trunk/vm_insnhelper.c#L2672 } static VALUE +vm_call_symbol( + rb_execution_context_t *ec, rb_control_frame_t *reg_cfp, + struct rb_calling_info *calling, const struct rb_callinfo *ci, + VALUE symbol) +{ + ASSUME(calling->argc >= 0); + /* Also assumes CALLER_SETUP_ARG is already done. */ + enum method_missing_reason missing_reason = MISSING_NOENTRY; + int argc = calling->argc; + VALUE recv = calling->recv; + VALUE klass = CLASS_OF(recv); + ID mid = rb_check_id(&symbol); + int flags = VM_CALL_FCALL | + VM_CALL_OPT_SEND | + (calling->kw_splat ? VM_CALL_KW_SPLAT : 0); + if (UNLIKELY(! mid)) { + mid = idMethodMissing; + missing_reason = ci_missing_reason(ci); + ec->method_missing_reason = missing_reason; + /* E.g. when argc == 2 + * + * | | | | TOPN + * | | +------+ + * | | +---> | arg1 | 0 + * +------+ | +------+ + * | arg1 | -+ +-> | arg0 | 1 + * +------+ | +------+ + * | arg0 | ---+ | sym | 2 + * +------+ +------+ + * | recv | | recv | 3 + * --+------+--------+------+------ + */ + int i = argc; + INC_SP(1); + MEMMOVE(&TOPN(i - 1), &TOPN(i), VALUE, i); + argc = ++calling->argc; + if (rb_method_basic_definition_p(klass, idMethodMissing)) { + /* Inadvertent symbol creation shall be forbidden, see [Feature #5112] */ + TOPN(i) = symbol; + int priv = vm_ci_flag(ci) & (VM_CALL_FCALL | VM_CALL_VCALL); + const VALUE *argv = STACK_ADDR_FROM_TOP(argc); + VALUE exc = rb_make_no_method_exception( + rb_eNoMethodError, 0, recv, argc, argv, priv); + rb_exc_raise(exc); + } + else { + TOPN(i) = rb_str_intern(symbol); + } + } + return vm_call_method(ec, reg_cfp, calling, &(struct rb_call_data) { + .ci = vm_ci_new_runtime(mid, flags, argc, vm_ci_kwarg(ci)), + .cc = &(struct rb_callcache) { + .flags = T_IMEMO | (imemo_callcache << FL_USHIFT) | VM_CALLCACHE_UNMARKABLE, + .klass = klass, + .cme_ = rb_callable_method_entry_with_refinements(klass, mid, NULL), + .call_ = 0, + .aux_.method_missing_reason = missing_reason, + }, + }); +} + +static VALUE vm_call_opt_send(rb_execution_context_t *ec, rb_control_frame_t *reg_cfp, struct rb_calling_info *calling, struct rb_call_data *orig_cd) { RB_DEBUG_COUNTER_INC(ccf_opt_send); int i; VALUE sym; - ID mid; - struct rb_call_data cd; - enum method_missing_reason missing_reason = 0; CALLER_SETUP_ARG(reg_cfp, calling, orig_cd->ci); @@ -2689,40 +2748,30 @@ vm_call_opt_send(rb_execution_context_t *ec, rb_control_frame_t *reg_cfp, struct https://github.com/ruby/ruby/blob/trunk/vm_insnhelper.c#L2748 if (calling->argc == 0) { rb_raise(rb_eArgError, "no method name given"); } - - sym = TOPN(i); - - if (!(mid = rb_check_id(&sym))) { - if (rb_method_basic_definition_p(CLASS_OF(calling->recv), idMethodMissing)) { - VALUE exc = - rb_make_no_method_exception(rb_eNoMethodError, 0, calling->recv, - rb_long2int(calling->argc), &TOPN(i), - vm_ci_flag(orig_cd->ci) & (VM_CALL_FCALL|VM_CALL_VCALL)); - rb_exc_raise(exc); - } - TOPN(i) = rb_str_intern(sym); - mid = idMethodMissing; - missing_reason = ci_missing_reason(orig_cd->ci); - ec->method_missing_reason = missing_reason; - } else { + sym = TOPN(i); + /* E.g. when i == 2 + * + * | | | | TOPN + * +------+ | | + * | arg1 | ---+ | | 0 + * +------+ | +------+ + * | arg0 | -+ +-> | arg1 | 1 + * +------+ | +------+ + * | sym | +---> | arg0 | 2 + * +------+ +------+ + * | recv | | recv | 3 + * --+------+--------+------+------ + */ /* shift arguments */ if (i > 0) { MEMMOVE(&TOPN(i), &TOPN(i-1), VALUE, i); } calling->argc -= 1; DEC_SP(1); - } - unsigned int new_flag = VM_CALL_FCALL | VM_CALL_OPT_SEND | (calling->kw_splat ? VM_CALL_KW_SPLAT : 0); - cd.ci = vm_ci_new_runtime(mid, new_flag, 0 /* not accessed (calling->argc is used) */, vm_ci_kwarg(orig_cd->ci)); - struct rb_callcache cc_body; - cd.cc = vm_cc_fill(&cc_body, - Qundef, - rb_callable_method_entry_with_refinements(CLASS_OF(calling->recv), mid, NULL), - 0); - if (missing_reason != 0) vm_cc_method_missing_reason_set(cd.cc, missing_reason); - return vm_call_method(ec, reg_cfp, calling, (CALL_DATA)&cd); + return vm_call_symbol(ec, reg_cfp, calling, orig_cd->ci, sym); + } } static inline VALUE vm_invoke_block(rb_execution_context_t *ec, rb_control_frame_t *reg_cfp, struct rb_calling_info *calling, const struct rb_callinfo *ci, bool is_lambda, VALUE block_handler); @@ -3412,39 +3461,15 @@ vm_invoke_symbol_block(rb_execution_context_t *ec, rb_control_frame_t *reg_cfp, https://github.com/ruby/ruby/blob/trunk/vm_insnhelper.c#L3461 struct rb_calling_info *calling, const struct rb_callinfo *ci, MAYBE_UNUSED(bool is_lambda), VALUE block_handler) { - int argc = calling->argc; - - if (argc < 1) { + if (calling->argc < 1) { rb_raise(rb_eArgError, "no receiver given"); } - else if (argc > 1) { - /* E.g. when argc == 3 - * - * | | | | TOPN - * | | +------+ - * | | +---> | arg1 | -1 - * +------+ | +------+ - * | arg1 | -+ +-> | arg0 | 0 - * +------+ | +------+ - * | arg0 | ---+ | BH | 1 - * +------+ +------+ - * | recv | | recv | 2 - * --+------+--------+------+------ - * - * INC_SP is done immediately below. - */ - MEMMOVE(&TOPN(argc - 3), &TOPN(argc - 2), VALUE, argc - 1); + else { + VALUE symbol = VM_BH_TO_SYMBOL(block_handler); + CALLER_SETUP_ARG(reg_cfp, calling, ci); + calling->recv = TOPN(--calling->argc); + return vm_call_symbol(ec, reg_cfp, calling, ci, symbol); } - - TOPN(argc - 2) = VM_BH_TO_SYMBOL(block_handler); - calling->recv = TOPN(argc - 1); - INC_SP(1); - return vm_call_opt_send(ec, reg_cfp, calling, - &(struct rb_call_data) { - .ci = ci, - .cc = NULL, - } - ); } static VALUE -- cgit v0.10.2 -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/