summaryrefslogtreecommitdiff
path: root/vm_args.c
diff options
context:
space:
mode:
authorKoichi Sasada <ko1@atdot.net>2023-01-13 17:52:59 +0900
committerKoichi Sasada <ko1@atdot.net>2023-03-06 15:03:06 +0900
commite87d0882910001ef3b0c2ccd43bf00cee8c34a0c (patch)
tree85a4cab782f6660530e100117183e0cd7d583130 /vm_args.c
parent0463c5806ac63bbd082f4abb1e3ceeae6ffc39ce (diff)
downloadruby-e87d0882910001ef3b0c2ccd43bf00cee8c34a0c.tar.gz
Change bytecode of `f(*a, **kw)`
`f(*a, **kw)` is compiled to `f([*a, kw])` but it makes an dummy array, so change it to pass two arguments `a` and `kw` with calling flags. ``` ruby 3.2.0 (2022-12-29 revision a7d467a792) [x86_64-linux] Calculating ------------------------------------- foo() 15.354M (± 4.2%) i/s - 77.295M in 5.043650s dele() 13.439M (± 3.9%) i/s - 67.109M in 5.001974s dele(*) 6.265M (± 4.5%) i/s - 31.730M in 5.075649s dele(*a) 6.286M (± 3.3%) i/s - 31.719M in 5.051516s dele(*a, **kw) 1.926M (± 4.5%) i/s - 9.753M in 5.076487s dele(*, **) 1.927M (± 4.2%) i/s - 9.710M in 5.048224s dele(...) 5.871M (± 3.9%) i/s - 29.471M in 5.028023s forwardable 4.969M (± 4.1%) i/s - 25.233M in 5.087498s ruby 3.3.0dev (2023-01-13T01:28:00Z master 7e8802fa5b) [x86_64-linux] Calculating ------------------------------------- foo() 16.354M (± 4.7%) i/s - 81.799M in 5.014561s dele() 14.256M (± 3.5%) i/s - 71.656M in 5.032883s dele(*) 6.701M (± 3.8%) i/s - 33.948M in 5.074938s dele(*a) 6.681M (± 3.3%) i/s - 33.578M in 5.031720s dele(*a, **kw) 4.200M (± 4.4%) i/s - 21.258M in 5.072583s dele(*, **) 4.197M (± 5.3%) i/s - 21.322M in 5.096684s dele(...) 6.039M (± 6.8%) i/s - 30.355M in 5.052662s forwardable 4.788M (± 3.2%) i/s - 24.033M in 5.024875s ```
Diffstat (limited to 'vm_args.c')
-rw-r--r--vm_args.c128
1 files changed, 55 insertions, 73 deletions
diff --git a/vm_args.c b/vm_args.c
index 0197109b03..44de015540 100644
--- a/vm_args.c
+++ b/vm_args.c
@@ -440,9 +440,10 @@ ignore_keyword_hash_p(VALUE keyword_hash, const rb_iseq_t * const iseq, unsigned
if (!RB_TYPE_P(keyword_hash, T_HASH)) {
keyword_hash = rb_to_hash_type(keyword_hash);
}
+
if (!(*kw_flag & VM_CALL_KW_SPLAT_MUT) &&
- (ISEQ_BODY(iseq)->param.flags.has_kwrest ||
- ISEQ_BODY(iseq)->param.flags.ruby2_keywords)) {
+ (ISEQ_BODY(iseq)->param.flags.has_kwrest ||
+ ISEQ_BODY(iseq)->param.flags.ruby2_keywords)) {
*kw_flag |= VM_CALL_KW_SPLAT_MUT;
keyword_hash = rb_hash_dup(keyword_hash);
}
@@ -520,54 +521,78 @@ setup_parameters_complex(rb_execution_context_t * const ec, const rb_iseq_t * co
args->kw_argv = NULL;
}
- if (vm_ci_flag(ci) & VM_CALL_ARGS_SPLAT) {
- int len;
+ if ((vm_ci_flag(ci) & VM_CALL_ARGS_SPLAT) && (vm_ci_flag(ci) & VM_CALL_KW_SPLAT)) {
+ // f(*a, **kw)
+ args->rest_index = 0;
+ keyword_hash = locals[--args->argc];
args->rest = locals[--args->argc];
+
+ if (ignore_keyword_hash_p(keyword_hash, iseq, &kw_flag, &converted_keyword_hash)) {
+ keyword_hash = Qnil;
+ }
+ else if (UNLIKELY(ISEQ_BODY(iseq)->param.flags.ruby2_keywords)) {
+ flag_keyword_hash = keyword_hash;
+ rb_ary_push(args->rest, keyword_hash);
+ keyword_hash = Qnil;
+ }
+ else if (!ISEQ_BODY(iseq)->param.flags.has_kwrest && !ISEQ_BODY(iseq)->param.flags.has_kw) {
+ rb_ary_push(args->rest, keyword_hash);
+ keyword_hash = Qnil;
+ }
+
+ int len = RARRAY_LENINT(args->rest);
+ given_argc += len - 2;
+ }
+ else if (vm_ci_flag(ci) & VM_CALL_ARGS_SPLAT) {
+ // f(*a)
args->rest_index = 0;
- len = RARRAY_LENINT(args->rest);
+ args->rest = locals[--args->argc];
+ int len = RARRAY_LENINT(args->rest);
given_argc += len - 1;
rest_last = RARRAY_AREF(args->rest, len - 1);
if (!kw_flag && len > 0) {
if (RB_TYPE_P(rest_last, T_HASH) &&
(((struct RHash *)rest_last)->basic.flags & RHASH_PASS_AS_KEYWORDS)) {
+ // def f(**kw); a = [..., kw]; g(*a)
splat_flagged_keyword_hash = rest_last;
rest_last = rb_hash_dup(rest_last);
kw_flag |= VM_CALL_KW_SPLAT | VM_CALL_KW_SPLAT_MUT;
- }
- else {
- rest_last = 0;
- }
- }
- if (kw_flag & VM_CALL_KW_SPLAT) {
- if (ignore_keyword_hash_p(rest_last, iseq, &kw_flag, &converted_keyword_hash)) {
- arg_rest_dup(args);
- rb_ary_pop(args->rest);
- given_argc--;
- kw_flag &= ~(VM_CALL_KW_SPLAT | VM_CALL_KW_SPLAT_MUT);
- }
- else {
- if (rest_last != converted_keyword_hash) {
- rest_last = converted_keyword_hash;
- arg_rest_dup(args);
- RARRAY_ASET(args->rest, len - 1, rest_last);
- }
-
- if (ISEQ_BODY(iseq)->param.flags.ruby2_keywords && rest_last) {
- flag_keyword_hash = rest_last;
- }
- else if (ISEQ_BODY(iseq)->param.flags.has_kw || ISEQ_BODY(iseq)->param.flags.has_kwrest) {
+ if (ignore_keyword_hash_p(rest_last, iseq, &kw_flag, &converted_keyword_hash)) {
arg_rest_dup(args);
rb_ary_pop(args->rest);
given_argc--;
- keyword_hash = rest_last;
+ kw_flag &= ~(VM_CALL_KW_SPLAT | VM_CALL_KW_SPLAT_MUT);
+ }
+ else {
+ if (rest_last != converted_keyword_hash) {
+ rest_last = converted_keyword_hash;
+ arg_rest_dup(args);
+ RARRAY_ASET(args->rest, len - 1, rest_last);
+ }
+
+ if (ISEQ_BODY(iseq)->param.flags.ruby2_keywords && rest_last) {
+ flag_keyword_hash = rest_last;
+ }
+ else if (ISEQ_BODY(iseq)->param.flags.has_kw || ISEQ_BODY(iseq)->param.flags.has_kwrest) {
+ arg_rest_dup(args);
+ rb_ary_pop(args->rest);
+ given_argc--;
+ keyword_hash = rest_last;
+ }
}
}
}
+ else {
+ rest_last = 0;
+ }
}
else {
- if (kw_flag & VM_CALL_KW_SPLAT) {
+ args->rest = Qfalse;
+
+ if (args->argc > 0 && (kw_flag & VM_CALL_KW_SPLAT)) {
+ // f(**kw)
VALUE last_arg = args->argv[args->argc-1];
if (ignore_keyword_hash_p(last_arg, iseq, &kw_flag, &converted_keyword_hash)) {
args->argc--;
@@ -590,7 +615,6 @@ setup_parameters_complex(rb_execution_context_t * const ec, const rb_iseq_t * co
}
}
}
- args->rest = Qfalse;
}
if (flag_keyword_hash && RB_TYPE_P(flag_keyword_hash, T_HASH)) {
@@ -778,48 +802,6 @@ argument_kw_error(rb_execution_context_t *ec, const rb_iseq_t *iseq, const char
raise_argument_error(ec, iseq, rb_keyword_error_new(error, keys));
}
-static inline void
-vm_caller_setup_arg_splat(rb_control_frame_t *cfp, struct rb_calling_info *calling)
-{
- int argc = calling->argc;
- VALUE *argv = cfp->sp - argc;
- VALUE ary = argv[argc-1];
-
- vm_check_canary(GET_EC(), cfp->sp);
- cfp->sp--;
-
- if (!NIL_P(ary)) {
- const VALUE *ptr = RARRAY_CONST_PTR_TRANSIENT(ary);
- long len = RARRAY_LEN(ary), i;
-
- CHECK_VM_STACK_OVERFLOW(cfp, len);
-
- for (i = 0; i < len; i++) {
- *cfp->sp++ = ptr[i];
- }
- calling->argc += i - 1;
- }
-}
-
-static inline void
-vm_caller_setup_arg_kw(rb_control_frame_t *cfp, struct rb_calling_info *calling, const struct rb_callinfo *ci)
-{
- const VALUE *const passed_keywords = vm_ci_kwarg(ci)->keywords;
- const int kw_len = vm_ci_kwarg(ci)->keyword_len;
- const VALUE h = rb_hash_new_with_size(kw_len);
- VALUE *sp = cfp->sp;
- int i;
-
- for (i=0; i<kw_len; i++) {
- rb_hash_aset(h, passed_keywords[i], (sp - kw_len)[i]);
- }
- (sp-kw_len)[0] = h;
-
- cfp->sp -= kw_len - 1;
- calling->argc -= kw_len - 1;
- calling->kw_splat = 1;
-}
-
static VALUE
vm_to_proc(VALUE proc)
{