Ruby  2.4.2p198(2017-09-14revision59899)
vm_args.c
Go to the documentation of this file.
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_thread_t *th, const rb_iseq_t *iseq, const VALUE exc));
12 NORETURN(static void argument_arity_error(rb_thread_t *th, 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_thread_t *th, 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(VALUE obj, ID id, int argc, const VALUE *argv,
16  enum method_missing_reason call_status);
17 
18 struct args_info {
19  /* basic args info */
21  int argc;
22  const struct rb_call_info_kw_arg *kw_arg;
23 
24  /* additional args info */
28 };
29 
34 };
35 
36 static inline int
37 args_argc(struct args_info *args)
38 {
39  if (args->rest == Qfalse) {
40  return args->argc;
41  }
42  else {
43  return args->argc + RARRAY_LENINT(args->rest) - args->rest_index;
44  }
45 }
46 
47 static inline void
48 args_extend(struct args_info *args, const int min_argc)
49 {
50  int i;
51 
52  if (args->rest) {
53  args->rest = rb_ary_dup(args->rest);
54  VM_ASSERT(args->rest_index == 0);
55  for (i=args->argc + RARRAY_LENINT(args->rest); i<min_argc; i++) {
56  rb_ary_push(args->rest, Qnil);
57  }
58  }
59  else {
60  for (i=args->argc; i<min_argc; i++) {
61  args->argv[args->argc++] = Qnil;
62  }
63  }
64 }
65 
66 static inline void
67 args_reduce(struct args_info *args, int over_argc)
68 {
69  if (args->rest) {
70  const long len = RARRAY_LEN(args->rest);
71 
72  if (len > over_argc) {
73  args->rest = rb_ary_dup(args->rest);
74  rb_ary_resize(args->rest, len - over_argc);
75  return;
76  }
77  else {
78  args->rest = Qfalse;
79  over_argc -= len;
80  }
81  }
82 
83  VM_ASSERT(args->argc >= over_argc);
84  args->argc -= over_argc;
85 }
86 
87 static inline int
89 {
90  VALUE ary = Qnil;
91 
92  if (args->rest && RARRAY_LEN(args->rest) == 1) {
93  VALUE arg0 = RARRAY_AREF(args->rest, 0);
94  ary = rb_check_array_type(arg0);
95  }
96  else if (args->argc == 1) {
97  VALUE arg0 = args->argv[0];
98  ary = rb_check_array_type(arg0);
99  args->argv[0] = arg0; /* see: https://bugs.ruby-lang.org/issues/8484 */
100  }
101 
102  if (!NIL_P(ary)) {
103  args->rest = ary;
104  args->rest_index = 0;
105  args->argc = 0;
106  return TRUE;
107  }
108 
109  return FALSE;
110 }
111 
112 static inline void
113 args_copy(struct args_info *args)
114 {
115  if (args->rest != Qfalse) {
116  int argc = args->argc;
117  args->argc = 0;
118  args->rest = rb_ary_dup(args->rest); /* make dup */
119 
120  /*
121  * argv: [m0, m1, m2, m3]
122  * rest: [a0, a1, a2, a3, a4, a5]
123  * ^
124  * rest_index
125  *
126  * #=> first loop
127  *
128  * argv: [m0, m1]
129  * rest: [m2, m3, a2, a3, a4, a5]
130  * ^
131  * rest_index
132  *
133  * #=> 2nd loop
134  *
135  * argv: [] (argc == 0)
136  * rest: [m0, m1, m2, m3, a2, a3, a4, a5]
137  * ^
138  * rest_index
139  */
140  while (args->rest_index > 0 && argc > 0) {
141  RARRAY_ASET(args->rest, --args->rest_index, args->argv[--argc]);
142  }
143  while (argc > 0) {
144  rb_ary_unshift(args->rest, args->argv[--argc]);
145  }
146  }
147  else if (args->argc > 0) {
148  args->rest = rb_ary_new_from_values(args->argc, args->argv);
149  args->rest_index = 0;
150  args->argc = 0;
151  }
152 }
153 
154 static inline const VALUE *
156 {
157  return RARRAY_CONST_PTR(args->rest) + args->rest_index;
158 }
159 
160 static inline VALUE
162 {
163  VALUE ary;
164 
165  if (args->rest) {
166  ary = rb_ary_subseq(args->rest, args->rest_index, RARRAY_LEN(args->rest) - args->rest_index);
167  args->rest = 0;
168  }
169  else {
170  ary = rb_ary_new();
171  }
172  return ary;
173 }
174 
175 static int
176 keyword_hash_p(VALUE *kw_hash_ptr, VALUE *rest_hash_ptr, rb_thread_t *th)
177 {
178  *rest_hash_ptr = rb_check_hash_type(*kw_hash_ptr);
179 
180  if (!NIL_P(*rest_hash_ptr)) {
181  VALUE hash = rb_extract_keywords(rest_hash_ptr);
182  if (!hash) hash = Qnil;
183  *kw_hash_ptr = hash;
184  return TRUE;
185  }
186  else {
187  *kw_hash_ptr = Qnil;
188  return FALSE;
189  }
190 }
191 
192 static VALUE
193 args_pop_keyword_hash(struct args_info *args, VALUE *kw_hash_ptr, rb_thread_t *th)
194 {
195  VALUE rest_hash;
196 
197  if (args->rest == Qfalse) {
198  from_argv:
199  VM_ASSERT(args->argc > 0);
200  *kw_hash_ptr = args->argv[args->argc-1];
201 
202  if (keyword_hash_p(kw_hash_ptr, &rest_hash, th)) {
203  if (rest_hash) {
204  args->argv[args->argc-1] = rest_hash;
205  }
206  else {
207  args->argc--;
208  return TRUE;
209  }
210  }
211  }
212  else {
213  long len = RARRAY_LEN(args->rest);
214 
215  if (len > 0) {
216  *kw_hash_ptr = RARRAY_AREF(args->rest, len - 1);
217 
218  if (keyword_hash_p(kw_hash_ptr, &rest_hash, th)) {
219  if (rest_hash) {
220  RARRAY_ASET(args->rest, len - 1, rest_hash);
221  }
222  else {
223  args->rest = rb_ary_dup(args->rest);
224  rb_ary_pop(args->rest);
225  return TRUE;
226  }
227  }
228  }
229  else {
230  goto from_argv;
231  }
232  }
233 
234  return FALSE;
235 }
236 
237 static int
239 {
240  const struct rb_call_info_kw_arg *kw_arg = args->kw_arg;
241  const VALUE *const passed_keywords = kw_arg->keywords;
242  const int kw_len = kw_arg->keyword_len;
243  VALUE h = rb_hash_new();
244  const int kw_start = args->argc - kw_len;
245  const VALUE * const kw_argv = args->argv + kw_start;
246  int i;
247 
248  args->argc = kw_start + 1;
249  for (i=0; i<kw_len; i++) {
250  rb_hash_aset(h, passed_keywords[i], kw_argv[i]);
251  }
252 
253  args->argv[args->argc - 1] = h;
254 
255  return args->argc;
256 }
257 
258 static void
260 {
261  VALUE h = rb_hash_new();
262  int i;
263  const struct rb_call_info_kw_arg *kw_arg = args->kw_arg;
264  const VALUE *const passed_keywords = kw_arg->keywords;
265  const int passed_keyword_len = kw_arg->keyword_len;
266 
267  for (i=0; i<passed_keyword_len; i++) {
268  rb_hash_aset(h, passed_keywords[i], args->kw_argv[i]);
269  }
270  args->kw_argv = NULL;
271 
272  if (args->rest) {
273  args->rest = rb_ary_dup(args->rest);
274  rb_ary_push(args->rest, h);
275  }
276  else {
277  args->argv[args->argc++] = h;
278  }
279 }
280 
281 static inline void
282 args_setup_lead_parameters(struct args_info *args, int argc, VALUE *locals)
283 {
284  if (args->argc >= argc) {
285  /* do noting */
286  args->argc -= argc;
287  args->argv += argc;
288  }
289  else {
290  int i, j;
291  const VALUE *argv = args_rest_argv(args);
292 
293  for (i=args->argc, j=0; i<argc; i++, j++) {
294  locals[i] = argv[j];
295  }
296  args->rest_index += argc - args->argc;
297  args->argc = 0;
298  }
299 }
300 
301 static inline void
302 args_setup_post_parameters(struct args_info *args, int argc, VALUE *locals)
303 {
304  long len;
305  args_copy(args);
306  len = RARRAY_LEN(args->rest);
307  MEMCPY(locals, RARRAY_CONST_PTR(args->rest) + len - argc, VALUE, argc);
308  rb_ary_resize(args->rest, len - argc);
309 }
310 
311 static inline int
312 args_setup_opt_parameters(struct args_info *args, int opt_max, VALUE *locals)
313 {
314  int i;
315 
316  if (args->argc >= opt_max) {
317  args->argc -= opt_max;
318  args->argv += opt_max;
319  i = opt_max;
320  }
321  else {
322  int j;
323  i = args->argc;
324  args->argc = 0;
325 
326  if (args->rest) {
327  int len = RARRAY_LENINT(args->rest);
328  const VALUE *argv = RARRAY_CONST_PTR(args->rest);
329 
330  for (; i<opt_max && args->rest_index < len; i++, args->rest_index++) {
331  locals[i] = argv[args->rest_index];
332  }
333  }
334 
335  /* initialize by nil */
336  for (j=i; j<opt_max; j++) {
337  locals[j] = Qnil;
338  }
339  }
340 
341  return i;
342 }
343 
344 static inline void
346 {
347  args_copy(args);
348  *locals = args_rest_array(args);
349 }
350 
351 static VALUE
352 make_unknown_kw_hash(const VALUE *passed_keywords, int passed_keyword_len, const VALUE *kw_argv)
353 {
354  int i;
355  VALUE obj = rb_ary_tmp_new(1);
356 
357  for (i=0; i<passed_keyword_len; i++) {
358  if (kw_argv[i] != Qundef) {
359  rb_ary_push(obj, passed_keywords[i]);
360  }
361  }
362  return obj;
363 }
364 
365 static VALUE
366 make_rest_kw_hash(const VALUE *passed_keywords, int passed_keyword_len, const VALUE *kw_argv)
367 {
368  int i;
369  VALUE obj = rb_hash_new();
370 
371  for (i=0; i<passed_keyword_len; i++) {
372  if (kw_argv[i] != Qundef) {
373  rb_hash_aset(obj, passed_keywords[i], kw_argv[i]);
374  }
375  }
376  return obj;
377 }
378 
379 static inline int
380 args_setup_kw_parameters_lookup(const ID key, VALUE *ptr, const VALUE *const passed_keywords, VALUE *passed_values, const int passed_keyword_len)
381 {
382  int i;
383  const VALUE keyname = ID2SYM(key);
384 
385  for (i=0; i<passed_keyword_len; i++) {
386  if (keyname == passed_keywords[i]) {
387  *ptr = passed_values[i];
388  passed_values[i] = Qundef;
389  return TRUE;
390  }
391  }
392 
393  return FALSE;
394 }
395 
396 static void
397 args_setup_kw_parameters(VALUE* const passed_values, const int passed_keyword_len, const VALUE *const passed_keywords,
398  const rb_iseq_t * const iseq, VALUE * const locals)
399 {
400  const ID *acceptable_keywords = iseq->body->param.keyword->table;
401  const int req_key_num = iseq->body->param.keyword->required_num;
402  const int key_num = iseq->body->param.keyword->num;
403  const VALUE * const default_values = iseq->body->param.keyword->default_values;
404  VALUE missing = 0;
405  int i, di, found = 0;
406  int unspecified_bits = 0;
407  VALUE unspecified_bits_value = Qnil;
408 
409  for (i=0; i<req_key_num; i++) {
410  ID key = acceptable_keywords[i];
411  if (args_setup_kw_parameters_lookup(key, &locals[i], passed_keywords, passed_values, passed_keyword_len)) {
412  found++;
413  }
414  else {
415  if (!missing) missing = rb_ary_tmp_new(1);
416  rb_ary_push(missing, ID2SYM(key));
417  }
418  }
419 
420  if (missing) argument_kw_error(GET_THREAD(), iseq, "missing", missing);
421 
422  for (di=0; i<key_num; i++, di++) {
423  if (args_setup_kw_parameters_lookup(acceptable_keywords[i], &locals[i], passed_keywords, passed_values, passed_keyword_len)) {
424  found++;
425  }
426  else {
427  if (default_values[di] == Qundef) {
428  locals[i] = Qnil;
429 
430  if (LIKELY(i < 32)) { /* TODO: 32 -> Fixnum's max bits */
431  unspecified_bits |= 0x01 << di;
432  }
433  else {
434  if (NIL_P(unspecified_bits_value)) {
435  /* fixnum -> hash */
436  int j;
437  unspecified_bits_value = rb_hash_new();
438 
439  for (j=0; j<32; j++) {
440  if (unspecified_bits & (0x01 << j)) {
441  rb_hash_aset(unspecified_bits_value, INT2FIX(j), Qtrue);
442  }
443  }
444  }
445  rb_hash_aset(unspecified_bits_value, INT2FIX(di), Qtrue);
446  }
447  }
448  else {
449  locals[i] = default_values[di];
450  }
451  }
452  }
453 
454  if (iseq->body->param.flags.has_kwrest) {
455  const int rest_hash_index = key_num + 1;
456  locals[rest_hash_index] = make_rest_kw_hash(passed_keywords, passed_keyword_len, passed_values);
457  }
458  else {
459  if (found != passed_keyword_len) {
460  VALUE keys = make_unknown_kw_hash(passed_keywords, passed_keyword_len, passed_values);
461  argument_kw_error(GET_THREAD(), iseq, "unknown", keys);
462  }
463  }
464 
465  if (NIL_P(unspecified_bits_value)) {
466  unspecified_bits_value = INT2FIX(unspecified_bits);
467  }
468  locals[key_num] = unspecified_bits_value;
469 }
470 
471 static inline void
473 {
474  locals[0] = NIL_P(keyword_hash) ? rb_hash_new() : rb_hash_dup(keyword_hash);
475 }
476 
477 static inline void
479 {
480  VALUE block_handler = calling->block_handler;
481  VALUE blockval = Qnil;
482 
483  if (block_handler != VM_BLOCK_HANDLER_NONE) {
484 
485  switch (vm_block_handler_type(block_handler)) {
488  blockval = rb_vm_make_proc(th, VM_BH_TO_CAPT_BLOCK(block_handler), rb_cProc);
489  break;
491  blockval = rb_sym_to_proc(VM_BH_TO_SYMBOL(block_handler));
492  break;
494  blockval = VM_BH_TO_PROC(block_handler);
495  break;
496  }
497  }
498  *locals = blockval;
499 }
500 
504  int argc;
505 };
506 
507 static int
509 {
510  struct fill_values_arg *arg = (struct fill_values_arg *)ptr;
511  int i = arg->argc++;
512  arg->keys[i] = (VALUE)key;
513  arg->vals[i] = (VALUE)val;
514  return ST_CONTINUE;
515 }
516 
517 static int
518 setup_parameters_complex(rb_thread_t * const th, const rb_iseq_t * const iseq,
519  struct rb_calling_info *const calling,
520  const struct rb_call_info *ci,
521  VALUE * const locals, const enum arg_setup_type arg_setup_type)
522 {
523  const int min_argc = iseq->body->param.lead_num + iseq->body->param.post_num;
524  const int max_argc = (iseq->body->param.flags.has_rest == FALSE) ? min_argc + iseq->body->param.opt_num : UNLIMITED_ARGUMENTS;
525  int opt_pc = 0;
526  int given_argc;
527  struct args_info args_body, *args;
528  VALUE keyword_hash = Qnil;
529  VALUE * const orig_sp = th->cfp->sp;
530  unsigned int i;
531 
532  /*
533  * Extend SP for GC.
534  *
535  * [pushed values] [uninitialized values]
536  * <- ci->argc -->
537  * <- iseq->body->param.size------------>
538  * ^ locals ^ sp
539  *
540  * =>
541  * [pushed values] [initialized values ]
542  * <- ci->argc -->
543  * <- iseq->body->param.size------------>
544  * ^ locals ^ sp
545  */
546  for (i=calling->argc; i<iseq->body->param.size; i++) {
547  locals[i] = Qnil;
548  }
549  th->cfp->sp = &locals[i];
550 
551  /* setup args */
552  args = &args_body;
553  given_argc = args->argc = calling->argc;
554  args->argv = locals;
555 
556  if (ci->flag & VM_CALL_KWARG) {
557  args->kw_arg = ((struct rb_call_info_with_kwarg *)ci)->kw_arg;
558 
559  if (iseq->body->param.flags.has_kw) {
560  int kw_len = args->kw_arg->keyword_len;
561  /* copy kw_argv */
562  args->kw_argv = ALLOCA_N(VALUE, kw_len);
563  args->argc -= kw_len;
564  given_argc -= kw_len;
565  MEMCPY(args->kw_argv, locals + args->argc, VALUE, kw_len);
566  }
567  else {
568  args->kw_argv = NULL;
569  given_argc = args_kw_argv_to_hash(args);
570  }
571  }
572  else {
573  args->kw_arg = NULL;
574  args->kw_argv = NULL;
575  }
576 
577  if (ci->flag & VM_CALL_ARGS_SPLAT) {
578  args->rest = locals[--args->argc];
579  args->rest_index = 0;
580  given_argc += RARRAY_LENINT(args->rest) - 1;
581  }
582  else {
583  args->rest = Qfalse;
584  }
585 
586  switch (arg_setup_type) {
587  case arg_setup_method:
588  break; /* do nothing special */
589  case arg_setup_block:
590  if (given_argc == 1 &&
591  (min_argc > 0 || iseq->body->param.opt_num > 1 ||
592  iseq->body->param.flags.has_kw || iseq->body->param.flags.has_kwrest) &&
593  !iseq->body->param.flags.ambiguous_param0 &&
594  args_check_block_arg0(args, th)) {
595  given_argc = RARRAY_LENINT(args->rest);
596  }
597  break;
598  case arg_setup_lambda:
599  break;
600  }
601 
602  /* argc check */
603  if (given_argc < min_argc) {
604  if (given_argc == min_argc - 1 && args->kw_argv) {
606  given_argc = args_argc(args);
607  }
608  else {
609  if (arg_setup_type == arg_setup_block) {
610  CHECK_VM_STACK_OVERFLOW(th->cfp, min_argc);
611  given_argc = min_argc;
612  args_extend(args, min_argc);
613  }
614  else {
615  argument_arity_error(th, iseq, given_argc, min_argc, max_argc);
616  }
617  }
618  }
619 
620  if (given_argc > min_argc &&
621  (iseq->body->param.flags.has_kw || iseq->body->param.flags.has_kwrest) &&
622  args->kw_argv == NULL) {
623  if (args_pop_keyword_hash(args, &keyword_hash, th)) {
624  given_argc--;
625  }
626  }
627 
628  if (given_argc > max_argc && max_argc != UNLIMITED_ARGUMENTS) {
629  if (arg_setup_type == arg_setup_block) {
630  /* truncate */
631  args_reduce(args, given_argc - max_argc);
632  given_argc = max_argc;
633  }
634  else {
635  argument_arity_error(th, iseq, given_argc, min_argc, max_argc);
636  }
637  }
638 
639  if (iseq->body->param.flags.has_lead) {
640  args_setup_lead_parameters(args, iseq->body->param.lead_num, locals + 0);
641  }
642 
643  if (iseq->body->param.flags.has_post) {
644  args_setup_post_parameters(args, iseq->body->param.post_num, locals + iseq->body->param.post_start);
645  }
646 
647  if (iseq->body->param.flags.has_opt) {
648  int opt = args_setup_opt_parameters(args, iseq->body->param.opt_num, locals + iseq->body->param.lead_num);
649  opt_pc = (int)iseq->body->param.opt_table[opt];
650  }
651 
652  if (iseq->body->param.flags.has_rest) {
653  args_setup_rest_parameter(args, locals + iseq->body->param.rest_start);
654  }
655 
656  if (iseq->body->param.flags.has_kw) {
657  VALUE * const klocals = locals + iseq->body->param.keyword->bits_start - iseq->body->param.keyword->num;
658 
659  if (args->kw_argv != NULL) {
660  const struct rb_call_info_kw_arg *kw_arg = args->kw_arg;
661  args_setup_kw_parameters(args->kw_argv, kw_arg->keyword_len, kw_arg->keywords, iseq, klocals);
662  }
663  else if (!NIL_P(keyword_hash)) {
664  int kw_len = rb_long2int(RHASH_SIZE(keyword_hash));
665  struct fill_values_arg arg;
666  /* copy kw_argv */
667  arg.keys = args->kw_argv = ALLOCA_N(VALUE, kw_len * 2);
668  arg.vals = arg.keys + kw_len;
669  arg.argc = 0;
670  rb_hash_foreach(keyword_hash, fill_keys_values, (VALUE)&arg);
671  VM_ASSERT(arg.argc == kw_len);
672  args_setup_kw_parameters(arg.vals, kw_len, arg.keys, iseq, klocals);
673  }
674  else {
675  VM_ASSERT(args_argc(args) == 0);
676  args_setup_kw_parameters(NULL, 0, NULL, iseq, klocals);
677  }
678  }
679  else if (iseq->body->param.flags.has_kwrest) {
680  args_setup_kw_rest_parameter(keyword_hash, locals + iseq->body->param.keyword->rest_start);
681  }
682 
683  if (iseq->body->param.flags.has_block) {
684  args_setup_block_parameter(th, calling, locals + iseq->body->param.block_start);
685  }
686 
687 #if 0
688  {
689  int i;
690  for (i=0; i<iseq->body->param.size; i++) {
691  fprintf(stderr, "local[%d] = %p\n", i, (void *)locals[i]);
692  }
693  }
694 #endif
695 
696  th->cfp->sp = orig_sp;
697  return opt_pc;
698 }
699 
700 static void
701 raise_argument_error(rb_thread_t *th, const rb_iseq_t *iseq, const VALUE exc)
702 {
703  VALUE at;
704 
705  if (iseq) {
707  VM_BLOCK_HANDLER_NONE /* specval*/, Qfalse /* me or cref */,
708  iseq->body->iseq_encoded, th->cfp->sp, 0, 0 /* stack_max */);
709  at = rb_vm_backtrace_object();
710  rb_vm_pop_frame(th);
711  }
712  else {
713  at = rb_vm_backtrace_object();
714  }
715 
716  rb_ivar_set(exc, idBt_locations, at);
717  rb_exc_set_backtrace(exc, at);
718  rb_exc_raise(exc);
719 }
720 
721 static void
722 argument_arity_error(rb_thread_t *th, const rb_iseq_t *iseq, const int miss_argc, const int min_argc, const int max_argc)
723 {
724  raise_argument_error(th, iseq, rb_arity_error_new(miss_argc, min_argc, max_argc));
725 }
726 
727 static void
728 argument_kw_error(rb_thread_t *th, const rb_iseq_t *iseq, const char *error, const VALUE keys)
729 {
730  raise_argument_error(th, iseq, rb_keyword_error_new(error, keys));
731 }
732 
733 static inline void
735 {
736  int argc = calling->argc;
737  VALUE *argv = cfp->sp - argc;
738  VALUE ary = argv[argc-1];
739 
740  cfp->sp--;
741 
742  if (!NIL_P(ary)) {
743  const VALUE *ptr = RARRAY_CONST_PTR(ary);
744  long len = RARRAY_LEN(ary), i;
745 
746  CHECK_VM_STACK_OVERFLOW(cfp, len);
747 
748  for (i = 0; i < len; i++) {
749  *cfp->sp++ = ptr[i];
750  }
751  calling->argc += i - 1;
752  }
753 }
754 
755 static inline void
757 {
758  struct rb_call_info_with_kwarg *ci_kw = (struct rb_call_info_with_kwarg *)ci;
759  const VALUE *const passed_keywords = ci_kw->kw_arg->keywords;
760  const int kw_len = ci_kw->kw_arg->keyword_len;
761  const VALUE h = rb_hash_new();
762  VALUE *sp = cfp->sp;
763  int i;
764 
765  for (i=0; i<kw_len; i++) {
766  rb_hash_aset(h, passed_keywords[i], (sp - kw_len)[i]);
767  }
768  (sp-kw_len)[0] = h;
769 
770  cfp->sp -= kw_len - 1;
771  calling->argc -= kw_len - 1;
772 }
773 
774 static VALUE
776 {
777  if (UNLIKELY(!rb_obj_is_proc(proc))) {
778  VALUE b;
779  b = rb_check_convert_type(proc, T_DATA, "Proc", "to_proc");
780 
781  if (NIL_P(b) || !rb_obj_is_proc(b)) {
783  "wrong argument type %s (expected Proc)",
784  rb_obj_classname(proc));
785  }
786  return b;
787  }
788  else {
789  return proc;
790  }
791 }
792 
793 static VALUE
795 {
796  VALUE obj;
797  ID mid;
798  const rb_callable_method_entry_t *me;
799  rb_thread_t *th;
800 
801  if (argc-- < 1) {
802  rb_raise(rb_eArgError, "no receiver given");
803  }
804  obj = *argv++;
805  mid = SYM2ID(callback_arg);
807  th = GET_THREAD();
808  if (!NIL_P(blockarg)) {
809  vm_passed_block_handler_set(th, blockarg);
810  }
811  if (!me) {
812  return method_missing(obj, mid, argc, argv, MISSING_NOENTRY);
813  }
814  return vm_call0(th, obj, mid, argc, argv, me);
815 }
816 
817 static void
819  struct rb_calling_info *calling, const struct rb_call_info *ci, rb_iseq_t *blockiseq, const int is_super)
820 {
821  if (ci->flag & VM_CALL_ARGS_BLOCKARG) {
822  VALUE block_code = *(--reg_cfp->sp);
823 
824  if (NIL_P(block_code)) {
826  }
827  else {
828  if (SYMBOL_P(block_code) && rb_method_basic_definition_p(rb_cSymbol, idTo_proc)) {
829  const rb_cref_t *cref = vm_env_cref(reg_cfp->ep);
830  if (cref && !NIL_P(cref->refinements)) {
831  VALUE ref = cref->refinements;
832  VALUE func = rb_hash_lookup(ref, block_code);
833  if (NIL_P(func)) {
834  /* TODO: limit cached funcs */
835  func = rb_func_proc_new(refine_sym_proc_call, block_code);
836  rb_hash_aset(ref, block_code, func);
837  }
838  block_code = func;
839  }
840  calling->block_handler = block_code;
841  }
842  else {
843  calling->block_handler = vm_to_proc(block_code);
844  }
845  }
846  }
847  else if (blockiseq != NULL) { /* likely */
848  struct rb_captured_block *captured = VM_CFP_TO_CAPTURED_BLOCK(reg_cfp);
849  captured->code.iseq = blockiseq;
850  calling->block_handler = VM_BH_FROM_ISEQ_BLOCK(captured);
851  }
852  else {
853  if (is_super) {
854  calling->block_handler = GET_BLOCK_HANDLER();
855  }
856  else {
858  }
859  }
860 }
861 
862 #define IS_ARGS_SPLAT(ci) ((ci)->flag & VM_CALL_ARGS_SPLAT)
863 #define IS_ARGS_KEYWORD(ci) ((ci)->flag & VM_CALL_KWARG)
864 
865 #define CALLER_SETUP_ARG(cfp, calling, ci) do { \
866  if (UNLIKELY(IS_ARGS_SPLAT(ci))) vm_caller_setup_arg_splat((cfp), (calling)); \
867  if (UNLIKELY(IS_ARGS_KEYWORD(ci))) vm_caller_setup_arg_kw((cfp), (calling), (ci)); \
868 } while (0)
rb_control_frame_t * cfp
Definition: vm_core.h:708
#define VM_CALL_ARGS_BLOCKARG
Definition: vm_core.h:904
VALUE rb_ary_unshift(VALUE ary, VALUE item)
Definition: array.c:1178
const VALUE * ep
Definition: vm_core.h:636
static void raise_argument_error(rb_thread_t *th, const rb_iseq_t *iseq, const VALUE exc)
Definition: vm_args.c:701
VALUE rb_ary_pop(VALUE ary)
Definition: array.c:949
static void vm_passed_block_handler_set(rb_thread_t *th, VALUE block_handler)
Definition: eval_intern.h:8
VALUE rb_vm_backtrace_object(void)
Definition: vm_backtrace.c:530
#define RARRAY_LEN(a)
Definition: ruby.h:1026
#define FALSE
Definition: nkf.h:174
const rb_callable_method_entry_t * rb_callable_method_entry_with_refinements(VALUE klass, ID id)
Definition: vm_method.c:873
static void vm_caller_setup_arg_splat(rb_control_frame_t *cfp, struct rb_calling_info *calling)
Definition: vm_args.c:734
static void args_copy(struct args_info *args)
Definition: vm_args.c:113
static int setup_parameters_complex(rb_thread_t *const th, const rb_iseq_t *const iseq, struct rb_calling_info *const calling, const struct rb_call_info *ci, VALUE *const locals, const enum arg_setup_type arg_setup_type)
Definition: vm_args.c:518
static int keyword_hash_p(VALUE *kw_hash_ptr, VALUE *rest_hash_ptr, rb_thread_t *th)
Definition: vm_args.c:176
VALUE rb_hash_dup(VALUE hash)
Definition: hash.c:457
static unsigned int hash(str, len) register const char *str
#define CLASS_OF(v)
Definition: ruby.h:453
VALUE rb_ary_subseq(VALUE ary, long beg, long len)
Definition: array.c:1212
#define Qtrue
Definition: ruby.h:437
Definition: st.h:99
struct rb_iseq_constant_body::@196::@197 flags
VALUE rb_eTypeError
Definition: error.c:762
VALUE rb_ary_push(VALUE ary, VALUE item)
Definition: array.c:905
#define rb_long2int(n)
Definition: ruby.h:319
#define VM_BLOCK_HANDLER_NONE
Definition: vm_core.h:1070
#define GET_BLOCK_HANDLER()
SSL_METHOD *(* func)(void)
Definition: ossl_ssl.c:54
#define SYM2ID(x)
Definition: ruby.h:384
static VALUE VM_BH_TO_SYMBOL(VALUE block_handler)
Definition: vm_core.h:1377
VALUE rb_ary_tmp_new(long capa)
Definition: array.c:532
struct rb_iseq_constant_body * body
Definition: vm_core.h:395
static void argument_arity_error(rb_thread_t *th, const rb_iseq_t *iseq, const int miss_argc, const int min_argc, const int max_argc)
Definition: vm_args.c:722
arg_setup_type
Definition: vm_args.c:30
static VALUE args_rest_array(struct args_info *args)
Definition: vm_args.c:161
struct rb_call_info_kw_arg * kw_arg
Definition: vm_core.h:228
void rb_raise(VALUE exc, const char *fmt,...)
Definition: error.c:2207
unsigned int flag
Definition: vm_core.h:217
struct rb_iseq_constant_body::@196 param
parameter information
#define VM_CALL_ARGS_SPLAT
Definition: vm_core.h:903
VALUE rb_hash_lookup(VALUE hash, VALUE key)
Definition: hash.c:867
#define VM_CALL_KWARG
Definition: vm_core.h:909
RUBY_EXTERN VALUE rb_cProc
Definition: ruby.h:1899
static void argument_kw_error(rb_thread_t *th, const rb_iseq_t *iseq, const char *error, const VALUE keys)
Definition: vm_args.c:728
VALUE * kw_argv
Definition: vm_args.c:26
static void args_setup_lead_parameters(struct args_info *args, int argc, VALUE *locals)
Definition: vm_args.c:282
const char * rb_obj_classname(VALUE)
Definition: variable.c:458
static rb_control_frame_t * vm_push_frame(rb_thread_t *th, const rb_iseq_t *iseq, VALUE type, VALUE self, VALUE specval, VALUE cref_or_me, const VALUE *pc, VALUE *sp, int local_size, int stack_max)
static const VALUE * args_rest_argv(struct args_info *args)
Definition: vm_args.c:155
#define GET_THREAD()
Definition: vm_core.h:1513
static VALUE method_missing(VALUE obj, ID id, int argc, const VALUE *argv, enum method_missing_reason call_status)
RUBY_SYMBOL_EXPORT_BEGIN typedef unsigned long st_data_t
Definition: st.h:22
VALUE rb_vm_make_proc(rb_thread_t *th, const struct rb_captured_block *captured, VALUE klass)
Definition: vm.c:863
const VALUE * iseq_encoded
Definition: vm_core.h:286
#define RB_BLOCK_CALL_FUNC_ARGLIST(yielded_arg, callback_arg)
Definition: ruby.h:1830
void rb_hash_foreach(VALUE hash, int(*func)(ANYARGS), VALUE farg)
Definition: hash.c:402
void rb_exc_raise(VALUE mesg)
Definition: eval.c:620
static const struct rb_captured_block * VM_BH_TO_CAPT_BLOCK(VALUE block_handler)
Definition: vm_core.h:1246
static void args_setup_post_parameters(struct args_info *args, int argc, VALUE *locals)
Definition: vm_args.c:302
VALUE rb_extract_keywords(VALUE *orighash)
Definition: class.c:1840
VALUE rb_hash_aset(VALUE hash, VALUE key, VALUE val)
Definition: hash.c:1576
static int args_setup_kw_parameters_lookup(const ID key, VALUE *ptr, const VALUE *const passed_keywords, VALUE *passed_values, const int passed_keyword_len)
Definition: vm_args.c:380
static int args_argc(struct args_info *args)
Definition: vm_args.c:37
#define val
static VALUE vm_call0(rb_thread_t *th, VALUE recv, ID id, int argc, const VALUE *argv, const rb_callable_method_entry_t *me)
Definition: vm_eval.c:46
VALUE * keys
Definition: vm_args.c:502
VALUE rb_ary_new(void)
Definition: array.c:493
int rest_index
Definition: vm_args.c:25
VALUE keywords[1]
Definition: vm_core.h:223
#define NIL_P(v)
Definition: ruby.h:451
static VALUE refine_sym_proc_call(RB_BLOCK_CALL_FUNC_ARGLIST(yielded_arg, callback_arg))
Definition: vm_args.c:794
int argc
Definition: ruby.c:183
#define Qfalse
Definition: ruby.h:436
const VALUE refinements
Definition: method.h:42
#define ALLOCA_N(type, n)
Definition: ruby.h:1593
Definition: method.h:58
#define MEMCPY(p1, p2, type, n)
Definition: ruby.h:1661
VALUE rb_exc_set_backtrace(VALUE exc, VALUE bt)
Definition: error.c:1044
const struct rb_iseq_constant_body::@196::rb_iseq_param_keyword * keyword
VALUE * argv
Definition: vm_args.c:20
static VALUE vm_to_proc(VALUE proc)
Definition: vm_args.c:775
static rb_cref_t * vm_env_cref(const VALUE *ep)
void rb_vm_pop_frame(rb_thread_t *th)
#define RARRAY_CONST_PTR(a)
Definition: ruby.h:1028
NORETURN(static void raise_argument_error(rb_thread_t *th, const rb_iseq_t *iseq, const VALUE exc))
#define TRUE
Definition: nkf.h:175
#define T_DATA
Definition: ruby.h:506
VALUE rb_obj_is_proc(VALUE)
Definition: proc.c:117
#define VM_ASSERT(expr)
Definition: vm_core.h:54
static void args_setup_kw_parameters(VALUE *const passed_values, const int passed_keyword_len, const VALUE *const passed_keywords, const rb_iseq_t *const iseq, VALUE *const locals)
Definition: vm_args.c:397
static enum rb_block_handler_type vm_block_handler_type(VALUE block_handler)
Definition: vm_core.h:1254
static int fill_keys_values(st_data_t key, st_data_t val, st_data_t ptr)
Definition: vm_args.c:508
#define RHASH_SIZE(hsh)
Definition: fbuffer.h:8
VALUE rb_hash_new(void)
Definition: hash.c:441
VALUE rb_ivar_set(VALUE, ID, VALUE)
Definition: variable.c:1364
VALUE rb_check_hash_type(VALUE hash)
Definition: hash.c:736
unsigned long ID
Definition: ruby.h:86
static void args_setup_block_parameter(rb_thread_t *th, struct rb_calling_info *calling, VALUE *locals)
Definition: vm_args.c:478
static void vm_caller_setup_arg_block(const rb_thread_t *th, rb_control_frame_t *reg_cfp, struct rb_calling_info *calling, const struct rb_call_info *ci, rb_iseq_t *blockiseq, const int is_super)
Definition: vm_args.c:818
#define Qnil
Definition: ruby.h:438
#define LIKELY(x)
Definition: ffi_common.h:125
VALUE rb_sym_to_proc(VALUE sym)
Definition: proc.c:1203
unsigned long VALUE
Definition: ruby.h:85
static VALUE make_unknown_kw_hash(const VALUE *passed_keywords, int passed_keyword_len, const VALUE *kw_argv)
Definition: vm_args.c:352
method_missing_reason
Definition: vm_core.h:203
static void vm_caller_setup_arg_kw(rb_control_frame_t *cfp, struct rb_calling_info *calling, const struct rb_call_info *ci)
Definition: vm_args.c:756
#define RARRAY_LENINT(ary)
Definition: ruby.h:1027
register unsigned int len
Definition: zonetab.h:51
VALUE rb_ary_new_from_values(long n, const VALUE *elts)
Definition: array.c:518
int argc
Definition: vm_args.c:21
static VALUE VM_BH_TO_PROC(VALUE block_handler)
Definition: vm_core.h:1391
VALUE rb_ary_resize(VALUE ary, long len)
expands or shrinks ary to len elements.
Definition: array.c:1650
#define RARRAY_ASET(a, i, v)
Definition: ruby.h:1041
static void args_extend(struct args_info *args, const int min_argc)
Definition: vm_args.c:48
#define INT2FIX(i)
Definition: ruby.h:232
static VALUE make_rest_kw_hash(const VALUE *passed_keywords, int passed_keyword_len, const VALUE *kw_argv)
Definition: vm_args.c:366
#define UNLIMITED_ARGUMENTS
Definition: intern.h:44
static int args_kw_argv_to_hash(struct args_info *args)
Definition: vm_args.c:238
#define RARRAY_AREF(a, i)
Definition: ruby.h:1040
VALUE rb_check_convert_type(VALUE, int, const char *, const char *)
Definition: object.c:2643
static void args_setup_rest_parameter(struct args_info *args, VALUE *locals)
Definition: vm_args.c:345
struct rb_call_info ci
Definition: vm_core.h:227
VALUE rb_check_array_type(VALUE ary)
Definition: array.c:635
VALUE block_handler
Definition: vm_core.h:232
VALUE * vals
Definition: vm_args.c:503
static VALUE rb_arity_error_new(int argc, int min, int max)
static int args_setup_opt_parameters(struct args_info *args, int opt_max, VALUE *locals)
Definition: vm_args.c:312
int rb_method_basic_definition_p(VALUE, ID)
Definition: vm_method.c:1880
VALUE rb_ary_dup(VALUE ary)
Definition: array.c:1927
VALUE rb_func_proc_new(rb_block_call_func_t func, VALUE val)
Definition: proc.c:676
#define UNLIKELY(x)
Definition: ffi_common.h:126
const rb_iseq_t * iseq
Definition: vm_core.h:602
static void args_stored_kw_argv_to_hash(struct args_info *args)
Definition: vm_args.c:259
static VALUE VM_BH_FROM_ISEQ_BLOCK(const struct rb_captured_block *captured)
Definition: vm_core.h:1198
const VALUE * opt_table
Definition: vm_core.h:333
#define ID2SYM(x)
Definition: ruby.h:383
static VALUE args_pop_keyword_hash(struct args_info *args, VALUE *kw_hash_ptr, rb_thread_t *th)
Definition: vm_args.c:193
static struct rb_captured_block * VM_CFP_TO_CAPTURED_BLOCK(const rb_control_frame_t *cfp)
Definition: vm.c:146
#define CHECK_VM_STACK_OVERFLOW(cfp, margin)
Definition: vm_core.h:1497
VALUE rest
Definition: vm_args.c:27
RUBY_EXTERN VALUE rb_cSymbol
Definition: ruby.h:1908
static int args_check_block_arg0(struct args_info *args, rb_thread_t *th)
Definition: vm_args.c:88
static void args_setup_kw_rest_parameter(VALUE keyword_hash, VALUE *locals)
Definition: vm_args.c:472
unsigned int size
Definition: vm_core.h:324
#define SYMBOL_P(x)
Definition: ruby.h:382
#define NULL
Definition: _sdbm.c:102
#define Qundef
Definition: ruby.h:439
const struct rb_call_info_kw_arg * kw_arg
Definition: vm_args.c:22
VALUE rb_eArgError
Definition: error.c:763
union rb_captured_block::@202 code
static void args_reduce(struct args_info *args, int over_argc)
Definition: vm_args.c:67
VALUE rb_keyword_error_new(const char *error, VALUE keys)
Definition: class.c:1787
char ** argv
Definition: ruby.c:184