1 /**********************************************************************
3 vm_args.c - process method call arguments.
7 Copyright (C) 2014- Yukihiro Matsumoto
9 **********************************************************************/
11 NORETURN(static void raise_argument_error(rb_execution_context_t
*ec
, const rb_iseq_t
*iseq
, const VALUE exc
));
12 NORETURN(static void argument_arity_error(rb_execution_context_t
*ec
, const rb_iseq_t
*iseq
, const int miss_argc
, const int min_argc
, const int max_argc
));
13 NORETURN(static void argument_kw_error(rb_execution_context_t
*ec
, const rb_iseq_t
*iseq
, const char *error
, const VALUE keys
));
14 VALUE
rb_keyword_error_new(const char *error
, VALUE keys
); /* class.c */
15 static VALUE
method_missing(rb_execution_context_t
*ec
, VALUE obj
, ID id
, int argc
, const VALUE
*argv
,
16 enum method_missing_reason call_status
, int kw_splat
);
17 const rb_callable_method_entry_t
*rb_resolve_refined_method_callable(VALUE refinements
, const rb_callable_method_entry_t
*me
);
24 /* additional args info */
27 const struct rb_callinfo_kwarg
*kw_arg
;
38 arg_rest_dup(struct args_info
*args
)
40 if (!args
->rest_dupped
) {
41 args
->rest
= rb_ary_dup(args
->rest
);
42 args
->rest_dupped
= TRUE
;
47 args_argc(struct args_info
*args
)
49 if (args
->rest
== Qfalse
) {
53 return args
->argc
+ RARRAY_LENINT(args
->rest
) - args
->rest_index
;
58 args_extend(struct args_info
*args
, const int min_argc
)
64 VM_ASSERT(args
->rest_index
== 0);
65 for (i
=args
->argc
+ RARRAY_LENINT(args
->rest
); i
<min_argc
; i
++) {
66 rb_ary_push(args
->rest
, Qnil
);
70 for (i
=args
->argc
; i
<min_argc
; i
++) {
71 args
->argv
[args
->argc
++] = Qnil
;
77 args_reduce(struct args_info
*args
, int over_argc
)
80 const long len
= RARRAY_LEN(args
->rest
);
82 if (len
> over_argc
) {
84 rb_ary_resize(args
->rest
, len
- over_argc
);
93 VM_ASSERT(args
->argc
>= over_argc
);
94 args
->argc
-= over_argc
;
98 args_check_block_arg0(struct args_info
*args
)
102 if (args
->rest
&& RARRAY_LEN(args
->rest
) == 1) {
103 VALUE arg0
= RARRAY_AREF(args
->rest
, 0);
104 ary
= rb_check_array_type(arg0
);
106 else if (args
->argc
== 1) {
107 VALUE arg0
= args
->argv
[0];
108 ary
= rb_check_array_type(arg0
);
109 args
->argv
[0] = arg0
; /* see: https://bugs.ruby-lang.org/issues/8484 */
114 args
->rest_index
= 0;
123 args_copy(struct args_info
*args
)
125 if (args
->rest
!= Qfalse
) {
126 int argc
= args
->argc
;
131 * argv: [m0, m1, m2, m3]
132 * rest: [a0, a1, a2, a3, a4, a5]
139 * rest: [m2, m3, a2, a3, a4, a5]
145 * argv: [] (argc == 0)
146 * rest: [m0, m1, m2, m3, a2, a3, a4, a5]
150 while (args
->rest_index
> 0 && argc
> 0) {
151 RARRAY_ASET(args
->rest
, --args
->rest_index
, args
->argv
[--argc
]);
154 rb_ary_unshift(args
->rest
, args
->argv
[--argc
]);
157 else if (args
->argc
> 0) {
158 args
->rest
= rb_ary_new_from_values(args
->argc
, args
->argv
);
159 args
->rest_index
= 0;
160 args
->rest_dupped
= TRUE
;
165 static inline const VALUE
*
166 args_rest_argv(struct args_info
*args
)
168 return RARRAY_CONST_PTR(args
->rest
) + args
->rest_index
;
172 args_rest_array(struct args_info
*args
)
177 ary
= rb_ary_behead(args
->rest
, args
->rest_index
);
178 args
->rest_index
= 0;
188 args_kw_argv_to_hash(struct args_info
*args
)
190 const struct rb_callinfo_kwarg
*kw_arg
= args
->kw_arg
;
191 const VALUE
*const passed_keywords
= kw_arg
->keywords
;
192 const int kw_len
= kw_arg
->keyword_len
;
193 VALUE h
= rb_hash_new_with_size(kw_len
);
194 const int kw_start
= args
->argc
- kw_len
;
195 const VALUE
* const kw_argv
= args
->argv
+ kw_start
;
198 args
->argc
= kw_start
+ 1;
199 for (i
=0; i
<kw_len
; i
++) {
200 rb_hash_aset(h
, passed_keywords
[i
], kw_argv
[i
]);
203 args
->argv
[args
->argc
- 1] = h
;
209 args_setup_lead_parameters(struct args_info
*args
, int argc
, VALUE
*locals
)
211 if (args
->argc
>= argc
) {
218 const VALUE
*argv
= args_rest_argv(args
);
220 for (i
=args
->argc
, j
=0; i
<argc
; i
++, j
++) {
223 args
->rest_index
+= argc
- args
->argc
;
229 args_setup_post_parameters(struct args_info
*args
, int argc
, VALUE
*locals
)
232 len
= RARRAY_LEN(args
->rest
);
233 MEMCPY(locals
, RARRAY_CONST_PTR(args
->rest
) + len
- argc
, VALUE
, argc
);
234 rb_ary_resize(args
->rest
, len
- argc
);
238 args_setup_opt_parameters(struct args_info
*args
, int opt_max
, VALUE
*locals
)
242 if (args
->argc
>= opt_max
) {
243 args
->argc
-= opt_max
;
244 args
->argv
+= opt_max
;
253 int len
= RARRAY_LENINT(args
->rest
);
254 const VALUE
*argv
= RARRAY_CONST_PTR(args
->rest
);
256 for (; i
<opt_max
&& args
->rest_index
< len
; i
++, args
->rest_index
++) {
257 locals
[i
] = argv
[args
->rest_index
];
261 /* initialize by nil */
262 for (j
=i
; j
<opt_max
; j
++) {
271 args_setup_rest_parameter(struct args_info
*args
, VALUE
*locals
)
273 *locals
= args_rest_array(args
);
277 make_unknown_kw_hash(const VALUE
*passed_keywords
, int passed_keyword_len
, const VALUE
*kw_argv
)
280 VALUE obj
= rb_ary_hidden_new(1);
282 for (i
=0; i
<passed_keyword_len
; i
++) {
283 if (!UNDEF_P(kw_argv
[i
])) {
284 rb_ary_push(obj
, passed_keywords
[i
]);
291 make_rest_kw_hash(const VALUE
*passed_keywords
, int passed_keyword_len
, const VALUE
*kw_argv
)
294 VALUE obj
= rb_hash_new_with_size(passed_keyword_len
);
296 for (i
=0; i
<passed_keyword_len
; i
++) {
297 if (!UNDEF_P(kw_argv
[i
])) {
298 rb_hash_aset(obj
, passed_keywords
[i
], kw_argv
[i
]);
305 args_setup_kw_parameters_lookup(const ID key
, VALUE
*ptr
, const VALUE
*const passed_keywords
, VALUE
*passed_values
, const int passed_keyword_len
)
308 const VALUE keyname
= ID2SYM(key
);
310 for (i
=0; i
<passed_keyword_len
; i
++) {
311 if (keyname
== passed_keywords
[i
]) {
312 *ptr
= passed_values
[i
];
313 passed_values
[i
] = Qundef
;
321 #define KW_SPECIFIED_BITS_MAX (32-1) /* TODO: 32 -> Fixnum's max bits */
324 args_setup_kw_parameters(rb_execution_context_t
*const ec
, const rb_iseq_t
*const iseq
,
325 VALUE
*const passed_values
, const int passed_keyword_len
, const VALUE
*const passed_keywords
,
328 const ID
*acceptable_keywords
= ISEQ_BODY(iseq
)->param
.keyword
->table
;
329 const int req_key_num
= ISEQ_BODY(iseq
)->param
.keyword
->required_num
;
330 const int key_num
= ISEQ_BODY(iseq
)->param
.keyword
->num
;
331 const VALUE
* const default_values
= ISEQ_BODY(iseq
)->param
.keyword
->default_values
;
333 int i
, di
, found
= 0;
334 int unspecified_bits
= 0;
335 VALUE unspecified_bits_value
= Qnil
;
337 for (i
=0; i
<req_key_num
; i
++) {
338 ID key
= acceptable_keywords
[i
];
339 if (args_setup_kw_parameters_lookup(key
, &locals
[i
], passed_keywords
, passed_values
, passed_keyword_len
)) {
343 if (!missing
) missing
= rb_ary_hidden_new(1);
344 rb_ary_push(missing
, ID2SYM(key
));
348 if (missing
) argument_kw_error(ec
, iseq
, "missing", missing
);
350 for (di
=0; i
<key_num
; i
++, di
++) {
351 if (args_setup_kw_parameters_lookup(acceptable_keywords
[i
], &locals
[i
], passed_keywords
, passed_values
, passed_keyword_len
)) {
355 if (UNDEF_P(default_values
[di
])) {
358 if (LIKELY(i
< KW_SPECIFIED_BITS_MAX
)) {
359 unspecified_bits
|= 0x01 << di
;
362 if (NIL_P(unspecified_bits_value
)) {
365 unspecified_bits_value
= rb_hash_new();
367 for (j
=0; j
<KW_SPECIFIED_BITS_MAX
; j
++) {
368 if (unspecified_bits
& (0x01 << j
)) {
369 rb_hash_aset(unspecified_bits_value
, INT2FIX(j
), Qtrue
);
373 rb_hash_aset(unspecified_bits_value
, INT2FIX(di
), Qtrue
);
377 locals
[i
] = default_values
[di
];
382 if (ISEQ_BODY(iseq
)->param
.flags
.has_kwrest
) {
383 const int rest_hash_index
= key_num
+ 1;
384 locals
[rest_hash_index
] = make_rest_kw_hash(passed_keywords
, passed_keyword_len
, passed_values
);
387 if (found
!= passed_keyword_len
) {
388 VALUE keys
= make_unknown_kw_hash(passed_keywords
, passed_keyword_len
, passed_values
);
389 argument_kw_error(ec
, iseq
, "unknown", keys
);
393 if (NIL_P(unspecified_bits_value
)) {
394 unspecified_bits_value
= INT2FIX(unspecified_bits
);
396 locals
[key_num
] = unspecified_bits_value
;
400 args_setup_kw_parameters_from_kwsplat(rb_execution_context_t
*const ec
, const rb_iseq_t
*const iseq
,
401 VALUE keyword_hash
, VALUE
*const locals
, bool remove_hash_value
)
403 const ID
*acceptable_keywords
= ISEQ_BODY(iseq
)->param
.keyword
->table
;
404 const int req_key_num
= ISEQ_BODY(iseq
)->param
.keyword
->required_num
;
405 const int key_num
= ISEQ_BODY(iseq
)->param
.keyword
->num
;
406 const VALUE
* const default_values
= ISEQ_BODY(iseq
)->param
.keyword
->default_values
;
409 int unspecified_bits
= 0;
410 size_t keyword_size
= RHASH_SIZE(keyword_hash
);
411 VALUE unspecified_bits_value
= Qnil
;
413 for (i
=0; i
<req_key_num
; i
++) {
414 VALUE key
= ID2SYM(acceptable_keywords
[i
]);
416 if (remove_hash_value
) {
417 value
= rb_hash_delete_entry(keyword_hash
, key
);
420 value
= rb_hash_lookup2(keyword_hash
, key
, Qundef
);
423 if (!UNDEF_P(value
)) {
428 if (!missing
) missing
= rb_ary_hidden_new(1);
429 rb_ary_push(missing
, key
);
433 if (missing
) argument_kw_error(ec
, iseq
, "missing", missing
);
435 for (di
=0; i
<key_num
; i
++, di
++) {
436 VALUE key
= ID2SYM(acceptable_keywords
[i
]);
438 if (remove_hash_value
) {
439 value
= rb_hash_delete_entry(keyword_hash
, key
);
442 value
= rb_hash_lookup2(keyword_hash
, key
, Qundef
);
445 if (!UNDEF_P(value
)) {
450 if (UNDEF_P(default_values
[di
])) {
453 if (LIKELY(i
< KW_SPECIFIED_BITS_MAX
)) {
454 unspecified_bits
|= 0x01 << di
;
457 if (NIL_P(unspecified_bits_value
)) {
460 unspecified_bits_value
= rb_hash_new();
462 for (j
=0; j
<KW_SPECIFIED_BITS_MAX
; j
++) {
463 if (unspecified_bits
& (0x01 << j
)) {
464 rb_hash_aset(unspecified_bits_value
, INT2FIX(j
), Qtrue
);
468 rb_hash_aset(unspecified_bits_value
, INT2FIX(di
), Qtrue
);
472 locals
[i
] = default_values
[di
];
477 if (ISEQ_BODY(iseq
)->param
.flags
.has_kwrest
) {
478 const int rest_hash_index
= key_num
+ 1;
479 locals
[rest_hash_index
] = keyword_hash
;
482 if (!remove_hash_value
) {
483 if (keyword_size
!= 0) {
484 /* Recurse with duplicated keyword hash in remove mode.
485 * This is simpler than writing code to check which entries in the hash do not match.
486 * This will raise an exception, so the additional performance impact shouldn't be material.
488 args_setup_kw_parameters_from_kwsplat(ec
, iseq
, rb_hash_dup(keyword_hash
), locals
, true);
491 else if (!RHASH_EMPTY_P(keyword_hash
)) {
492 argument_kw_error(ec
, iseq
, "unknown", rb_hash_keys(keyword_hash
));
496 if (NIL_P(unspecified_bits_value
)) {
497 unspecified_bits_value
= INT2FIX(unspecified_bits
);
499 locals
[key_num
] = unspecified_bits_value
;
503 args_setup_kw_rest_parameter(VALUE keyword_hash
, VALUE
*locals
, int kw_flag
, bool anon_kwrest
)
505 if (NIL_P(keyword_hash
)) {
507 keyword_hash
= rb_hash_new();
510 else if (!(kw_flag
& VM_CALL_KW_SPLAT_MUT
)) {
511 keyword_hash
= rb_hash_dup(keyword_hash
);
513 locals
[0] = keyword_hash
;
517 args_setup_block_parameter(const rb_execution_context_t
*ec
, struct rb_calling_info
*calling
, VALUE
*locals
)
519 VALUE block_handler
= calling
->block_handler
;
520 *locals
= rb_vm_bh_to_procval(ec
, block_handler
);
524 ignore_keyword_hash_p(VALUE keyword_hash
, const rb_iseq_t
* const iseq
, unsigned int * kw_flag
, VALUE
* converted_keyword_hash
)
526 if (keyword_hash
== Qnil
) {
529 else if (!RB_TYPE_P(keyword_hash
, T_HASH
)) {
530 keyword_hash
= rb_to_hash_type(keyword_hash
);
532 else if (UNLIKELY(ISEQ_BODY(iseq
)->param
.flags
.anon_kwrest
)) {
533 if (!ISEQ_BODY(iseq
)->param
.flags
.has_kw
) {
534 *kw_flag
|= VM_CALL_KW_SPLAT_MUT
;
538 if (RHASH_EMPTY_P(keyword_hash
) && !ISEQ_BODY(iseq
)->param
.flags
.has_kwrest
) {
542 if (!(*kw_flag
& VM_CALL_KW_SPLAT_MUT
) &&
543 (ISEQ_BODY(iseq
)->param
.flags
.has_kwrest
||
544 ISEQ_BODY(iseq
)->param
.flags
.ruby2_keywords
)) {
545 *kw_flag
|= VM_CALL_KW_SPLAT_MUT
;
546 keyword_hash
= rb_hash_dup(keyword_hash
);
548 *converted_keyword_hash
= keyword_hash
;
550 if (!(ISEQ_BODY(iseq
)->param
.flags
.has_kw
) &&
551 !(ISEQ_BODY(iseq
)->param
.flags
.has_kwrest
) &&
552 RHASH_EMPTY_P(keyword_hash
)) {
554 *kw_flag
&= ~(VM_CALL_KW_SPLAT
| VM_CALL_KW_SPLAT_MUT
);
563 check_kwrestarg(VALUE keyword_hash
, unsigned int *kw_flag
)
565 if (!(*kw_flag
& VM_CALL_KW_SPLAT_MUT
)) {
566 *kw_flag
|= VM_CALL_KW_SPLAT_MUT
;
567 return rb_hash_dup(keyword_hash
);
575 flatten_rest_args(rb_execution_context_t
* const ec
, struct args_info
*args
, VALUE
* const locals
, unsigned int *ci_flag
)
577 const VALUE
*argv
= RARRAY_CONST_PTR(args
->rest
);
578 int j
, i
=args
->argc
, rest_len
= RARRAY_LENINT(args
->rest
)-1;
579 args
->argc
+= rest_len
;
581 CHECK_VM_STACK_OVERFLOW(ec
->cfp
, rest_len
+1);
582 for (i
, j
=0; rest_len
> 0; rest_len
--, i
++, j
++) {
587 *ci_flag
&= ~VM_CALL_ARGS_SPLAT
;
591 setup_parameters_complex(rb_execution_context_t
* const ec
, const rb_iseq_t
* const iseq
,
592 struct rb_calling_info
*const calling
,
593 const struct rb_callinfo
*ci
,
594 VALUE
* const locals
, const enum arg_setup_type arg_setup_type
)
596 const int min_argc
= ISEQ_BODY(iseq
)->param
.lead_num
+ ISEQ_BODY(iseq
)->param
.post_num
;
597 const int max_argc
= (ISEQ_BODY(iseq
)->param
.flags
.has_rest
== FALSE
) ? min_argc
+ ISEQ_BODY(iseq
)->param
.opt_num
: UNLIMITED_ARGUMENTS
;
599 unsigned int ci_flag
= vm_ci_flag(ci
);
600 unsigned int kw_flag
= ci_flag
& (VM_CALL_KWARG
| VM_CALL_KW_SPLAT
| VM_CALL_KW_SPLAT_MUT
);
601 int opt_pc
= 0, allow_autosplat
= !kw_flag
;
602 struct args_info args_body
, *args
;
603 VALUE keyword_hash
= Qnil
;
604 VALUE
* const orig_sp
= ec
->cfp
->sp
;
606 VALUE flag_keyword_hash
= 0;
607 VALUE splat_flagged_keyword_hash
= 0;
608 VALUE converted_keyword_hash
= 0;
611 vm_check_canary(ec
, orig_sp
);
615 * [pushed values] [uninitialized values]
617 * <- ISEQ_BODY(iseq)->param.size------------>
621 * [pushed values] [initialized values ]
623 * <- ISEQ_BODY(iseq)->param.size------------>
626 for (i
=calling
->argc
; i
<ISEQ_BODY(iseq
)->param
.size
; i
++) {
629 ec
->cfp
->sp
= &locals
[i
];
633 given_argc
= args
->argc
= calling
->argc
;
635 args
->rest_dupped
= ci_flag
& VM_CALL_ARGS_SPLAT_MUT
;
637 if (UNLIKELY(ISEQ_BODY(iseq
)->param
.flags
.anon_rest
)) {
638 if ((ci_flag
& VM_CALL_ARGS_SPLAT
) &&
639 given_argc
== ISEQ_BODY(iseq
)->param
.lead_num
+ (kw_flag
? 2 : 1) &&
640 !ISEQ_BODY(iseq
)->param
.flags
.has_opt
&&
641 !ISEQ_BODY(iseq
)->param
.flags
.has_post
&&
642 !ISEQ_BODY(iseq
)->param
.flags
.ruby2_keywords
&&
644 !ISEQ_BODY(iseq
)->param
.flags
.has_kw
||
645 !ISEQ_BODY(iseq
)->param
.flags
.has_kwrest
||
646 !ISEQ_BODY(iseq
)->param
.flags
.accepts_no_kwarg
)) {
647 args
->rest_dupped
= true;
651 if (kw_flag
& VM_CALL_KWARG
) {
652 args
->kw_arg
= vm_ci_kwarg(ci
);
654 if (ISEQ_BODY(iseq
)->param
.flags
.has_kw
) {
655 int kw_len
= args
->kw_arg
->keyword_len
;
657 args
->kw_argv
= ALLOCA_N(VALUE
, kw_len
);
658 args
->argc
-= kw_len
;
659 given_argc
-= kw_len
;
660 MEMCPY(args
->kw_argv
, locals
+ args
->argc
, VALUE
, kw_len
);
663 args
->kw_argv
= NULL
;
664 given_argc
= args_kw_argv_to_hash(args
);
665 kw_flag
|= VM_CALL_KW_SPLAT
| VM_CALL_KW_SPLAT_MUT
;
670 args
->kw_argv
= NULL
;
673 if ((ci_flag
& VM_CALL_ARGS_SPLAT
) && (ci_flag
& VM_CALL_KW_SPLAT
)) {
675 args
->rest_index
= 0;
676 keyword_hash
= locals
[--args
->argc
];
677 args
->rest
= locals
[--args
->argc
];
679 if (ignore_keyword_hash_p(keyword_hash
, iseq
, &kw_flag
, &converted_keyword_hash
)) {
682 else if (UNLIKELY(ISEQ_BODY(iseq
)->param
.flags
.ruby2_keywords
)) {
683 converted_keyword_hash
= check_kwrestarg(converted_keyword_hash
, &kw_flag
);
684 flag_keyword_hash
= converted_keyword_hash
;
686 rb_ary_push(args
->rest
, converted_keyword_hash
);
689 else if (!ISEQ_BODY(iseq
)->param
.flags
.has_kwrest
&& !ISEQ_BODY(iseq
)->param
.flags
.has_kw
) {
690 converted_keyword_hash
= check_kwrestarg(converted_keyword_hash
, &kw_flag
);
691 if (ISEQ_BODY(iseq
)->param
.flags
.has_rest
) {
693 rb_ary_push(args
->rest
, converted_keyword_hash
);
697 // Avoid duping rest when not necessary
698 // Copy rest elements and converted keyword hash directly to VM stack
699 const VALUE
*argv
= RARRAY_CONST_PTR(args
->rest
);
700 int j
, i
=args
->argc
, rest_len
= RARRAY_LENINT(args
->rest
);
702 CHECK_VM_STACK_OVERFLOW(ec
->cfp
, rest_len
+1);
703 given_argc
+= rest_len
;
704 args
->argc
+= rest_len
;
705 for (j
=0; rest_len
> 0; rest_len
--, i
++, j
++) {
709 locals
[i
] = converted_keyword_hash
;
713 ci_flag
&= ~(VM_CALL_ARGS_SPLAT
|VM_CALL_KW_SPLAT
);
715 goto arg_splat_and_kw_splat_flattened
;
719 keyword_hash
= converted_keyword_hash
;
722 int len
= RARRAY_LENINT(args
->rest
);
723 given_argc
+= len
- 2;
725 else if (ci_flag
& VM_CALL_ARGS_SPLAT
) {
727 args
->rest_index
= 0;
728 args
->rest
= locals
[--args
->argc
];
729 int len
= RARRAY_LENINT(args
->rest
);
730 given_argc
+= len
- 1;
732 if (!kw_flag
&& len
> 0) {
733 rest_last
= RARRAY_AREF(args
->rest
, len
- 1);
734 if (RB_TYPE_P(rest_last
, T_HASH
) && FL_TEST_RAW(rest_last
, RHASH_PASS_AS_KEYWORDS
)) {
735 // def f(**kw); a = [..., kw]; g(*a)
736 splat_flagged_keyword_hash
= rest_last
;
737 if (!(RHASH_EMPTY_P(rest_last
) || ISEQ_BODY(iseq
)->param
.flags
.has_kw
) || (ISEQ_BODY(iseq
)->param
.flags
.has_kwrest
)) {
738 rest_last
= rb_hash_dup(rest_last
);
740 kw_flag
|= VM_CALL_KW_SPLAT
| VM_CALL_KW_SPLAT_MUT
;
742 // Unset rest_dupped set by anon_rest as we may need to modify splat in this case
743 args
->rest_dupped
= false;
745 if (ignore_keyword_hash_p(rest_last
, iseq
, &kw_flag
, &converted_keyword_hash
)) {
746 if (ISEQ_BODY(iseq
)->param
.flags
.has_rest
) {
747 // Only duplicate/modify splat array if it will be used
749 rb_ary_pop(args
->rest
);
751 else if (arg_setup_type
== arg_setup_block
&& !ISEQ_BODY(iseq
)->param
.flags
.has_kwrest
) {
752 // Avoid hash allocation for empty hashes
753 // Copy rest elements except empty keyword hash directly to VM stack
754 flatten_rest_args(ec
, args
, locals
, &ci_flag
);
760 else if (!ISEQ_BODY(iseq
)->param
.flags
.has_rest
) {
761 // Avoid duping rest when not necessary
762 // Copy rest elements and converted keyword hash directly to VM stack
763 flatten_rest_args(ec
, args
, locals
, &ci_flag
);
765 if (ISEQ_BODY(iseq
)->param
.flags
.has_kw
|| ISEQ_BODY(iseq
)->param
.flags
.has_kwrest
) {
767 keyword_hash
= converted_keyword_hash
;
770 locals
[args
->argc
] = converted_keyword_hash
;
777 if (rest_last
!= converted_keyword_hash
) {
778 rest_last
= converted_keyword_hash
;
780 RARRAY_ASET(args
->rest
, len
- 1, rest_last
);
783 if (ISEQ_BODY(iseq
)->param
.flags
.ruby2_keywords
&& rest_last
) {
784 flag_keyword_hash
= rest_last
;
786 else if (ISEQ_BODY(iseq
)->param
.flags
.has_kw
|| ISEQ_BODY(iseq
)->param
.flags
.has_kwrest
) {
788 rb_ary_pop(args
->rest
);
790 keyword_hash
= rest_last
;
799 if (args
->argc
> 0 && (kw_flag
& VM_CALL_KW_SPLAT
)) {
801 VALUE last_arg
= args
->argv
[args
->argc
-1];
802 if (ignore_keyword_hash_p(last_arg
, iseq
, &kw_flag
, &converted_keyword_hash
)) {
807 if (!(kw_flag
& VM_CALL_KW_SPLAT_MUT
) && !ISEQ_BODY(iseq
)->param
.flags
.has_kw
) {
808 converted_keyword_hash
= rb_hash_dup(converted_keyword_hash
);
809 kw_flag
|= VM_CALL_KW_SPLAT_MUT
;
812 if (last_arg
!= converted_keyword_hash
) {
813 last_arg
= converted_keyword_hash
;
814 args
->argv
[args
->argc
-1] = last_arg
;
817 if (ISEQ_BODY(iseq
)->param
.flags
.ruby2_keywords
) {
818 flag_keyword_hash
= last_arg
;
820 else if (ISEQ_BODY(iseq
)->param
.flags
.has_kw
|| ISEQ_BODY(iseq
)->param
.flags
.has_kwrest
) {
823 keyword_hash
= last_arg
;
829 if (flag_keyword_hash
) {
830 FL_SET_RAW(flag_keyword_hash
, RHASH_PASS_AS_KEYWORDS
);
833 arg_splat_and_kw_splat_flattened
:
834 if (kw_flag
&& ISEQ_BODY(iseq
)->param
.flags
.accepts_no_kwarg
) {
835 rb_raise(rb_eArgError
, "no keywords accepted");
838 switch (arg_setup_type
) {
839 case arg_setup_method
:
840 break; /* do nothing special */
841 case arg_setup_block
:
842 if (given_argc
== 1 &&
844 !splat_flagged_keyword_hash
&&
845 (min_argc
> 0 || ISEQ_BODY(iseq
)->param
.opt_num
> 1) &&
846 !ISEQ_BODY(iseq
)->param
.flags
.ambiguous_param0
&&
847 !((ISEQ_BODY(iseq
)->param
.flags
.has_kw
||
848 ISEQ_BODY(iseq
)->param
.flags
.has_kwrest
)
850 args_check_block_arg0(args
)) {
851 given_argc
= RARRAY_LENINT(args
->rest
);
857 if (given_argc
< min_argc
) {
858 if (arg_setup_type
== arg_setup_block
) {
859 CHECK_VM_STACK_OVERFLOW(ec
->cfp
, min_argc
);
860 given_argc
= min_argc
;
861 args_extend(args
, min_argc
);
864 argument_arity_error(ec
, iseq
, given_argc
, min_argc
, max_argc
);
868 if (given_argc
> max_argc
&& max_argc
!= UNLIMITED_ARGUMENTS
) {
869 if (arg_setup_type
== arg_setup_block
) {
871 args_reduce(args
, given_argc
- max_argc
);
872 given_argc
= max_argc
;
875 argument_arity_error(ec
, iseq
, given_argc
, min_argc
, max_argc
);
879 if (ISEQ_BODY(iseq
)->param
.flags
.has_lead
) {
880 args_setup_lead_parameters(args
, ISEQ_BODY(iseq
)->param
.lead_num
, locals
+ 0);
883 if (ISEQ_BODY(iseq
)->param
.flags
.has_rest
|| ISEQ_BODY(iseq
)->param
.flags
.has_post
){
887 if (ISEQ_BODY(iseq
)->param
.flags
.has_post
) {
888 args_setup_post_parameters(args
, ISEQ_BODY(iseq
)->param
.post_num
, locals
+ ISEQ_BODY(iseq
)->param
.post_start
);
891 if (ISEQ_BODY(iseq
)->param
.flags
.has_opt
) {
892 int opt
= args_setup_opt_parameters(args
, ISEQ_BODY(iseq
)->param
.opt_num
, locals
+ ISEQ_BODY(iseq
)->param
.lead_num
);
893 opt_pc
= (int)ISEQ_BODY(iseq
)->param
.opt_table
[opt
];
896 if (ISEQ_BODY(iseq
)->param
.flags
.has_rest
) {
897 args_setup_rest_parameter(args
, locals
+ ISEQ_BODY(iseq
)->param
.rest_start
);
898 VALUE ary
= *(locals
+ ISEQ_BODY(iseq
)->param
.rest_start
);
899 VALUE index
= RARRAY_LEN(ary
) - 1;
900 if (splat_flagged_keyword_hash
&&
901 !ISEQ_BODY(iseq
)->param
.flags
.ruby2_keywords
&&
902 !ISEQ_BODY(iseq
)->param
.flags
.has_kw
&&
903 !ISEQ_BODY(iseq
)->param
.flags
.has_kwrest
&&
904 RARRAY_AREF(ary
, index
) == splat_flagged_keyword_hash
) {
905 ((struct RHash
*)rest_last
)->basic
.flags
&= ~RHASH_PASS_AS_KEYWORDS
;
906 RARRAY_ASET(ary
, index
, rest_last
);
910 if (ISEQ_BODY(iseq
)->param
.flags
.has_kw
) {
911 VALUE
* const klocals
= locals
+ ISEQ_BODY(iseq
)->param
.keyword
->bits_start
- ISEQ_BODY(iseq
)->param
.keyword
->num
;
913 if (args
->kw_argv
!= NULL
) {
914 const struct rb_callinfo_kwarg
*kw_arg
= args
->kw_arg
;
915 args_setup_kw_parameters(ec
, iseq
, args
->kw_argv
, kw_arg
->keyword_len
, kw_arg
->keywords
, klocals
);
917 else if (!NIL_P(keyword_hash
)) {
918 bool remove_hash_value
= false;
919 if (ISEQ_BODY(iseq
)->param
.flags
.has_kwrest
) {
920 keyword_hash
= check_kwrestarg(keyword_hash
, &kw_flag
);
921 remove_hash_value
= true;
923 args_setup_kw_parameters_from_kwsplat(ec
, iseq
, keyword_hash
, klocals
, remove_hash_value
);
926 #if VM_CHECK_MODE > 0
927 if (args_argc(args
) != 0) {
928 VM_ASSERT(ci_flag
& VM_CALL_ARGS_SPLAT
);
929 VM_ASSERT(!(ci_flag
& (VM_CALL_KWARG
| VM_CALL_KW_SPLAT
| VM_CALL_KW_SPLAT_MUT
)));
931 VM_ASSERT(!ISEQ_BODY(iseq
)->param
.flags
.has_rest
);
932 VM_ASSERT(RARRAY_LENINT(args
->rest
) > 0);
933 VM_ASSERT(RB_TYPE_P(rest_last
, T_HASH
));
934 VM_ASSERT(FL_TEST_RAW(rest_last
, RHASH_PASS_AS_KEYWORDS
));
935 VM_ASSERT(args_argc(args
) == 1);
938 args_setup_kw_parameters(ec
, iseq
, NULL
, 0, NULL
, klocals
);
941 else if (ISEQ_BODY(iseq
)->param
.flags
.has_kwrest
) {
942 args_setup_kw_rest_parameter(keyword_hash
, locals
+ ISEQ_BODY(iseq
)->param
.keyword
->rest_start
,
943 kw_flag
, ISEQ_BODY(iseq
)->param
.flags
.anon_kwrest
);
945 else if (!NIL_P(keyword_hash
) && RHASH_SIZE(keyword_hash
) > 0 && arg_setup_type
== arg_setup_method
) {
946 argument_kw_error(ec
, iseq
, "unknown", rb_hash_keys(keyword_hash
));
949 if (ISEQ_BODY(iseq
)->param
.flags
.has_block
) {
950 if (ISEQ_BODY(iseq
)->local_iseq
== iseq
) {
954 args_setup_block_parameter(ec
, calling
, locals
+ ISEQ_BODY(iseq
)->param
.block_start
);
961 for (i
=0; i
<ISEQ_BODY(iseq
)->param
.size
; i
++) {
962 ruby_debug_printf("local[%d] = %p\n", i
, (void *)locals
[i
]);
967 ec
->cfp
->sp
= orig_sp
;
972 raise_argument_error(rb_execution_context_t
*ec
, const rb_iseq_t
*iseq
, const VALUE exc
)
977 vm_push_frame(ec
, iseq
, VM_FRAME_MAGIC_DUMMY
| VM_ENV_FLAG_LOCAL
, Qnil
/* self */,
978 VM_BLOCK_HANDLER_NONE
/* specval*/, Qfalse
/* me or cref */,
979 ISEQ_BODY(iseq
)->iseq_encoded
,
980 ec
->cfp
->sp
, 0, 0 /* stack_max */);
981 at
= rb_ec_backtrace_object(ec
);
982 rb_backtrace_use_iseq_first_lineno_for_last_location(at
);
986 at
= rb_ec_backtrace_object(ec
);
989 rb_ivar_set(exc
, idBt_locations
, at
);
990 rb_exc_set_backtrace(exc
, at
);
995 argument_arity_error(rb_execution_context_t
*ec
, const rb_iseq_t
*iseq
, const int miss_argc
, const int min_argc
, const int max_argc
)
997 VALUE exc
= rb_arity_error_new(miss_argc
, min_argc
, max_argc
);
998 if (ISEQ_BODY(iseq
)->param
.flags
.has_kw
) {
999 const struct rb_iseq_param_keyword
*const kw
= ISEQ_BODY(iseq
)->param
.keyword
;
1000 const ID
*keywords
= kw
->table
;
1001 int req_key_num
= kw
->required_num
;
1002 if (req_key_num
> 0) {
1003 static const char required
[] = "; required keywords";
1004 VALUE mesg
= rb_attr_get(exc
, idMesg
);
1005 rb_str_resize(mesg
, RSTRING_LEN(mesg
)-1);
1006 rb_str_cat(mesg
, required
, sizeof(required
) - 1 - (req_key_num
== 1));
1007 rb_str_cat_cstr(mesg
, ":");
1009 rb_str_cat_cstr(mesg
, " ");
1010 rb_str_append(mesg
, rb_id2str(*keywords
++));
1011 rb_str_cat_cstr(mesg
, ",");
1012 } while (--req_key_num
);
1013 RSTRING_PTR(mesg
)[RSTRING_LEN(mesg
)-1] = ')';
1016 raise_argument_error(ec
, iseq
, exc
);
1020 argument_kw_error(rb_execution_context_t
*ec
, const rb_iseq_t
*iseq
, const char *error
, const VALUE keys
)
1022 raise_argument_error(ec
, iseq
, rb_keyword_error_new(error
, keys
));
1026 vm_to_proc(VALUE proc
)
1028 if (UNLIKELY(!rb_obj_is_proc(proc
))) {
1030 const rb_callable_method_entry_t
*me
=
1031 rb_callable_method_entry_with_refinements(CLASS_OF(proc
), idTo_proc
, NULL
);
1034 b
= rb_vm_call0(GET_EC(), proc
, idTo_proc
, 0, NULL
, me
, RB_NO_KEYWORDS
);
1037 /* NOTE: calling method_missing */
1038 b
= rb_check_convert_type_with_id(proc
, T_DATA
, "Proc", idTo_proc
);
1041 if (NIL_P(b
) || !rb_obj_is_proc(b
)) {
1042 rb_raise(rb_eTypeError
,
1043 "wrong argument type %s (expected Proc)",
1044 rb_obj_classname(proc
));
1054 refine_sym_proc_call(RB_BLOCK_CALL_FUNC_ARGLIST(yielded_arg
, callback_arg
))
1058 const rb_callable_method_entry_t
*me
= 0; /* for hidden object case */
1059 rb_execution_context_t
*ec
;
1060 const VALUE symbol
= RARRAY_AREF(callback_arg
, 0);
1061 const VALUE refinements
= RARRAY_AREF(callback_arg
, 1);
1062 int kw_splat
= RB_PASS_CALLED_KEYWORDS
;
1066 rb_raise(rb_eArgError
, "no receiver given");
1070 mid
= SYM2ID(symbol
);
1071 for (klass
= CLASS_OF(obj
); klass
; klass
= RCLASS_SUPER(klass
)) {
1072 me
= rb_callable_method_entry(klass
, mid
);
1074 me
= rb_resolve_refined_method_callable(refinements
, me
);
1080 if (!NIL_P(blockarg
)) {
1081 vm_passed_block_handler_set(ec
, blockarg
);
1084 return method_missing(ec
, obj
, mid
, argc
, argv
, MISSING_NOENTRY
, kw_splat
);
1086 return rb_vm_call0(ec
, obj
, mid
, argc
, argv
, me
, kw_splat
);
1090 vm_caller_setup_arg_block(const rb_execution_context_t
*ec
, rb_control_frame_t
*reg_cfp
,
1091 const struct rb_callinfo
*ci
, const rb_iseq_t
*blockiseq
, const int is_super
)
1093 if (vm_ci_flag(ci
) & VM_CALL_ARGS_BLOCKARG
) {
1094 VALUE block_code
= *(--reg_cfp
->sp
);
1096 if (NIL_P(block_code
)) {
1097 return VM_BLOCK_HANDLER_NONE
;
1099 else if (block_code
== rb_block_param_proxy
) {
1100 return VM_CF_BLOCK_HANDLER(reg_cfp
);
1102 else if (SYMBOL_P(block_code
) && rb_method_basic_definition_p(rb_cSymbol
, idTo_proc
)) {
1103 const rb_cref_t
*cref
= vm_env_cref(reg_cfp
->ep
);
1104 if (cref
&& !NIL_P(cref
->refinements
)) {
1105 VALUE ref
= cref
->refinements
;
1106 VALUE func
= rb_hash_lookup(ref
, block_code
);
1108 /* TODO: limit cached funcs */
1109 VALUE callback_arg
= rb_ary_hidden_new(2);
1110 rb_ary_push(callback_arg
, block_code
);
1111 rb_ary_push(callback_arg
, ref
);
1112 OBJ_FREEZE(callback_arg
);
1113 func
= rb_func_lambda_new(refine_sym_proc_call
, callback_arg
, 1, UNLIMITED_ARGUMENTS
);
1114 rb_hash_aset(ref
, block_code
, func
);
1121 return vm_to_proc(block_code
);
1124 else if (blockiseq
!= NULL
) { /* likely */
1125 struct rb_captured_block
*captured
= VM_CFP_TO_CAPTURED_BLOCK(reg_cfp
);
1126 captured
->code
.iseq
= blockiseq
;
1127 return VM_BH_FROM_ISEQ_BLOCK(captured
);
1131 return GET_BLOCK_HANDLER();
1134 return VM_BLOCK_HANDLER_NONE
;
1139 static void vm_adjust_stack_forwarding(const struct rb_execution_context_struct
*ec
, struct rb_control_frame_struct
*cfp
, int argc
, VALUE splat
);
1142 vm_caller_setup_fwd_args(const rb_execution_context_t
*ec
, rb_control_frame_t
*reg_cfp
,
1143 CALL_DATA cd
, const rb_iseq_t
*blockiseq
, const int is_super
,
1144 struct rb_forwarding_call_data
*adjusted_cd
, struct rb_callinfo
*adjusted_ci
)
1146 CALL_INFO site_ci
= cd
->ci
;
1149 RUBY_ASSERT(ISEQ_BODY(ISEQ_BODY(GET_ISEQ())->local_iseq
)->param
.flags
.forwardable
);
1150 CALL_INFO caller_ci
= (CALL_INFO
)TOPN(0);
1152 unsigned int site_argc
= vm_ci_argc(site_ci
);
1153 unsigned int site_flag
= vm_ci_flag(site_ci
);
1154 ID site_mid
= vm_ci_mid(site_ci
);
1156 unsigned int caller_argc
= vm_ci_argc(caller_ci
);
1157 unsigned int caller_flag
= vm_ci_flag(caller_ci
);
1158 const struct rb_callinfo_kwarg
* kw
= vm_ci_kwarg(caller_ci
);
1160 VALUE splat
= Qfalse
;
1162 if (site_flag
& VM_CALL_ARGS_SPLAT
) {
1163 // If we're called with args_splat, the top 1 should be an array
1165 site_argc
+= (RARRAY_LEN(splat
) - 1);
1168 // Need to setup the block in case of e.g. `super { :block }`
1169 if (is_super
&& blockiseq
) {
1170 bh
= vm_caller_setup_arg_block(ec
, GET_CFP(), site_ci
, blockiseq
, is_super
);
1173 bh
= VM_ENV_BLOCK_HANDLER(GET_LEP());
1176 vm_adjust_stack_forwarding(ec
, GET_CFP(), caller_argc
, splat
);
1178 *adjusted_ci
= VM_CI_ON_STACK(
1180 (caller_flag
| (site_flag
& (VM_CALL_FCALL
| VM_CALL_FORWARDING
))),
1181 site_argc
+ caller_argc
,
1185 adjusted_cd
->cd
.ci
= adjusted_ci
;
1186 adjusted_cd
->cd
.cc
= cd
->cc
;
1187 adjusted_cd
->caller_ci
= caller_ci
;