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
) {
530 if (!RB_TYPE_P(keyword_hash
, T_HASH
)) {
531 keyword_hash
= rb_to_hash_type(keyword_hash
);
533 else if (UNLIKELY(ISEQ_BODY(iseq
)->param
.flags
.anon_kwrest
)) {
534 if (!ISEQ_BODY(iseq
)->param
.flags
.has_kw
) {
535 *kw_flag
|= VM_CALL_KW_SPLAT_MUT
;
539 if (!(*kw_flag
& VM_CALL_KW_SPLAT_MUT
) &&
540 (ISEQ_BODY(iseq
)->param
.flags
.has_kwrest
||
541 ISEQ_BODY(iseq
)->param
.flags
.ruby2_keywords
)) {
542 *kw_flag
|= VM_CALL_KW_SPLAT_MUT
;
543 keyword_hash
= rb_hash_dup(keyword_hash
);
545 *converted_keyword_hash
= keyword_hash
;
546 return !(ISEQ_BODY(iseq
)->param
.flags
.has_kw
) &&
547 !(ISEQ_BODY(iseq
)->param
.flags
.has_kwrest
) &&
548 RHASH_EMPTY_P(keyword_hash
);
552 check_kwrestarg(VALUE keyword_hash
, unsigned int *kw_flag
)
554 if (!(*kw_flag
& VM_CALL_KW_SPLAT_MUT
)) {
555 *kw_flag
|= VM_CALL_KW_SPLAT_MUT
;
556 return rb_hash_dup(keyword_hash
);
564 setup_parameters_complex(rb_execution_context_t
* const ec
, const rb_iseq_t
* const iseq
,
565 struct rb_calling_info
*const calling
,
566 const struct rb_callinfo
*ci
,
567 VALUE
* const locals
, const enum arg_setup_type arg_setup_type
)
569 const int min_argc
= ISEQ_BODY(iseq
)->param
.lead_num
+ ISEQ_BODY(iseq
)->param
.post_num
;
570 const int max_argc
= (ISEQ_BODY(iseq
)->param
.flags
.has_rest
== FALSE
) ? min_argc
+ ISEQ_BODY(iseq
)->param
.opt_num
: UNLIMITED_ARGUMENTS
;
572 unsigned int ci_flag
= vm_ci_flag(ci
);
573 unsigned int kw_flag
= ci_flag
& (VM_CALL_KWARG
| VM_CALL_KW_SPLAT
| VM_CALL_KW_SPLAT_MUT
);
574 int opt_pc
= 0, allow_autosplat
= !kw_flag
;
575 struct args_info args_body
, *args
;
576 VALUE keyword_hash
= Qnil
;
577 VALUE
* const orig_sp
= ec
->cfp
->sp
;
579 VALUE flag_keyword_hash
= 0;
580 VALUE splat_flagged_keyword_hash
= 0;
581 VALUE converted_keyword_hash
= 0;
584 vm_check_canary(ec
, orig_sp
);
588 * [pushed values] [uninitialized values]
590 * <- ISEQ_BODY(iseq)->param.size------------>
594 * [pushed values] [initialized values ]
596 * <- ISEQ_BODY(iseq)->param.size------------>
599 for (i
=calling
->argc
; i
<ISEQ_BODY(iseq
)->param
.size
; i
++) {
602 ec
->cfp
->sp
= &locals
[i
];
606 given_argc
= args
->argc
= calling
->argc
;
608 args
->rest_dupped
= ci_flag
& VM_CALL_ARGS_SPLAT_MUT
;
610 if (UNLIKELY(ISEQ_BODY(iseq
)->param
.flags
.anon_rest
)) {
611 if ((ci_flag
& VM_CALL_ARGS_SPLAT
) &&
612 given_argc
== ISEQ_BODY(iseq
)->param
.lead_num
+ (kw_flag
? 2 : 1) &&
613 !ISEQ_BODY(iseq
)->param
.flags
.has_opt
&&
614 !ISEQ_BODY(iseq
)->param
.flags
.has_post
&&
615 !ISEQ_BODY(iseq
)->param
.flags
.ruby2_keywords
&&
617 !ISEQ_BODY(iseq
)->param
.flags
.has_kw
||
618 !ISEQ_BODY(iseq
)->param
.flags
.has_kwrest
||
619 !ISEQ_BODY(iseq
)->param
.flags
.accepts_no_kwarg
)) {
620 args
->rest_dupped
= true;
624 if (kw_flag
& VM_CALL_KWARG
) {
625 args
->kw_arg
= vm_ci_kwarg(ci
);
627 if (ISEQ_BODY(iseq
)->param
.flags
.has_kw
) {
628 int kw_len
= args
->kw_arg
->keyword_len
;
630 args
->kw_argv
= ALLOCA_N(VALUE
, kw_len
);
631 args
->argc
-= kw_len
;
632 given_argc
-= kw_len
;
633 MEMCPY(args
->kw_argv
, locals
+ args
->argc
, VALUE
, kw_len
);
636 args
->kw_argv
= NULL
;
637 given_argc
= args_kw_argv_to_hash(args
);
638 kw_flag
|= VM_CALL_KW_SPLAT
| VM_CALL_KW_SPLAT_MUT
;
643 args
->kw_argv
= NULL
;
646 if ((ci_flag
& VM_CALL_ARGS_SPLAT
) && (ci_flag
& VM_CALL_KW_SPLAT
)) {
648 args
->rest_index
= 0;
649 keyword_hash
= locals
[--args
->argc
];
650 args
->rest
= locals
[--args
->argc
];
652 if (ignore_keyword_hash_p(keyword_hash
, iseq
, &kw_flag
, &converted_keyword_hash
)) {
655 else if (UNLIKELY(ISEQ_BODY(iseq
)->param
.flags
.ruby2_keywords
)) {
656 converted_keyword_hash
= check_kwrestarg(converted_keyword_hash
, &kw_flag
);
657 flag_keyword_hash
= converted_keyword_hash
;
659 rb_ary_push(args
->rest
, converted_keyword_hash
);
662 else if (!ISEQ_BODY(iseq
)->param
.flags
.has_kwrest
&& !ISEQ_BODY(iseq
)->param
.flags
.has_kw
) {
663 converted_keyword_hash
= check_kwrestarg(converted_keyword_hash
, &kw_flag
);
665 rb_ary_push(args
->rest
, converted_keyword_hash
);
669 keyword_hash
= converted_keyword_hash
;
672 int len
= RARRAY_LENINT(args
->rest
);
673 given_argc
+= len
- 2;
675 else if (ci_flag
& VM_CALL_ARGS_SPLAT
) {
677 args
->rest_index
= 0;
678 args
->rest
= locals
[--args
->argc
];
679 int len
= RARRAY_LENINT(args
->rest
);
680 given_argc
+= len
- 1;
682 if (!kw_flag
&& len
> 0) {
683 rest_last
= RARRAY_AREF(args
->rest
, len
- 1);
684 if (RB_TYPE_P(rest_last
, T_HASH
) && FL_TEST_RAW(rest_last
, RHASH_PASS_AS_KEYWORDS
)) {
685 // def f(**kw); a = [..., kw]; g(*a)
686 splat_flagged_keyword_hash
= rest_last
;
687 rest_last
= rb_hash_dup(rest_last
);
688 kw_flag
|= VM_CALL_KW_SPLAT
| VM_CALL_KW_SPLAT_MUT
;
690 // Unset rest_dupped set by anon_rest as we may need to modify splat in this case
691 args
->rest_dupped
= false;
693 if (ignore_keyword_hash_p(rest_last
, iseq
, &kw_flag
, &converted_keyword_hash
)) {
695 rb_ary_pop(args
->rest
);
697 kw_flag
&= ~(VM_CALL_KW_SPLAT
| VM_CALL_KW_SPLAT_MUT
);
700 if (rest_last
!= converted_keyword_hash
) {
701 rest_last
= converted_keyword_hash
;
703 RARRAY_ASET(args
->rest
, len
- 1, rest_last
);
706 if (ISEQ_BODY(iseq
)->param
.flags
.ruby2_keywords
&& rest_last
) {
707 flag_keyword_hash
= rest_last
;
709 else if (ISEQ_BODY(iseq
)->param
.flags
.has_kw
|| ISEQ_BODY(iseq
)->param
.flags
.has_kwrest
) {
711 rb_ary_pop(args
->rest
);
713 keyword_hash
= rest_last
;
722 if (args
->argc
> 0 && (kw_flag
& VM_CALL_KW_SPLAT
)) {
724 VALUE last_arg
= args
->argv
[args
->argc
-1];
725 if (ignore_keyword_hash_p(last_arg
, iseq
, &kw_flag
, &converted_keyword_hash
)) {
728 kw_flag
&= ~(VM_CALL_KW_SPLAT
| VM_CALL_KW_SPLAT_MUT
);
731 if (!(kw_flag
& VM_CALL_KW_SPLAT_MUT
) && !ISEQ_BODY(iseq
)->param
.flags
.has_kw
) {
732 converted_keyword_hash
= rb_hash_dup(converted_keyword_hash
);
733 kw_flag
|= VM_CALL_KW_SPLAT_MUT
;
736 if (last_arg
!= converted_keyword_hash
) {
737 last_arg
= converted_keyword_hash
;
738 args
->argv
[args
->argc
-1] = last_arg
;
741 if (ISEQ_BODY(iseq
)->param
.flags
.ruby2_keywords
) {
742 flag_keyword_hash
= last_arg
;
744 else if (ISEQ_BODY(iseq
)->param
.flags
.has_kw
|| ISEQ_BODY(iseq
)->param
.flags
.has_kwrest
) {
747 keyword_hash
= last_arg
;
753 if (flag_keyword_hash
) {
754 FL_SET_RAW(flag_keyword_hash
, RHASH_PASS_AS_KEYWORDS
);
757 if (kw_flag
&& ISEQ_BODY(iseq
)->param
.flags
.accepts_no_kwarg
) {
758 rb_raise(rb_eArgError
, "no keywords accepted");
761 switch (arg_setup_type
) {
762 case arg_setup_method
:
763 break; /* do nothing special */
764 case arg_setup_block
:
765 if (given_argc
== 1 &&
767 !splat_flagged_keyword_hash
&&
768 (min_argc
> 0 || ISEQ_BODY(iseq
)->param
.opt_num
> 1) &&
769 !ISEQ_BODY(iseq
)->param
.flags
.ambiguous_param0
&&
770 !((ISEQ_BODY(iseq
)->param
.flags
.has_kw
||
771 ISEQ_BODY(iseq
)->param
.flags
.has_kwrest
)
773 args_check_block_arg0(args
)) {
774 given_argc
= RARRAY_LENINT(args
->rest
);
780 if (given_argc
< min_argc
) {
781 if (arg_setup_type
== arg_setup_block
) {
782 CHECK_VM_STACK_OVERFLOW(ec
->cfp
, min_argc
);
783 given_argc
= min_argc
;
784 args_extend(args
, min_argc
);
787 argument_arity_error(ec
, iseq
, given_argc
, min_argc
, max_argc
);
791 if (given_argc
> max_argc
&& max_argc
!= UNLIMITED_ARGUMENTS
) {
792 if (arg_setup_type
== arg_setup_block
) {
794 args_reduce(args
, given_argc
- max_argc
);
795 given_argc
= max_argc
;
798 argument_arity_error(ec
, iseq
, given_argc
, min_argc
, max_argc
);
802 if (ISEQ_BODY(iseq
)->param
.flags
.has_lead
) {
803 args_setup_lead_parameters(args
, ISEQ_BODY(iseq
)->param
.lead_num
, locals
+ 0);
806 if (ISEQ_BODY(iseq
)->param
.flags
.has_rest
|| ISEQ_BODY(iseq
)->param
.flags
.has_post
){
810 if (ISEQ_BODY(iseq
)->param
.flags
.has_post
) {
811 args_setup_post_parameters(args
, ISEQ_BODY(iseq
)->param
.post_num
, locals
+ ISEQ_BODY(iseq
)->param
.post_start
);
814 if (ISEQ_BODY(iseq
)->param
.flags
.has_opt
) {
815 int opt
= args_setup_opt_parameters(args
, ISEQ_BODY(iseq
)->param
.opt_num
, locals
+ ISEQ_BODY(iseq
)->param
.lead_num
);
816 opt_pc
= (int)ISEQ_BODY(iseq
)->param
.opt_table
[opt
];
819 if (ISEQ_BODY(iseq
)->param
.flags
.has_rest
) {
820 args_setup_rest_parameter(args
, locals
+ ISEQ_BODY(iseq
)->param
.rest_start
);
821 VALUE ary
= *(locals
+ ISEQ_BODY(iseq
)->param
.rest_start
);
822 VALUE index
= RARRAY_LEN(ary
) - 1;
823 if (splat_flagged_keyword_hash
&&
824 !ISEQ_BODY(iseq
)->param
.flags
.ruby2_keywords
&&
825 !ISEQ_BODY(iseq
)->param
.flags
.has_kw
&&
826 !ISEQ_BODY(iseq
)->param
.flags
.has_kwrest
&&
827 RARRAY_AREF(ary
, index
) == splat_flagged_keyword_hash
) {
828 ((struct RHash
*)rest_last
)->basic
.flags
&= ~RHASH_PASS_AS_KEYWORDS
;
829 RARRAY_ASET(ary
, index
, rest_last
);
833 if (ISEQ_BODY(iseq
)->param
.flags
.has_kw
) {
834 VALUE
* const klocals
= locals
+ ISEQ_BODY(iseq
)->param
.keyword
->bits_start
- ISEQ_BODY(iseq
)->param
.keyword
->num
;
836 if (args
->kw_argv
!= NULL
) {
837 const struct rb_callinfo_kwarg
*kw_arg
= args
->kw_arg
;
838 args_setup_kw_parameters(ec
, iseq
, args
->kw_argv
, kw_arg
->keyword_len
, kw_arg
->keywords
, klocals
);
840 else if (!NIL_P(keyword_hash
)) {
841 bool remove_hash_value
= false;
842 if (ISEQ_BODY(iseq
)->param
.flags
.has_kwrest
) {
843 keyword_hash
= check_kwrestarg(keyword_hash
, &kw_flag
);
844 remove_hash_value
= true;
846 args_setup_kw_parameters_from_kwsplat(ec
, iseq
, keyword_hash
, klocals
, remove_hash_value
);
849 VM_ASSERT(args_argc(args
) == 0);
850 args_setup_kw_parameters(ec
, iseq
, NULL
, 0, NULL
, klocals
);
853 else if (ISEQ_BODY(iseq
)->param
.flags
.has_kwrest
) {
854 args_setup_kw_rest_parameter(keyword_hash
, locals
+ ISEQ_BODY(iseq
)->param
.keyword
->rest_start
,
855 kw_flag
, ISEQ_BODY(iseq
)->param
.flags
.anon_kwrest
);
857 else if (!NIL_P(keyword_hash
) && RHASH_SIZE(keyword_hash
) > 0 && arg_setup_type
== arg_setup_method
) {
858 argument_kw_error(ec
, iseq
, "unknown", rb_hash_keys(keyword_hash
));
861 if (ISEQ_BODY(iseq
)->param
.flags
.has_block
) {
862 if (ISEQ_BODY(iseq
)->local_iseq
== iseq
) {
866 args_setup_block_parameter(ec
, calling
, locals
+ ISEQ_BODY(iseq
)->param
.block_start
);
873 for (i
=0; i
<ISEQ_BODY(iseq
)->param
.size
; i
++) {
874 ruby_debug_printf("local[%d] = %p\n", i
, (void *)locals
[i
]);
879 ec
->cfp
->sp
= orig_sp
;
884 raise_argument_error(rb_execution_context_t
*ec
, const rb_iseq_t
*iseq
, const VALUE exc
)
889 vm_push_frame(ec
, iseq
, VM_FRAME_MAGIC_DUMMY
| VM_ENV_FLAG_LOCAL
, Qnil
/* self */,
890 VM_BLOCK_HANDLER_NONE
/* specval*/, Qfalse
/* me or cref */,
891 ISEQ_BODY(iseq
)->iseq_encoded
,
892 ec
->cfp
->sp
, 0, 0 /* stack_max */);
893 at
= rb_ec_backtrace_object(ec
);
894 rb_backtrace_use_iseq_first_lineno_for_last_location(at
);
898 at
= rb_ec_backtrace_object(ec
);
901 rb_ivar_set(exc
, idBt_locations
, at
);
902 rb_exc_set_backtrace(exc
, at
);
907 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
)
909 VALUE exc
= rb_arity_error_new(miss_argc
, min_argc
, max_argc
);
910 if (ISEQ_BODY(iseq
)->param
.flags
.has_kw
) {
911 const struct rb_iseq_param_keyword
*const kw
= ISEQ_BODY(iseq
)->param
.keyword
;
912 const ID
*keywords
= kw
->table
;
913 int req_key_num
= kw
->required_num
;
914 if (req_key_num
> 0) {
915 static const char required
[] = "; required keywords";
916 VALUE mesg
= rb_attr_get(exc
, idMesg
);
917 rb_str_resize(mesg
, RSTRING_LEN(mesg
)-1);
918 rb_str_cat(mesg
, required
, sizeof(required
) - 1 - (req_key_num
== 1));
919 rb_str_cat_cstr(mesg
, ":");
921 rb_str_cat_cstr(mesg
, " ");
922 rb_str_append(mesg
, rb_id2str(*keywords
++));
923 rb_str_cat_cstr(mesg
, ",");
924 } while (--req_key_num
);
925 RSTRING_PTR(mesg
)[RSTRING_LEN(mesg
)-1] = ')';
928 raise_argument_error(ec
, iseq
, exc
);
932 argument_kw_error(rb_execution_context_t
*ec
, const rb_iseq_t
*iseq
, const char *error
, const VALUE keys
)
934 raise_argument_error(ec
, iseq
, rb_keyword_error_new(error
, keys
));
938 vm_to_proc(VALUE proc
)
940 if (UNLIKELY(!rb_obj_is_proc(proc
))) {
942 const rb_callable_method_entry_t
*me
=
943 rb_callable_method_entry_with_refinements(CLASS_OF(proc
), idTo_proc
, NULL
);
946 b
= rb_vm_call0(GET_EC(), proc
, idTo_proc
, 0, NULL
, me
, RB_NO_KEYWORDS
);
949 /* NOTE: calling method_missing */
950 b
= rb_check_convert_type_with_id(proc
, T_DATA
, "Proc", idTo_proc
);
953 if (NIL_P(b
) || !rb_obj_is_proc(b
)) {
954 rb_raise(rb_eTypeError
,
955 "wrong argument type %s (expected Proc)",
956 rb_obj_classname(proc
));
966 refine_sym_proc_call(RB_BLOCK_CALL_FUNC_ARGLIST(yielded_arg
, callback_arg
))
970 const rb_callable_method_entry_t
*me
= 0; /* for hidden object case */
971 rb_execution_context_t
*ec
;
972 const VALUE symbol
= RARRAY_AREF(callback_arg
, 0);
973 const VALUE refinements
= RARRAY_AREF(callback_arg
, 1);
974 int kw_splat
= RB_PASS_CALLED_KEYWORDS
;
978 rb_raise(rb_eArgError
, "no receiver given");
982 mid
= SYM2ID(symbol
);
983 for (klass
= CLASS_OF(obj
); klass
; klass
= RCLASS_SUPER(klass
)) {
984 me
= rb_callable_method_entry(klass
, mid
);
986 me
= rb_resolve_refined_method_callable(refinements
, me
);
992 if (!NIL_P(blockarg
)) {
993 vm_passed_block_handler_set(ec
, blockarg
);
996 return method_missing(ec
, obj
, mid
, argc
, argv
, MISSING_NOENTRY
, kw_splat
);
998 return rb_vm_call0(ec
, obj
, mid
, argc
, argv
, me
, kw_splat
);
1002 vm_caller_setup_arg_block(const rb_execution_context_t
*ec
, rb_control_frame_t
*reg_cfp
,
1003 const struct rb_callinfo
*ci
, const rb_iseq_t
*blockiseq
, const int is_super
)
1005 if (vm_ci_flag(ci
) & VM_CALL_ARGS_BLOCKARG
) {
1006 VALUE block_code
= *(--reg_cfp
->sp
);
1008 if (NIL_P(block_code
)) {
1009 return VM_BLOCK_HANDLER_NONE
;
1011 else if (block_code
== rb_block_param_proxy
) {
1012 return VM_CF_BLOCK_HANDLER(reg_cfp
);
1014 else if (SYMBOL_P(block_code
) && rb_method_basic_definition_p(rb_cSymbol
, idTo_proc
)) {
1015 const rb_cref_t
*cref
= vm_env_cref(reg_cfp
->ep
);
1016 if (cref
&& !NIL_P(cref
->refinements
)) {
1017 VALUE ref
= cref
->refinements
;
1018 VALUE func
= rb_hash_lookup(ref
, block_code
);
1020 /* TODO: limit cached funcs */
1021 VALUE callback_arg
= rb_ary_hidden_new(2);
1022 rb_ary_push(callback_arg
, block_code
);
1023 rb_ary_push(callback_arg
, ref
);
1024 OBJ_FREEZE(callback_arg
);
1025 func
= rb_func_lambda_new(refine_sym_proc_call
, callback_arg
, 1, UNLIMITED_ARGUMENTS
);
1026 rb_hash_aset(ref
, block_code
, func
);
1033 return vm_to_proc(block_code
);
1036 else if (blockiseq
!= NULL
) { /* likely */
1037 struct rb_captured_block
*captured
= VM_CFP_TO_CAPTURED_BLOCK(reg_cfp
);
1038 captured
->code
.iseq
= blockiseq
;
1039 return VM_BH_FROM_ISEQ_BLOCK(captured
);
1043 return GET_BLOCK_HANDLER();
1046 return VM_BLOCK_HANDLER_NONE
;