summaryrefslogtreecommitdiff
path: root/vm_eval.c
diff options
context:
space:
mode:
Diffstat (limited to 'vm_eval.c')
-rw-r--r--vm_eval.c46
1 files changed, 34 insertions, 12 deletions
diff --git a/vm_eval.c b/vm_eval.c
index bacf91f5eb..220e7c9681 100644
--- a/vm_eval.c
+++ b/vm_eval.c
@@ -41,19 +41,33 @@ typedef enum call_type {
static VALUE send_internal(int argc, const VALUE *argv, VALUE recv, call_type scope);
static VALUE vm_call0_body(rb_execution_context_t* ec, struct rb_calling_info *calling, const VALUE *argv);
+static VALUE *
+vm_argv_ruby_array(VALUE *av, const VALUE *argv, int *flags, int *argc, int kw_splat)
+{
+ *flags |= VM_CALL_ARGS_SPLAT;
+ VALUE argv_ary = rb_ary_hidden_new(*argc);
+ rb_ary_cat(argv_ary, argv, *argc);
+ *argc = 2;
+ av[0] = argv_ary;
+ if (kw_splat) {
+ av[1] = rb_ary_pop(argv_ary);
+ }
+ else {
+ // Make sure flagged keyword hash passed as regular argument
+ // isn't treated as keywords
+ *flags |= VM_CALL_KW_SPLAT;
+ av[1] = rb_hash_new();
+ }
+ return av;
+}
+
+static inline VALUE vm_call0_cc(rb_execution_context_t *ec, VALUE recv, ID id, int argc, const VALUE *argv, const struct rb_callcache *cc, int kw_splat);
+
VALUE
rb_vm_call0(rb_execution_context_t *ec, VALUE recv, ID id, int argc, const VALUE *argv, const rb_callable_method_entry_t *cme, int kw_splat)
{
- struct rb_calling_info calling = {
- .ci = &VM_CI_ON_STACK(id, kw_splat ? VM_CALL_KW_SPLAT : 0, argc, NULL),
- .cc = &VM_CC_ON_STACK(Qfalse, vm_call_general, {{ 0 }}, cme),
- .block_handler = vm_passed_block_handler(ec),
- .recv = recv,
- .argc = argc,
- .kw_splat = kw_splat,
- };
-
- return vm_call0_body(ec, &calling, argv);
+ const struct rb_callcache cc = VM_CC_ON_STACK(Qfalse, vm_call_general, {{ 0 }}, cme);
+ return vm_call0_cc(ec, recv, id, argc, argv, &cc, kw_splat);
}
VALUE
@@ -73,8 +87,16 @@ rb_vm_call_with_refinements(rb_execution_context_t *ec, VALUE recv, ID id, int a
static inline VALUE
vm_call0_cc(rb_execution_context_t *ec, VALUE recv, ID id, int argc, const VALUE *argv, const struct rb_callcache *cc, int kw_splat)
{
+ int flags = kw_splat ? VM_CALL_KW_SPLAT : 0;
+ VALUE *use_argv = (VALUE *)argv;
+ VALUE av[2];
+
+ if (UNLIKELY(vm_cc_cme(cc)->def->type == VM_METHOD_TYPE_ISEQ && argc > VM_ARGC_STACK_MAX)) {
+ use_argv = vm_argv_ruby_array(av, argv, &flags, &argc, kw_splat);
+ }
+
struct rb_calling_info calling = {
- .ci = &VM_CI_ON_STACK(id, kw_splat ? VM_CALL_KW_SPLAT : 0, argc, NULL),
+ .ci = &VM_CI_ON_STACK(id, flags, argc, NULL),
.cc = cc,
.block_handler = vm_passed_block_handler(ec),
.recv = recv,
@@ -82,7 +104,7 @@ vm_call0_cc(rb_execution_context_t *ec, VALUE recv, ID id, int argc, const VALUE
.kw_splat = kw_splat,
};
- return vm_call0_body(ec, &calling, argv);
+ return vm_call0_body(ec, &calling, use_argv);
}
static VALUE