summaryrefslogtreecommitdiff
path: root/vm_insnhelper.c
diff options
context:
space:
mode:
author卜部昌平 <shyouhei@ruby-lang.org>2020-05-27 22:36:12 +0900
committer卜部昌平 <shyouhei@ruby-lang.org>2020-06-03 16:13:47 +0900
commit36322942dbce6dedaf67626b152dbf893d42e082 (patch)
treef8cbfb11b6211925670f9bb6fd591a8469e41f73 /vm_insnhelper.c
parent973883aaa16bde8ba41caceb56569b52adb4c74f (diff)
downloadruby-36322942dbce6dedaf67626b152dbf893d42e082.tar.gz
vm_invoke_symbol_block: call vm_call_opt_send
Symbol#to_proc and Object#send are closely related each other. Why not share their implementations. By doing so we can skip recursive call of vm_exec(), which could benefit for speed.
Diffstat (limited to 'vm_insnhelper.c')
-rw-r--r--vm_insnhelper.c41
1 files changed, 33 insertions, 8 deletions
diff --git a/vm_insnhelper.c b/vm_insnhelper.c
index baf682ba85..3a19a45783 100644
--- a/vm_insnhelper.c
+++ b/vm_insnhelper.c
@@ -3412,14 +3412,39 @@ vm_invoke_symbol_block(rb_execution_context_t *ec, rb_control_frame_t *reg_cfp,
struct rb_calling_info *calling, const struct rb_callinfo *ci,
MAYBE_UNUSED(bool is_lambda), VALUE block_handler)
{
- VALUE val;
- int argc;
- VALUE symbol = VM_BH_TO_SYMBOL(block_handler);
- CALLER_SETUP_ARG(ec->cfp, calling, ci);
- argc = calling->argc;
- val = vm_yield_with_symbol(ec, symbol, argc, STACK_ADDR_FROM_TOP(argc), calling->kw_splat, calling->block_handler);
- POPN(argc);
- return val;
+ int argc = calling->argc;
+
+ if (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);
+ }
+
+ 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