aboutsummaryrefslogtreecommitdiffstats
path: root/vm_insnhelper.c
diff options
context:
space:
mode:
authorJeremy Evans <code@jeremyevans.net>2023-04-02 11:28:01 -0700
committerJeremy Evans <code@jeremyevans.net>2023-04-25 08:06:16 -0700
commita82a24ed575c5f97b3755317f1a3bd6c9149a67e (patch)
treec057d758345149b10148829eb49cf95bf76dbfbc /vm_insnhelper.c
parent583e9d24d419023bc1123190768297a468113613 (diff)
downloadruby-a82a24ed575c5f97b3755317f1a3bd6c9149a67e.tar.gz
Optimize method_missing calls
CALLER_ARG_SPLAT is not necessary for method_missing. We just need to unshift the method name into the arguments. This optimizes all method_missing calls: * mm(recv) ~9% * mm(recv, *args) ~215% for args.length == 200 * mm(recv, *args, **kw) ~55% for args.length == 200 * mm(recv, **kw) ~22% * mm(recv, kw: 1) ~100% Note that empty argument splats do get slower with this approach, by about 30-40%. Other than non-empty argument splats, other argument splats are faster, with the speedup depending on the number of arguments.
Diffstat (limited to 'vm_insnhelper.c')
-rw-r--r--vm_insnhelper.c28
1 files changed, 9 insertions, 19 deletions
diff --git a/vm_insnhelper.c b/vm_insnhelper.c
index 362ac7dcb2..917333d248 100644
--- a/vm_insnhelper.c
+++ b/vm_insnhelper.c
@@ -4006,27 +4006,17 @@ vm_call_method_missing_body(rb_execution_context_t *ec, rb_control_frame_t *reg_
VALUE *argv = STACK_ADDR_FROM_TOP(calling->argc);
unsigned int argc, flag;
- CALLER_SETUP_ARG(reg_cfp, calling, orig_ci, ALLOW_HEAP_ARGV);
- if (UNLIKELY(calling->heap_argv)) {
- flag = VM_CALL_ARGS_SPLAT | VM_CALL_FCALL | VM_CALL_OPT_SEND | (calling->kw_splat ? VM_CALL_KW_SPLAT : 0);
- argc = 1;
- rb_ary_unshift(calling->heap_argv, ID2SYM(vm_ci_mid(orig_ci)));
- }
- else {
- argc = calling->argc + 1;
+ flag = VM_CALL_FCALL | VM_CALL_OPT_SEND | vm_ci_flag(orig_ci);
+ argc = ++calling->argc;
- flag = VM_CALL_FCALL | VM_CALL_OPT_SEND | (calling->kw_splat ? VM_CALL_KW_SPLAT : 0);
- calling->argc = argc;
-
- /* shift arguments: m(a, b, c) #=> method_missing(:m, a, b, c) */
- CHECK_VM_STACK_OVERFLOW(reg_cfp, 1);
- vm_check_canary(ec, reg_cfp->sp);
- if (argc > 1) {
- MEMMOVE(argv+1, argv, VALUE, argc-1);
- }
- argv[0] = ID2SYM(vm_ci_mid(orig_ci));
- INC_SP(1);
+ /* shift arguments: m(a, b, c) #=> method_missing(:m, a, b, c) */
+ CHECK_VM_STACK_OVERFLOW(reg_cfp, 1);
+ vm_check_canary(ec, reg_cfp->sp);
+ if (argc > 1) {
+ MEMMOVE(argv+1, argv, VALUE, argc-1);
}
+ argv[0] = ID2SYM(vm_ci_mid(orig_ci));
+ INC_SP(1);
ec->method_missing_reason = reason;
calling->ci = &VM_CI_ON_STACK(idMethodMissing, flag, argc, vm_ci_kwarg(orig_ci));