pub(crate) fn gen_send(
        &mut self,
        globals: &mut Globals,
        iseq: &mut ISeq,
        receiver: Node,
        method: IdentId,
        arglist: ArgList,
        safe_nav: bool,
        use_value: bool,
        loc: Loc,
    ) -> Result<(), RubyError> {
        // push receiver.
        if NodeKind::SelfValue == receiver.kind {
            iseq.gen_push_self();
        } else {
            self.gen(globals, iseq, receiver.clone(), true)?;
        }
        //let loc = self.loc;
        let delegate_flag = arglist.delegate;
        let hash_len = arglist.hash_splat.len();
        // push positional args.
        let args_num = arglist.args.len();
        let splat_flag = self.gen_nodes_check_splat(globals, iseq, arglist.args)?;
        // push keyword args as a Hash.
        let kw_args_len = arglist.kw_args.len();
        let kw_flag = kw_args_len != 0;
        if kw_flag {
            for (id, default) in arglist.kw_args {
                iseq.gen_val(Value::symbol(id));
                self.gen(globals, iseq, default, true)?;
            }
            iseq.gen_create_hash(kw_args_len);
        }
        // push double splat args.
        if hash_len > 0 {
            for arg in arglist.hash_splat {
                self.gen(globals, iseq, arg, true)?;
            }
            iseq.gen_create_array(hash_len);
        }
        let (block_ref, block_flag) = self.get_block(globals, iseq, arglist.block)?;
        // If the method call without block nor keyword/block/splat/double splat arguments, gen OPT_SEND.
        if !block_flag && !kw_flag && !splat_flag && hash_len == 0 && !delegate_flag {
            if safe_nav {
                iseq.gen_dup(1);
                iseq.gen_push_nil();
                iseq.push(Inst::NE);
                let src = iseq.gen_jmp_if_f();
                self.emit_opt_send(globals, iseq, method, args_num, block_ref, use_value, loc);
                iseq.write_disp_from_cur(src);
            } else {
                self.emit_opt_send(globals, iseq, method, args_num, block_ref, use_value, loc);
            }
        } else {
            let flag = ArgFlag::new(kw_flag, block_flag, delegate_flag, hash_len > 0, splat_flag);
            self.emit_send(globals, iseq, method, args_num, flag, block_ref, loc);

            if !use_value {
                iseq.gen_pop()
            };
        }

        Ok(())
    }
Stack layout of arguments

+------+------+------+--+------+------+------+-------+
| self | arg0 | args |..| argn |  kw  |hashsp| block |
+------+------+------+--+------+------+------+-------+

argx:   arguments
kw:     [optional] keyword arguments (Hash object)
hashsp: [optional] hash splat arguments (Array of Hash object)
block:  [optional] block argument
ruruby/src/codegen/send.rs