Ruby  3.1.4p223 (2023-03-30 revision HEAD)
vm_args.c
1 /**********************************************************************
2 
3  vm_args.c - process method call arguments.
4 
5  $Author$
6 
7  Copyright (C) 2014- Yukihiro Matsumoto
8 
9 **********************************************************************/
10 
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 #if !defined(_MSC_VER) || !defined(MJIT_HEADER)
18 MJIT_FUNC_EXPORTED
19 #endif
20 const rb_callable_method_entry_t *rb_resolve_refined_method_callable(VALUE refinements, const rb_callable_method_entry_t *me);
21 
22 struct args_info {
23  /* basic args info */
24  VALUE *argv;
25  int argc;
26 
27  /* additional args info */
28  int rest_index;
29  int rest_dupped;
30  const struct rb_callinfo_kwarg *kw_arg;
31  VALUE *kw_argv;
32  VALUE rest;
33 };
34 
35 enum arg_setup_type {
36  arg_setup_method,
37  arg_setup_block
38 };
39 
40 static inline void
41 arg_rest_dup(struct args_info *args)
42 {
43  if (!args->rest_dupped) {
44  args->rest = rb_ary_dup(args->rest);
45  args->rest_dupped = TRUE;
46  }
47 }
48 
49 static inline int
50 args_argc(struct args_info *args)
51 {
52  if (args->rest == Qfalse) {
53  return args->argc;
54  }
55  else {
56  return args->argc + RARRAY_LENINT(args->rest) - args->rest_index;
57  }
58 }
59 
60 static inline void
61 args_extend(struct args_info *args, const int min_argc)
62 {
63  int i;
64 
65  if (args->rest) {
66  arg_rest_dup(args);
67  VM_ASSERT(args->rest_index == 0);
68  for (i=args->argc + RARRAY_LENINT(args->rest); i<min_argc; i++) {
69  rb_ary_push(args->rest, Qnil);
70  }
71  }
72  else {
73  for (i=args->argc; i<min_argc; i++) {
74  args->argv[args->argc++] = Qnil;
75  }
76  }
77 }
78 
79 static inline void
80 args_reduce(struct args_info *args, int over_argc)
81 {
82  if (args->rest) {
83  const long len = RARRAY_LEN(args->rest);
84 
85  if (len > over_argc) {
86  arg_rest_dup(args);
87  rb_ary_resize(args->rest, len - over_argc);
88  return;
89  }
90  else {
91  args->rest = Qfalse;
92  over_argc -= len;
93  }
94  }
95 
96  VM_ASSERT(args->argc >= over_argc);
97  args->argc -= over_argc;
98 }
99 
100 static inline int
101 args_check_block_arg0(struct args_info *args)
102 {
103  VALUE ary = Qnil;
104 
105  if (args->rest && RARRAY_LEN(args->rest) == 1) {
106  VALUE arg0 = RARRAY_AREF(args->rest, 0);
107  ary = rb_check_array_type(arg0);
108  }
109  else if (args->argc == 1) {
110  VALUE arg0 = args->argv[0];
111  ary = rb_check_array_type(arg0);
112  args->argv[0] = arg0; /* see: https://bugs.ruby-lang.org/issues/8484 */
113  }
114 
115  if (!NIL_P(ary)) {
116  args->rest = ary;
117  args->rest_index = 0;
118  args->argc = 0;
119  return TRUE;
120  }
121 
122  return FALSE;
123 }
124 
125 static inline void
126 args_copy(struct args_info *args)
127 {
128  if (args->rest != Qfalse) {
129  int argc = args->argc;
130  args->argc = 0;
131  arg_rest_dup(args);
132 
133  /*
134  * argv: [m0, m1, m2, m3]
135  * rest: [a0, a1, a2, a3, a4, a5]
136  * ^
137  * rest_index
138  *
139  * #=> first loop
140  *
141  * argv: [m0, m1]
142  * rest: [m2, m3, a2, a3, a4, a5]
143  * ^
144  * rest_index
145  *
146  * #=> 2nd loop
147  *
148  * argv: [] (argc == 0)
149  * rest: [m0, m1, m2, m3, a2, a3, a4, a5]
150  * ^
151  * rest_index
152  */
153  while (args->rest_index > 0 && argc > 0) {
154  RARRAY_ASET(args->rest, --args->rest_index, args->argv[--argc]);
155  }
156  while (argc > 0) {
157  rb_ary_unshift(args->rest, args->argv[--argc]);
158  }
159  }
160  else if (args->argc > 0) {
161  args->rest = rb_ary_new_from_values(args->argc, args->argv);
162  args->rest_index = 0;
163  args->rest_dupped = TRUE;
164  args->argc = 0;
165  }
166 }
167 
168 static inline const VALUE *
169 args_rest_argv(struct args_info *args)
170 {
171  return RARRAY_CONST_PTR_TRANSIENT(args->rest) + args->rest_index;
172 }
173 
174 static inline VALUE
175 args_rest_array(struct args_info *args)
176 {
177  VALUE ary;
178 
179  if (args->rest) {
180  ary = rb_ary_behead(args->rest, args->rest_index);
181  args->rest_index = 0;
182  args->rest = 0;
183  }
184  else {
185  ary = rb_ary_new();
186  }
187  return ary;
188 }
189 
190 static int
191 args_kw_argv_to_hash(struct args_info *args)
192 {
193  const struct rb_callinfo_kwarg *kw_arg = args->kw_arg;
194  const VALUE *const passed_keywords = kw_arg->keywords;
195  const int kw_len = kw_arg->keyword_len;
196  VALUE h = rb_hash_new_with_size(kw_len);
197  const int kw_start = args->argc - kw_len;
198  const VALUE * const kw_argv = args->argv + kw_start;
199  int i;
200 
201  args->argc = kw_start + 1;
202  for (i=0; i<kw_len; i++) {
203  rb_hash_aset(h, passed_keywords[i], kw_argv[i]);
204  }
205 
206  args->argv[args->argc - 1] = h;
207 
208  return args->argc;
209 }
210 
211 static inline void
212 args_setup_lead_parameters(struct args_info *args, int argc, VALUE *locals)
213 {
214  if (args->argc >= argc) {
215  /* do noting */
216  args->argc -= argc;
217  args->argv += argc;
218  }
219  else {
220  int i, j;
221  const VALUE *argv = args_rest_argv(args);
222 
223  for (i=args->argc, j=0; i<argc; i++, j++) {
224  locals[i] = argv[j];
225  }
226  args->rest_index += argc - args->argc;
227  args->argc = 0;
228  }
229 }
230 
231 static inline void
232 args_setup_post_parameters(struct args_info *args, int argc, VALUE *locals)
233 {
234  long len;
235  len = RARRAY_LEN(args->rest);
236  MEMCPY(locals, RARRAY_CONST_PTR_TRANSIENT(args->rest) + len - argc, VALUE, argc);
237  rb_ary_resize(args->rest, len - argc);
238 }
239 
240 static inline int
241 args_setup_opt_parameters(struct args_info *args, int opt_max, VALUE *locals)
242 {
243  int i;
244 
245  if (args->argc >= opt_max) {
246  args->argc -= opt_max;
247  args->argv += opt_max;
248  i = opt_max;
249  }
250  else {
251  int j;
252  i = args->argc;
253  args->argc = 0;
254 
255  if (args->rest) {
256  int len = RARRAY_LENINT(args->rest);
257  const VALUE *argv = RARRAY_CONST_PTR_TRANSIENT(args->rest);
258 
259  for (; i<opt_max && args->rest_index < len; i++, args->rest_index++) {
260  locals[i] = argv[args->rest_index];
261  }
262  }
263 
264  /* initialize by nil */
265  for (j=i; j<opt_max; j++) {
266  locals[j] = Qnil;
267  }
268  }
269 
270  return i;
271 }
272 
273 static inline void
274 args_setup_rest_parameter(struct args_info *args, VALUE *locals)
275 {
276  *locals = args_rest_array(args);
277 }
278 
279 static VALUE
280 make_unknown_kw_hash(const VALUE *passed_keywords, int passed_keyword_len, const VALUE *kw_argv)
281 {
282  int i;
283  VALUE obj = rb_ary_tmp_new(1);
284 
285  for (i=0; i<passed_keyword_len; i++) {
286  if (kw_argv[i] != Qundef) {
287  rb_ary_push(obj, passed_keywords[i]);
288  }
289  }
290  return obj;
291 }
292 
293 static VALUE
294 make_rest_kw_hash(const VALUE *passed_keywords, int passed_keyword_len, const VALUE *kw_argv)
295 {
296  int i;
297  VALUE obj = rb_hash_new_with_size(passed_keyword_len);
298 
299  for (i=0; i<passed_keyword_len; i++) {
300  if (kw_argv[i] != Qundef) {
301  rb_hash_aset(obj, passed_keywords[i], kw_argv[i]);
302  }
303  }
304  return obj;
305 }
306 
307 static inline int
308 args_setup_kw_parameters_lookup(const ID key, VALUE *ptr, const VALUE *const passed_keywords, VALUE *passed_values, const int passed_keyword_len)
309 {
310  int i;
311  const VALUE keyname = ID2SYM(key);
312 
313  for (i=0; i<passed_keyword_len; i++) {
314  if (keyname == passed_keywords[i]) {
315  *ptr = passed_values[i];
316  passed_values[i] = Qundef;
317  return TRUE;
318  }
319  }
320 
321  return FALSE;
322 }
323 
324 #define KW_SPECIFIED_BITS_MAX (32-1) /* TODO: 32 -> Fixnum's max bits */
325 
326 static void
327 args_setup_kw_parameters(rb_execution_context_t *const ec, const rb_iseq_t *const iseq,
328  VALUE *const passed_values, const int passed_keyword_len, const VALUE *const passed_keywords,
329  VALUE *const locals)
330 {
331  const ID *acceptable_keywords = iseq->body->param.keyword->table;
332  const int req_key_num = iseq->body->param.keyword->required_num;
333  const int key_num = iseq->body->param.keyword->num;
334  const VALUE * const default_values = iseq->body->param.keyword->default_values;
335  VALUE missing = 0;
336  int i, di, found = 0;
337  int unspecified_bits = 0;
338  VALUE unspecified_bits_value = Qnil;
339 
340  for (i=0; i<req_key_num; i++) {
341  ID key = acceptable_keywords[i];
342  if (args_setup_kw_parameters_lookup(key, &locals[i], passed_keywords, passed_values, passed_keyword_len)) {
343  found++;
344  }
345  else {
346  if (!missing) missing = rb_ary_tmp_new(1);
347  rb_ary_push(missing, ID2SYM(key));
348  }
349  }
350 
351  if (missing) argument_kw_error(ec, iseq, "missing", missing);
352 
353  for (di=0; i<key_num; i++, di++) {
354  if (args_setup_kw_parameters_lookup(acceptable_keywords[i], &locals[i], passed_keywords, passed_values, passed_keyword_len)) {
355  found++;
356  }
357  else {
358  if (default_values[di] == Qundef) {
359  locals[i] = Qnil;
360 
361  if (LIKELY(i < KW_SPECIFIED_BITS_MAX)) {
362  unspecified_bits |= 0x01 << di;
363  }
364  else {
365  if (NIL_P(unspecified_bits_value)) {
366  /* fixnum -> hash */
367  int j;
368  unspecified_bits_value = rb_hash_new();
369 
370  for (j=0; j<KW_SPECIFIED_BITS_MAX; j++) {
371  if (unspecified_bits & (0x01 << j)) {
372  rb_hash_aset(unspecified_bits_value, INT2FIX(j), Qtrue);
373  }
374  }
375  }
376  rb_hash_aset(unspecified_bits_value, INT2FIX(di), Qtrue);
377  }
378  }
379  else {
380  locals[i] = default_values[di];
381  }
382  }
383  }
384 
385  if (iseq->body->param.flags.has_kwrest) {
386  const int rest_hash_index = key_num + 1;
387  locals[rest_hash_index] = make_rest_kw_hash(passed_keywords, passed_keyword_len, passed_values);
388  }
389  else {
390  if (found != passed_keyword_len) {
391  VALUE keys = make_unknown_kw_hash(passed_keywords, passed_keyword_len, passed_values);
392  argument_kw_error(ec, iseq, "unknown", keys);
393  }
394  }
395 
396  if (NIL_P(unspecified_bits_value)) {
397  unspecified_bits_value = INT2FIX(unspecified_bits);
398  }
399  locals[key_num] = unspecified_bits_value;
400 }
401 
402 static inline void
403 args_setup_kw_rest_parameter(VALUE keyword_hash, VALUE *locals, int kw_flag)
404 {
405  if (NIL_P(keyword_hash)) {
406  keyword_hash = rb_hash_new();
407  }
408  else if (!(kw_flag & VM_CALL_KW_SPLAT_MUT)) {
409  keyword_hash = rb_hash_dup(keyword_hash);
410  }
411  locals[0] = keyword_hash;
412 }
413 
414 static inline void
415 args_setup_block_parameter(const rb_execution_context_t *ec, struct rb_calling_info *calling, VALUE *locals)
416 {
417  VALUE block_handler = calling->block_handler;
418  *locals = rb_vm_bh_to_procval(ec, block_handler);
419 }
420 
422  VALUE *keys;
423  VALUE *vals;
424  int argc;
425 };
426 
427 static int
428 fill_keys_values(st_data_t key, st_data_t val, st_data_t ptr)
429 {
430  struct fill_values_arg *arg = (struct fill_values_arg *)ptr;
431  int i = arg->argc++;
432  arg->keys[i] = (VALUE)key;
433  arg->vals[i] = (VALUE)val;
434  return ST_CONTINUE;
435 }
436 
437 static inline int
438 ignore_keyword_hash_p(VALUE keyword_hash, const rb_iseq_t * const iseq, unsigned int * kw_flag, VALUE * converted_keyword_hash)
439 {
440  if (!RB_TYPE_P(keyword_hash, T_HASH)) {
441  keyword_hash = rb_to_hash_type(keyword_hash);
442  }
443  if (!(*kw_flag & VM_CALL_KW_SPLAT_MUT) &&
444  (iseq->body->param.flags.has_kwrest ||
445  iseq->body->param.flags.ruby2_keywords)) {
446  *kw_flag |= VM_CALL_KW_SPLAT_MUT;
447  keyword_hash = rb_hash_dup(keyword_hash);
448  }
449  *converted_keyword_hash = keyword_hash;
450  return !(iseq->body->param.flags.has_kw) &&
451  !(iseq->body->param.flags.has_kwrest) &&
452  RHASH_EMPTY_P(keyword_hash);
453 }
454 
455 static int
456 setup_parameters_complex(rb_execution_context_t * const ec, const rb_iseq_t * const iseq,
457  struct rb_calling_info *const calling,
458  const struct rb_callinfo *ci,
459  VALUE * const locals, const enum arg_setup_type arg_setup_type)
460 {
461  const int min_argc = iseq->body->param.lead_num + iseq->body->param.post_num;
462  const int max_argc = (iseq->body->param.flags.has_rest == FALSE) ? min_argc + iseq->body->param.opt_num : UNLIMITED_ARGUMENTS;
463  int given_argc;
464  unsigned int kw_flag = vm_ci_flag(ci) & (VM_CALL_KWARG | VM_CALL_KW_SPLAT | VM_CALL_KW_SPLAT_MUT);
465  int opt_pc = 0, allow_autosplat = !kw_flag;
466  struct args_info args_body, *args;
467  VALUE keyword_hash = Qnil;
468  VALUE * const orig_sp = ec->cfp->sp;
469  unsigned int i;
470  VALUE flag_keyword_hash = 0;
471  VALUE converted_keyword_hash = 0;
472 
473  vm_check_canary(ec, orig_sp);
474  /*
475  * Extend SP for GC.
476  *
477  * [pushed values] [uninitialized values]
478  * <- ci->argc -->
479  * <- iseq->body->param.size------------>
480  * ^ locals ^ sp
481  *
482  * =>
483  * [pushed values] [initialized values ]
484  * <- ci->argc -->
485  * <- iseq->body->param.size------------>
486  * ^ locals ^ sp
487  */
488  for (i=calling->argc; i<iseq->body->param.size; i++) {
489  locals[i] = Qnil;
490  }
491  ec->cfp->sp = &locals[i];
492 
493  /* setup args */
494  args = &args_body;
495  given_argc = args->argc = calling->argc;
496  args->argv = locals;
497  args->rest_dupped = FALSE;
498 
499  if (kw_flag & VM_CALL_KWARG) {
500  args->kw_arg = vm_ci_kwarg(ci);
501 
502  if (iseq->body->param.flags.has_kw) {
503  int kw_len = args->kw_arg->keyword_len;
504  /* copy kw_argv */
505  args->kw_argv = ALLOCA_N(VALUE, kw_len);
506  args->argc -= kw_len;
507  given_argc -= kw_len;
508  MEMCPY(args->kw_argv, locals + args->argc, VALUE, kw_len);
509  }
510  else {
511  args->kw_argv = NULL;
512  given_argc = args_kw_argv_to_hash(args);
513  kw_flag |= VM_CALL_KW_SPLAT | VM_CALL_KW_SPLAT_MUT;
514  }
515  }
516  else {
517  args->kw_arg = NULL;
518  args->kw_argv = NULL;
519  }
520 
521  if (vm_ci_flag(ci) & VM_CALL_ARGS_SPLAT) {
522  VALUE rest_last = 0;
523  int len;
524  args->rest = locals[--args->argc];
525  args->rest_index = 0;
526  len = RARRAY_LENINT(args->rest);
527  given_argc += len - 1;
528  rest_last = RARRAY_AREF(args->rest, len - 1);
529 
530  if (!kw_flag && len > 0) {
531  if (RB_TYPE_P(rest_last, T_HASH) &&
532  (((struct RHash *)rest_last)->basic.flags & RHASH_PASS_AS_KEYWORDS)) {
533  rest_last = rb_hash_dup(rest_last);
534  kw_flag |= VM_CALL_KW_SPLAT | VM_CALL_KW_SPLAT_MUT;
535  }
536  else {
537  rest_last = 0;
538  }
539  }
540 
541  if (kw_flag & VM_CALL_KW_SPLAT) {
542  if (ignore_keyword_hash_p(rest_last, iseq, &kw_flag, &converted_keyword_hash)) {
543  arg_rest_dup(args);
544  rb_ary_pop(args->rest);
545  given_argc--;
546  kw_flag &= ~(VM_CALL_KW_SPLAT | VM_CALL_KW_SPLAT_MUT);
547  }
548  else {
549  if (rest_last != converted_keyword_hash) {
550  rest_last = converted_keyword_hash;
551  arg_rest_dup(args);
552  RARRAY_ASET(args->rest, len - 1, rest_last);
553  }
554 
555  if (iseq->body->param.flags.ruby2_keywords && rest_last) {
556  flag_keyword_hash = rest_last;
557  }
558  else if (iseq->body->param.flags.has_kw || iseq->body->param.flags.has_kwrest) {
559  arg_rest_dup(args);
560  rb_ary_pop(args->rest);
561  given_argc--;
562  keyword_hash = rest_last;
563  }
564  }
565  }
566  }
567  else {
568  if (kw_flag & VM_CALL_KW_SPLAT) {
569  VALUE last_arg = args->argv[args->argc-1];
570  if (ignore_keyword_hash_p(last_arg, iseq, &kw_flag, &converted_keyword_hash)) {
571  args->argc--;
572  given_argc--;
573  kw_flag &= ~(VM_CALL_KW_SPLAT | VM_CALL_KW_SPLAT_MUT);
574  }
575  else {
576  if (last_arg != converted_keyword_hash) {
577  last_arg = converted_keyword_hash;
578  args->argv[args->argc-1] = last_arg;
579  }
580 
581  if (iseq->body->param.flags.ruby2_keywords) {
582  flag_keyword_hash = last_arg;
583  }
584  else if (iseq->body->param.flags.has_kw || iseq->body->param.flags.has_kwrest) {
585  args->argc--;
586  given_argc--;
587  keyword_hash = last_arg;
588  }
589  }
590  }
591  args->rest = Qfalse;
592  }
593 
594  if (flag_keyword_hash && RB_TYPE_P(flag_keyword_hash, T_HASH)) {
595  ((struct RHash *)flag_keyword_hash)->basic.flags |= RHASH_PASS_AS_KEYWORDS;
596  }
597 
598  if (kw_flag && iseq->body->param.flags.accepts_no_kwarg) {
599  rb_raise(rb_eArgError, "no keywords accepted");
600  }
601 
602 
603  switch (arg_setup_type) {
604  case arg_setup_method:
605  break; /* do nothing special */
606  case arg_setup_block:
607  if (given_argc == (NIL_P(keyword_hash) ? 1 : 2) &&
608  allow_autosplat &&
609  (min_argc > 0 || iseq->body->param.opt_num > 1) &&
610  !iseq->body->param.flags.ambiguous_param0 &&
611  args_check_block_arg0(args)) {
612  given_argc = RARRAY_LENINT(args->rest);
613  }
614  break;
615  }
616 
617  /* argc check */
618  if (given_argc < min_argc) {
619  if (arg_setup_type == arg_setup_block) {
620  CHECK_VM_STACK_OVERFLOW(ec->cfp, min_argc);
621  given_argc = min_argc;
622  args_extend(args, min_argc);
623  }
624  else {
625  argument_arity_error(ec, iseq, given_argc, min_argc, max_argc);
626  }
627  }
628 
629  if (given_argc > max_argc && max_argc != UNLIMITED_ARGUMENTS) {
630  if (arg_setup_type == arg_setup_block) {
631  /* truncate */
632  args_reduce(args, given_argc - max_argc);
633  given_argc = max_argc;
634  }
635  else {
636  argument_arity_error(ec, iseq, given_argc, min_argc, max_argc);
637  }
638  }
639 
640  if (iseq->body->param.flags.has_lead) {
641  args_setup_lead_parameters(args, iseq->body->param.lead_num, locals + 0);
642  }
643 
644  if (iseq->body->param.flags.has_rest || iseq->body->param.flags.has_post){
645  args_copy(args);
646  }
647 
648  if (iseq->body->param.flags.has_post) {
649  args_setup_post_parameters(args, iseq->body->param.post_num, locals + iseq->body->param.post_start);
650  }
651 
652  if (iseq->body->param.flags.has_opt) {
653  int opt = args_setup_opt_parameters(args, iseq->body->param.opt_num, locals + iseq->body->param.lead_num);
654  opt_pc = (int)iseq->body->param.opt_table[opt];
655  }
656 
657  if (iseq->body->param.flags.has_rest) {
658  args_setup_rest_parameter(args, locals + iseq->body->param.rest_start);
659  }
660 
661  if (iseq->body->param.flags.has_kw) {
662  VALUE * const klocals = locals + iseq->body->param.keyword->bits_start - iseq->body->param.keyword->num;
663 
664  if (args->kw_argv != NULL) {
665  const struct rb_callinfo_kwarg *kw_arg = args->kw_arg;
666  args_setup_kw_parameters(ec, iseq, args->kw_argv, kw_arg->keyword_len, kw_arg->keywords, klocals);
667  }
668  else if (!NIL_P(keyword_hash)) {
669  int kw_len = rb_long2int(RHASH_SIZE(keyword_hash));
670  struct fill_values_arg arg;
671  /* copy kw_argv */
672  arg.keys = args->kw_argv = ALLOCA_N(VALUE, kw_len * 2);
673  arg.vals = arg.keys + kw_len;
674  arg.argc = 0;
675  rb_hash_foreach(keyword_hash, fill_keys_values, (VALUE)&arg);
676  VM_ASSERT(arg.argc == kw_len);
677  args_setup_kw_parameters(ec, iseq, arg.vals, kw_len, arg.keys, klocals);
678  }
679  else {
680  VM_ASSERT(args_argc(args) == 0);
681  args_setup_kw_parameters(ec, iseq, NULL, 0, NULL, klocals);
682  }
683  }
684  else if (iseq->body->param.flags.has_kwrest) {
685  args_setup_kw_rest_parameter(keyword_hash, locals + iseq->body->param.keyword->rest_start, kw_flag);
686  }
687  else if (!NIL_P(keyword_hash) && RHASH_SIZE(keyword_hash) > 0 && arg_setup_type == arg_setup_method) {
688  argument_kw_error(ec, iseq, "unknown", rb_hash_keys(keyword_hash));
689  }
690 
691  if (iseq->body->param.flags.has_block) {
692  if (iseq->body->local_iseq == iseq) {
693  /* Do nothing */
694  }
695  else {
696  args_setup_block_parameter(ec, calling, locals + iseq->body->param.block_start);
697  }
698  }
699 
700 #if 0
701  {
702  int i;
703  for (i=0; i<iseq->body->param.size; i++) {
704  ruby_debug_printf("local[%d] = %p\n", i, (void *)locals[i]);
705  }
706  }
707 #endif
708 
709  ec->cfp->sp = orig_sp;
710  return opt_pc;
711 }
712 
713 static void
714 raise_argument_error(rb_execution_context_t *ec, const rb_iseq_t *iseq, const VALUE exc)
715 {
716  VALUE at;
717 
718  if (iseq) {
719  vm_push_frame(ec, iseq, VM_FRAME_MAGIC_DUMMY | VM_ENV_FLAG_LOCAL, Qnil /* self */,
720  VM_BLOCK_HANDLER_NONE /* specval*/, Qfalse /* me or cref */,
721  iseq->body->iseq_encoded,
722  ec->cfp->sp, 0, 0 /* stack_max */);
723  at = rb_ec_backtrace_object(ec);
724  rb_backtrace_use_iseq_first_lineno_for_last_location(at);
725  rb_vm_pop_frame(ec);
726  }
727  else {
728  at = rb_ec_backtrace_object(ec);
729  }
730 
731  rb_ivar_set(exc, idBt_locations, at);
732  rb_exc_set_backtrace(exc, at);
733  rb_exc_raise(exc);
734 }
735 
736 static void
737 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)
738 {
739  VALUE exc = rb_arity_error_new(miss_argc, min_argc, max_argc);
740  if (iseq->body->param.flags.has_kw) {
741  const struct rb_iseq_param_keyword *const kw = iseq->body->param.keyword;
742  const ID *keywords = kw->table;
743  int req_key_num = kw->required_num;
744  if (req_key_num > 0) {
745  static const char required[] = "; required keywords";
746  VALUE mesg = rb_attr_get(exc, idMesg);
747  rb_str_resize(mesg, RSTRING_LEN(mesg)-1);
748  rb_str_cat(mesg, required, sizeof(required) - 1 - (req_key_num == 1));
749  rb_str_cat_cstr(mesg, ":");
750  do {
751  rb_str_cat_cstr(mesg, " ");
752  rb_str_append(mesg, rb_id2str(*keywords++));
753  rb_str_cat_cstr(mesg, ",");
754  } while (--req_key_num);
755  RSTRING_PTR(mesg)[RSTRING_LEN(mesg)-1] = ')';
756  }
757  }
758  raise_argument_error(ec, iseq, exc);
759 }
760 
761 static void
762 argument_kw_error(rb_execution_context_t *ec, const rb_iseq_t *iseq, const char *error, const VALUE keys)
763 {
764  raise_argument_error(ec, iseq, rb_keyword_error_new(error, keys));
765 }
766 
767 static inline void
768 vm_caller_setup_arg_splat(rb_control_frame_t *cfp, struct rb_calling_info *calling)
769 {
770  int argc = calling->argc;
771  VALUE *argv = cfp->sp - argc;
772  VALUE ary = argv[argc-1];
773 
774  vm_check_canary(GET_EC(), cfp->sp);
775  cfp->sp--;
776 
777  if (!NIL_P(ary)) {
778  const VALUE *ptr = RARRAY_CONST_PTR_TRANSIENT(ary);
779  long len = RARRAY_LEN(ary), i;
780 
781  CHECK_VM_STACK_OVERFLOW(cfp, len);
782 
783  for (i = 0; i < len; i++) {
784  *cfp->sp++ = ptr[i];
785  }
786  calling->argc += i - 1;
787  }
788 }
789 
790 static inline void
791 vm_caller_setup_arg_kw(rb_control_frame_t *cfp, struct rb_calling_info *calling, const struct rb_callinfo *ci)
792 {
793  const VALUE *const passed_keywords = vm_ci_kwarg(ci)->keywords;
794  const int kw_len = vm_ci_kwarg(ci)->keyword_len;
795  const VALUE h = rb_hash_new_with_size(kw_len);
796  VALUE *sp = cfp->sp;
797  int i;
798 
799  for (i=0; i<kw_len; i++) {
800  rb_hash_aset(h, passed_keywords[i], (sp - kw_len)[i]);
801  }
802  (sp-kw_len)[0] = h;
803 
804  cfp->sp -= kw_len - 1;
805  calling->argc -= kw_len - 1;
806  calling->kw_splat = 1;
807 }
808 
809 static VALUE
810 vm_to_proc(VALUE proc)
811 {
812  if (UNLIKELY(!rb_obj_is_proc(proc))) {
813  VALUE b;
814  const rb_callable_method_entry_t *me =
815  rb_callable_method_entry_with_refinements(CLASS_OF(proc), idTo_proc, NULL);
816 
817  if (me) {
818  b = rb_vm_call0(GET_EC(), proc, idTo_proc, 0, NULL, me, RB_NO_KEYWORDS);
819  }
820  else {
821  /* NOTE: calling method_missing */
822  b = rb_check_convert_type_with_id(proc, T_DATA, "Proc", idTo_proc);
823  }
824 
825  if (NIL_P(b) || !rb_obj_is_proc(b)) {
827  "wrong argument type %s (expected Proc)",
828  rb_obj_classname(proc));
829  }
830  return b;
831  }
832  else {
833  return proc;
834  }
835 }
836 
837 static VALUE
838 refine_sym_proc_call(RB_BLOCK_CALL_FUNC_ARGLIST(yielded_arg, callback_arg))
839 {
840  VALUE obj;
841  ID mid;
842  const rb_callable_method_entry_t *me = 0; /* for hidden object case */
844  const VALUE symbol = RARRAY_AREF(callback_arg, 0);
845  const VALUE refinements = RARRAY_AREF(callback_arg, 1);
846  int kw_splat = RB_PASS_CALLED_KEYWORDS;
847  VALUE klass;
848 
849  if (argc-- < 1) {
850  rb_raise(rb_eArgError, "no receiver given");
851  }
852  obj = *argv++;
853 
854  mid = SYM2ID(symbol);
855  for (klass = CLASS_OF(obj); klass; klass = RCLASS_SUPER(klass)) {
856  me = rb_callable_method_entry(klass, mid);
857  if (me) {
858  me = rb_resolve_refined_method_callable(refinements, me);
859  if (me) break;
860  }
861  }
862 
863  ec = GET_EC();
864  if (!NIL_P(blockarg)) {
865  vm_passed_block_handler_set(ec, blockarg);
866  }
867  if (!me) {
868  return method_missing(ec, obj, mid, argc, argv, MISSING_NOENTRY, kw_splat);
869  }
870  return rb_vm_call0(ec, obj, mid, argc, argv, me, kw_splat);
871 }
872 
873 static VALUE
874 vm_caller_setup_arg_block(const rb_execution_context_t *ec, rb_control_frame_t *reg_cfp,
875  const struct rb_callinfo *ci, const rb_iseq_t *blockiseq, const int is_super)
876 {
877  if (vm_ci_flag(ci) & VM_CALL_ARGS_BLOCKARG) {
878  VALUE block_code = *(--reg_cfp->sp);
879 
880  if (NIL_P(block_code)) {
881  return VM_BLOCK_HANDLER_NONE;
882  }
883  else if (block_code == rb_block_param_proxy) {
884  VM_ASSERT(!VM_CFP_IN_HEAP_P(GET_EC(), reg_cfp));
885  VALUE handler = VM_CF_BLOCK_HANDLER(reg_cfp);
886  reg_cfp->block_code = (const void *) handler;
887  return handler;
888  }
889  else if (SYMBOL_P(block_code) && rb_method_basic_definition_p(rb_cSymbol, idTo_proc)) {
890  const rb_cref_t *cref = vm_env_cref(reg_cfp->ep);
891  if (cref && !NIL_P(cref->refinements)) {
892  VALUE ref = cref->refinements;
893  VALUE func = rb_hash_lookup(ref, block_code);
894  if (NIL_P(func)) {
895  /* TODO: limit cached funcs */
896  VALUE callback_arg = rb_ary_tmp_new(2);
897  rb_ary_push(callback_arg, block_code);
898  rb_ary_push(callback_arg, ref);
899  OBJ_FREEZE_RAW(callback_arg);
900  func = rb_func_lambda_new(refine_sym_proc_call, callback_arg, 1, UNLIMITED_ARGUMENTS);
901  rb_hash_aset(ref, block_code, func);
902  }
903  block_code = func;
904  }
905  return block_code;
906  }
907  else {
908  return vm_to_proc(block_code);
909  }
910  }
911  else if (blockiseq != NULL) { /* likely */
912  struct rb_captured_block *captured = VM_CFP_TO_CAPTURED_BLOCK(reg_cfp);
913  captured->code.iseq = blockiseq;
914  return VM_BH_FROM_ISEQ_BLOCK(captured);
915  }
916  else {
917  if (is_super) {
918  return GET_BLOCK_HANDLER();
919  }
920  else {
921  return VM_BLOCK_HANDLER_NONE;
922  }
923  }
924 }
#define Qundef
Old name of RUBY_Qundef.
#define INT2FIX
Old name of RB_INT2FIX.
Definition: long.h:48
#define ID2SYM
Old name of RB_ID2SYM.
Definition: symbol.h:44
#define OBJ_FREEZE_RAW
Old name of RB_OBJ_FREEZE_RAW.
Definition: fl_type.h:144
#define SYM2ID
Old name of RB_SYM2ID.
Definition: symbol.h:45
#define T_DATA
Old name of RUBY_T_DATA.
Definition: value_type.h:60
#define CLASS_OF
Old name of rb_class_of.
Definition: globals.h:203
#define T_HASH
Old name of RUBY_T_HASH.
Definition: value_type.h:65
#define Qtrue
Old name of RUBY_Qtrue.
#define Qnil
Old name of RUBY_Qnil.
#define Qfalse
Old name of RUBY_Qfalse.
#define NIL_P
Old name of RB_NIL_P.
#define SYMBOL_P
Old name of RB_SYMBOL_P.
Definition: value_type.h:88
void rb_raise(VALUE exc, const char *fmt,...)
Exception entry point.
Definition: error.c:3025
void rb_exc_raise(VALUE mesg)
Raises an exception in the current thread.
Definition: eval.c:675
VALUE rb_eTypeError
TypeError exception.
Definition: error.c:1099
VALUE rb_eArgError
ArgumentError exception.
Definition: error.c:1100
VALUE rb_cSymbol
Sumbol class.
Definition: string.c:81
VALUE rb_ary_new_from_values(long n, const VALUE *elts)
Identical to rb_ary_new_from_args(), except how objects are passed.
Definition: array.c:789
VALUE rb_ary_dup(VALUE ary)
Duplicates an array.
Definition: array.c:2663
VALUE rb_ary_unshift(VALUE ary, VALUE elem)
Destructively prepends the passed item at the beginning of the passed array.
Definition: array.c:1661
VALUE rb_check_array_type(VALUE obj)
Try converting an object to its array representation using its to_ary method, if any.
Definition: array.c:989
VALUE rb_ary_new(void)
Allocates a new, empty array.
Definition: array.c:750
VALUE rb_ary_resize(VALUE ary, long len)
Expands or shrinks the passed array to the passed length.
Definition: array.c:2234
VALUE rb_ary_pop(VALUE ary)
Destructively deletes an element from the end of the passed array and returns what was deleted.
Definition: array.c:1357
VALUE rb_ary_tmp_new(long capa)
Allocates a "temporary" array.
Definition: array.c:847
VALUE rb_ary_push(VALUE ary, VALUE elem)
Special case of rb_ary_cat() that it adds only one element.
Definition: array.c:1308
#define UNLIMITED_ARGUMENTS
This macro is used in conjunction with rb_check_arity().
Definition: error.h:35
void rb_hash_foreach(VALUE hash, int(*func)(VALUE key, VALUE val, VALUE arg), VALUE arg)
Iterates over a hash.
VALUE rb_hash_aset(VALUE hash, VALUE key, VALUE val)
Inserts or replaces ("upsert"s) the objects into the given hash table.
Definition: hash.c:2903
VALUE rb_hash_lookup(VALUE hash, VALUE key)
Identical to rb_hash_aref(), except it always returns RUBY_Qnil for misshits.
Definition: hash.c:2108
VALUE rb_hash_dup(VALUE hash)
Duplicates a hash.
Definition: hash.c:1585
VALUE rb_hash_new(void)
Creates a new, empty hash object.
Definition: hash.c:1529
VALUE rb_obj_is_proc(VALUE recv)
Queries if the given object is a proc.
Definition: proc.c:175
VALUE rb_str_append(VALUE dst, VALUE src)
Identical to rb_str_buf_append(), except it converts the right hand side before concatenating.
Definition: string.c:3317
VALUE rb_str_cat(VALUE dst, const char *src, long srclen)
Destructively appends the passed contents to the string.
Definition: string.c:3161
VALUE rb_str_resize(VALUE str, long len)
Overwrites the length of the string.
Definition: string.c:3056
VALUE rb_str_cat_cstr(VALUE dst, const char *src)
Identical to rb_str_cat(), except it assumes the passed pointer is a pointer to a C string.
Definition: string.c:3171
VALUE rb_attr_get(VALUE obj, ID name)
Identical to rb_ivar_get()
Definition: variable.c:1293
VALUE rb_ivar_set(VALUE obj, ID name, VALUE val)
Identical to rb_iv_set(), except it accepts the name as an ID instead of a C string.
Definition: variable.c:1575
int rb_method_basic_definition_p(VALUE klass, ID mid)
Well...
Definition: vm_method.c:2643
VALUE rb_id2str(ID id)
Identical to rb_id2name(), except it returns a Ruby's String instead of C's.
Definition: symbol.c:935
#define RB_BLOCK_CALL_FUNC_ARGLIST(yielded_arg, callback_arg)
Shim for block function parameters.
Definition: iterator.h:58
#define rb_long2int
Just another name of rb_long2int_inline.
Definition: long.h:62
#define MEMCPY(p1, p2, type, n)
Handy macro to call memcpy.
Definition: memory.h:366
#define ALLOCA_N(type, n)
Definition: memory.h:286
#define RARRAY_LEN
Just another name of rb_array_len.
Definition: rarray.h:68
#define RARRAY_CONST_PTR_TRANSIENT
Just another name of rb_array_const_ptr_transient.
Definition: rarray.h:70
static int RARRAY_LENINT(VALUE ary)
Identical to rb_array_len(), except it differs for the return type.
Definition: rarray.h:324
static void RARRAY_ASET(VALUE ary, long i, VALUE v)
Assigns an object in an array.
Definition: rarray.h:571
#define RARRAY_AREF(a, i)
Definition: rarray.h:588
#define RCLASS_SUPER
Just another name of rb_class_get_superclass.
Definition: rclass.h:46
#define RHASH_SIZE(h)
Queries the size of the hash.
Definition: rhash.h:82
#define RHASH_EMPTY_P(h)
Checks if the hash is empty.
Definition: rhash.h:92
static char * RSTRING_PTR(VALUE str)
Queries the contents pointer of the string.
Definition: rstring.h:497
static long RSTRING_LEN(VALUE str)
Queries the length of the string.
Definition: rstring.h:483
const char * rb_obj_classname(VALUE obj)
Queries the name of the class of the passed object.
Definition: variable.c:309
#define RB_PASS_CALLED_KEYWORDS
Pass keywords if current method is called with keywords, useful for argument delegation.
Definition: scan_args.h:78
#define RB_NO_KEYWORDS
Do not pass keywords.
Definition: scan_args.h:69
Definition: hash.h:43
Definition: method.h:62
CREF (Class REFerence)
Definition: method.h:44
struct rb_iseq_constant_body::@152 param
parameter information
uintptr_t ID
Type that represents a Ruby identifier such as a variable name.
Definition: value.h:52
uintptr_t VALUE
Type that represents a Ruby object.
Definition: value.h:40
static bool RB_TYPE_P(VALUE obj, enum ruby_value_type t)
Queries if the given object is of given type.
Definition: value_type.h:375