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